Developer pages
Zinvee WorkGuide

Build on Zinvee Work

Read and change tasks, projects, comments and time from your own code, hear the moment work changes, and let an AI assistant work with your tasks. Everything acts as the person who owns the token, with exactly their access.

Base URL https://work-api.zinvee.com/v1. Every endpoint is in the API reference.

Quick start

  1. Sign in to Zinvee Work, open Profile → API tokens and choose New token. Pick Read only or Read and write and how long it should last. Copy the token: it is shown once.
  2. Check it works:
    Who am I?
    export WORK_TOKEN="dgt_pat_…"
    
    curl https://work-api.zinvee.com/v1/me \
      -H "Authorization: Bearer $WORK_TOKEN"
  3. Create a task. A plain date is due at 18:00 in your workspace’s timezone:
    Create a task
    curl -X POST https://work-api.zinvee.com/v1/tasks \
      -H "Authorization: Bearer $WORK_TOKEN" \
      -H "Content-Type: application/json" \
      -H "Idempotency-Key: $(uuidgen)" \
      -d '{"title": "Send the GST return", "dueAt": "2026-11-20", "priority": "high"}'
  4. List what is on your plate, soonest first:
    My open tasks
    curl "https://work-api.zinvee.com/v1/tasks?assignee=me&open=true&sort=due_asc" \
      -H "Authorization: Bearer $WORK_TOKEN"

A task can be addressed by its id or by its key: /v1/tasks/DGT-42.

Authentication

Send a personal API token as a bearer token: Authorization: Bearer dgt_pat_…. A token acts as the person who created it (their role, the projects they can see, a guest’s limits, the workspace’s plan) and never more. It stops working the moment it is revoked or expires, its owner is removed, or the workspace is suspended.

  • Read only tokens can call GET endpoints and the MCP server’s read tools. Read and write tokens can call everything.
  • Tokens are stored as a keyed hash: nobody can see one again after it is created, us included.
  • Each person manages their own in Profile → API tokens. Workspace admins see every token (who holds it, its access, when and from where it was last used) and can revoke any of them in Settings → Security.
  • Tokens work only on the API (/v1) and the MCP server (/mcp), not for signing in, account security, billing or exports.

Pagination

Every list returns the same envelope. Pass nextCursor back as cursor until hasMore is false; limit sets the page size (1 to 100, default 50). Cursors are opaque, so don’t build them yourself.

A page
{
  "data": [ { "id": "…", "key": "DGT-41", "title": "…" } ],
  "hasMore": true,
  "nextCursor": "eyJ2IjoxLCJvIjo1MH0"
}

Errors

Errors use HTTP status codes and one body shape: { "error": { "code", "message", "details" } }. Branch on code; show message to people.

StatusCodesMeaning
401unauthorized, api_token_requiredNo token, or it is invalid, expired or revoked. The API only takes personal API tokens.
403insufficient_scopeA read-only token tried to change something.
403forbidden, guest_forbiddenYour role, or the project, does not allow it: the same rules as the app.
403plan_upgrade_requiredThe feature needs a higher plan (hook subscriptions need Pro or Business).
404not_foundIt does not exist, or you cannot see it. The two look the same on purpose.
409conflict, idempotency_key_reused, idempotency_in_progressIt clashes with the current state, or an Idempotency-Key was reused.
422validation_errorThe request is invalid. details lists each field: [{ path, message }].
429rate_limitedOver the token’s budget for the minute. Wait Retry-After seconds.

Rate limits

Each token may make 120 requests a minute by default, across the API and the MCP server. Limits are per token, not per plan. Every response says where you are:

Response headers
RateLimit-Limit: 120
RateLimit-Remaining: 117
RateLimit-Reset: 42

Over the limit you get 429 with Retry-After (seconds). Back off and retry.

Idempotency

Network calls fail half-way. Send an Idempotency-Key header (a UUID is ideal) with any create except subscribing a hook (its signing secret is never stored, so it can’t be replayed). A retry with the same key within 24 hours returns the first response, marked Idempotent-Replayed: true, instead of creating a second task. Reusing a key for a different request is refused with 409. Requests that fail are not remembered, so you can fix them and retry with the same key.

Triggers and webhooks

Two ways to hear about new and changed work.

Polling

Ask for tasks newer than the newest one you have seen, newest first. Use createdAt of the first item as the next since:

New tasks since the last poll
curl "https://work-api.zinvee.com/v1/tasks?sort=created_desc&since=2026-11-03T08:15:00.000Z" \
  -H "Authorization: Bearer $WORK_TOKEN"

For changed tasks use sort=updated_desc and the newest updatedAt. For new comments, poll GET /v1/comments?since=…: newest first, each with the task it is on (add task=DGT-42 to follow one task).

REST hooks

On Pro and Business, subscribe a URL to an event and Work POSTs each one to it as it happens: the same object the API returns, as the subscriber sees it at that moment. Events: task.created, task.updated, task.completed, comment.created, project.created.

Subscribe
curl -X POST https://work-api.zinvee.com/v1/hooks \
  -H "Authorization: Bearer $WORK_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"event": "task.completed", "targetUrl": "https://example.com/hooks/work"}'

The response carries the hook’s id and its signing secret (shown once). Unsubscribe with DELETE /v1/hooks/{id}, or answer a delivery with 410 Gone. Each delivery looks like this:

