Developers
The whole record, one call away.
Read every hour, project, timesheet and daily score the product shows a manager. From your own systems, over a versioned REST API, with keys scoped to exactly what one integration needs.
Free for two seats, no card. Keys are created in Settings → API keys.
- v1
- Versioned. A breaking change ships under a new prefix, never inside this one.
- OpenAPI 3.1
- One document. The reference and the typed client are both generated from it.
- X-Api-Key
- One header. Your organisation is taken from the key, never from a parameter.
# Yesterday's rollups, newest updated firstcurl "https://api.workmonitor.ai/v1/analytics/daily?limit=2" \ -H "X-Api-Key: $WM_API_KEY"{ "data": [ { "id": "dr_7c41f0", "memberId": "mem_9f2a", "date": "2026-09-02", "workMinutes": 431, "activeMinutes": 366, "breakMinutes": 42, "idleMinutes": 65, "meetingMinutes": 84, "productiveMinutes": 298, "neutralMinutes": 51, "unproductiveMinutes": 17, "avgActivityLevel": 0.71, "productivityScore": 78, "updatedAt": "2026-09-02T18:04:11.220Z" } ], "nextCursor": "eyJ1IjoiMjAyNi0wOS0wMlQxOD..."}The surface
Small enough to hold in your head.
6 routes: method, path, the scope a key must hold to call it, and what comes back. Read down the scope column to see how little a credential has to be able to do.
Every collection is cursor-paginated, newest-updated first: ask for up to 200 rows with limit and follow nextCursor until it comes back null. Writes exist too — appending time, submitting and deciding a timesheet, creating a project — and each one requires an Idempotency-Key, so a retry replays the stored answer instead of booking the hours twice.
Why any of this matters
Data you cannot get out is data you do not own.
Hours, projects, timesheets, daily scores and shipped deliverables all leave through the same versioned surface — into your warehouse, your BI tool, your own product. No export request, no CSV somebody emails you.
Quickstart
From nothing to your first call.
- 1
Create a scoped key
Settings → API keys. Grant only the scopes the integration needs, and optionally the IP ranges it may call from. The secret is shown once.
- 2
Send it on the request
As X-Api-Key, or the same key as a bearer token. Your organisation is taken from the key, so a credential can only ever read its own.
- 3
Page the collection
Ask for up to 200 rows at a time and follow nextCursor until it comes back null. Cursors are opaque — store them, do not parse them.
- 4
Poll for what changed
After the first load, pass updatedSince and de-duplicate on each record’s stable id. Nothing that has not moved is read twice.
Authorisation
Getting data out, without handing over the whole company.
Every read goes through a scoped API key you create in Settings → API keys. Send the key on each request in the X-Api-Key header (or as a bearer token); the secret is shown once at creation, and a key can never do more than the scopes it was granted.
X-Api-Key: vk_live_…- 01Scopes, not master keysGrant only what an integration needs: read members (members:read), time entries (time:read), projects (projects:read), and daily analytics (analytics:read).
- 02Per-key IP allowlistEach key can carry an optional IP allowlist (CIDR ranges, IPv4 and IPv6) enforced on every request.
- 03Incremental pollingCursor-paginate the collections, then poll incrementally with updatedSince and de-duplicate on each record’s stable id.
- 04Predictable limits & errorsKeys are rate-limited with a Retry-After header on 429, and every error is the same JSON envelope.
- 05No-code with ZapierConnect WorkMonitor to 6,000+ apps with the built-in Zapier integration, with no server to run.
The full, interactive reference lives at /v1/docs.
Self-hosting is on the roadmap, not shipped. Data residency and bring-your-own-key encryption will land with it.
- API keys
- Widgets
- Webhooks
- Custom domains
- Client portalvk_live_a91c7d2e••••time:readprojects:read2 ranges4m ago
- Warehouse syncvk_live_5f30b8c1••••analytics:readmembers:read1 range1h ago
- Proof widget, stagingSandboxvk_test_2d6af053••••ledger:readcertificates:readAny IP12m ago
- Zapiervk_live_c74e19ab••••time:readoutcomes:readAny IPYesterday
- Invoice exportvk_live_8b12ee74••••projects:readwebhooks:read1 range26 Aug
- Old billing scriptRevokedvk_live_ff4a0d19••••billing:readAny IP14 Jul
Settings → API keys, in the product. Each row carries the scopes it was granted and the source addresses it may call from; the sandbox key is marked, and the revoked one stays on the list so you can see it was revoked.
Beyond the read
What there is to build once reading works.
Everything below is shipped and reachable with the same credential. Nothing here is a roadmap item wearing a present tense.
- Signed event webhooksSubscribe an endpoint to timesheet.submitted, timesheet.approved and project.created. Every POST carries an HMAC signature and a timestamp, and a delivery that fails is retried rather than dropped.
- A sandbox that cannot touch live dataA vk_test_ key belongs to a sandbox tenant of its own, so an integration under construction is structurally unable to read the real organisation.
- OAuth2 client credentialsRegister a client, exchange it for a short-lived bearer token, and drive the identical routes without a long-lived secret sitting in a config file.
- A client generated from the specThe TypeScript SDK is generated from the same OpenAPI document the API serves, and validates each response against the published contract before you see it.
- Widgets on your own domainPut a verifiable certificate badge, an approver panel or an activity timeline inside your product, rendered from the API rather than pasted in.
- No server to run at allThe Zapier integration and the connector catalogue move the same records into the tools your team already pays for, without writing anything.
Straight answers
The questions we would ask in your position
Every answer here is the one you would get on a call. Open as many as you like; they stay open, so two can be held side by side.
Only the scopes you granted it, and only inside your own organisation. The organisation is resolved from the key itself rather than from anything in the request, so a key cannot be pointed at someone else’s data by editing a parameter, and a key missing a scope is refused rather than quietly given less.
Page through once with limit and nextCursor, then poll with updatedSince and de-duplicate on each record’s stable id. Rows come back newest-updated first, so an incremental poll reads what moved and nothing else. Cursors are opaque: store them, do not parse them.
A 429 with a Retry-After header saying how long to wait. There are two independent ceilings — a per-minute rate and a monthly call quota — and every response carries the limit, what is left of it and when the window resets, so a well-behaved client paces itself before it gets there. Limits are per key, so one integration can never throttle another.
Both. Writes go through the same services the product itself uses, so they inherit the same guards: the server computes a time entry’s minutes and decides whether it is billable, and an append into an approved timesheet is refused. Every write requires an Idempotency-Key header, so a retry replays the stored response rather than booking the same hours twice.
Rotate it rather than deleting it. The rotation mints a successor carrying the same scopes, environment and limits, and leaves the old secret working for a grace window while you roll your integration onto the new one. Nothing has to be revoked and recreated at midnight.
A breaking change ships under a new version prefix, never inside this one. A route being retired stays supported and advertises its removal date in the Deprecation, Sunset and Link response headers, so a client learns it is on borrowed time from the response itself rather than from an email somebody forgot to send.
Make the first call today.
Create an account, open Settings → API keys, and grant one scope. The sample at the top of this page then runs against your own workspace, and a sandbox key keeps the experiment away from live data entirely.
Free for two seats, no card. Talk to us about a partner or white-label integration.