A delivery
POST /hooks/work
Content-Type: application/json
X-Diginet-Event: task.completed
X-Diginet-Delivery: 6f1c…   (same on retries: dedupe on it)
X-Diginet-Signature: sha256=9b2e…

{
  "id": "6f1c…",
  "event": "task.completed",
  "hookId": "c2a8…",
  "occurredAt": "2026-11-03T08:15:02.114Z",
  "sentAt": "2026-11-03T08:15:02.380Z",
  "payload": { "id": "…", "key": "DGT-42", "title": "…", "status": "done" }
}

Check the signature before trusting a delivery. It is an HMAC-SHA256 of the raw body with the hook’s secret:

Verify a delivery (Node.js)
import { createHmac, timingSafeEqual } from 'node:crypto';

// rawBody: the request body exactly as received (a Buffer or string).
export function isFromWork(rawBody, signatureHeader, secret) {
  const expected = 'sha256=' + createHmac('sha256', secret).update(rawBody).digest('hex');
  const a = Buffer.from(signatureHeader ?? '');
  const b = Buffer.from(expected);
  return a.length === b.length && timingSafeEqual(a, b);
}

Answer with any 2xx within 10 seconds. Anything else is retried with backoff; after 10 failed deliveries in a row the hook is switched off and its owner is told. Targets must be on the public internet. A delivery is only sent when the hook’s owner can see the task, so moving a task into a private project they are not on stops its events.

Zapier, Make and n8n

Each platform’s own HTTP and webhook building blocks work with the API:

To do thisZapierMaken8n
Poll for new work (every plan)Webhooks by Zapier → Retrieve PollScheduled scenario + HTTP → Make a requestSchedule Trigger + HTTP Request
Instant events (Pro and Business)Webhooks by Zapier → Catch HookWebhooks → Custom webhookWebhook node (production URL)
Create, update, commentWebhooks by Zapier → Custom RequestHTTP → Make a requestHTTP Request
  1. Send your token on every request as the header Authorization: Bearer dgt_pat_…. In n8n, save it once as a Header Auth credential and pick that in each HTTP Request node.
  2. Poll for new work (every plan). Ask for the newest tasks; the list is under data and each item’s id is unique:
    Poll for new tasks
    GET https://work-api.zinvee.com/v1/tasks?sort=created_desc&since=2026-11-03T08:15:00.000Z
    Authorization: Bearer dgt_pat_…

    Zapier’s Retrieve Poll remembers which ids it has seen: give it the URL without since and set its key to data. In Make and n8n, run on a schedule and set since to a little before the previous run, skipping ids you have handled. In n8n, for a workflow that runs every five minutes with two minutes of overlap: {{ $now.minus({ minutes: 7 }).toUTC().toISO() }}.

  3. Or get events instantly (Pro and Business). Copy the URL your catch-hook trigger shows and subscribe it once with POST /v1/hooks as above. Each delivery’s payload is the task (or comment, or project). Keep the hook’s id and delete it when you switch the automation off. The URL must be reachable from the internet, so a self-hosted n8n needs a public address.
  4. Create and update. Send JSON, and use the triggering item’s id as the Idempotency-Key so a step that runs twice still creates one task:
    Create a task from an automation
    POST https://work-api.zinvee.com/v1/tasks
    Authorization: Bearer dgt_pat_…
    Content-Type: application/json
    Idempotency-Key: form-entry-8812
    
    {
      "title": "Call back Anil",
      "description": "From the website form",
      "priority": "high",
      "dueAt": "2026-11-20"
    }

    Change a task with PATCH /v1/tasks/DGT-42 and only the fields you send; comment with POST /v1/tasks/DGT-42/comments and {"body": "…"}.

Connect an AI assistant

The MCP server lets an assistant that speaks the Model Context Protocol search, read and update your tasks, as you and with your access. It uses the Streamable HTTP transport at:

MCP server URL
https://work-api.zinvee.com/mcp

Authenticate with a personal API token in the Authorization header. With a Read only token the assistant gets only the read tools. For clients that take an mcpServers configuration with remote servers:

mcpServers (remote HTTP)
{
  "mcpServers": {
    "zinvee-work": {
      "type": "http",
      "url": "https://work-api.zinvee.com/mcp",
      "headers": {
        "Authorization": "Bearer dgt_pat_…"
      }
    }
  }
}

Clients that can only start local (stdio) servers can reach it through a stdio-to-HTTP bridge, for example the open-source mcp-remote package:

mcpServers (through a local bridge)
{
  "mcpServers": {
    "zinvee-work": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-remote",
        "https://work-api.zinvee.com/mcp",
        "--header",
        "Authorization:${AUTH_HEADER}"
      ],
      "env": {
        "AUTH_HEADER": "Bearer dgt_pat_…"
      }
    }
  }
}
ToolWhat it doesToken
search_tasksFind tasks by words and filtersRead
get_taskOne task with its checklist and latest commentsRead
list_my_tasksYour open tasks, grouped by when they are dueRead
list_projectsProjects with open and overdue countsRead
get_project_statusA project’s health and recent status updatesRead
list_peoplePeople you work withRead
create_taskCreate a taskRead and write
update_taskChange title, description, status, priority, due date, assignees or projectRead and write
add_commentComment on a taskRead and write

Every tool answers with task keys and links into the app, so an assistant can point you straight at the work. The server is stateless and needs no session.