ttokidu
How it worksPricingDemo
EN
  • Español
  • Català
  • English
  • Galego
Sign inStart for free

The tokidu API

Read your projects and tasks, create tasks from a form or a script and close them from another app. The API goes through the same door as the web: a token never does anything its account couldn't do.

It's part of the Max plan: anyone with Max can use it, and so can anyone working in a project shared by someone with Max. It only reaches those projects.

Base URL
https://tokidu.com/api/v1
Header
Authorization: Bearer tkd_…
Limits
1000 requests per hour per account · 60 per minute per token
Full reference
/api/v1/openapi.json

Getting started

  1. In Account → Integrations, create a token and tick “See your projects and tasks” (and “Create and change tasks”, if it's going to write).
  2. Copy it, because it's only shown once, and keep it like a password. In the examples it lives in the TOKIDU_TOKEN variable.
  3. Try it by asking for your account:
curl https://tokidu.com/api/v1/me \
  -H "Authorization: Bearer $TOKIDU_TOKEN"

Call it from a server or a script, not from a web page: the API doesn't allow CORS and ignores cookies.

Tokens and scopes

When you create a token you choose what it can do, which projects it reaches and when it expires:

  • read, “See your projects and tasks”: read projects, tasks and “Up next”.
  • write, “Create and change tasks”: create projects and tasks, change them, finish them, reopen them and delete them, as on the web.
  • Projects: all you can see or only the ones you tick. If you stop seeing one, the token stops reaching it.
  • Expiry: after 30, 90 or 365 days. If you don't choose, after a year.

The Madrugo token (integrations:read) only reads “Up next” for Madrugo, across all the projects you can see: it doesn't open this API and can't be limited to some projects.

You can have 10 active tokens. Revoke them one by one or all at once, and see the latest changes for each one: we keep what changes were made with each token, without the content, for 90 days.

Limits

  • 1000 requests per hour for your whole account and 60 per minute for each token.
  • Every response carries RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset: the limit, what's left and when it renews.
  • If you go over, the response is 429 demasiadas_peticiones with Retry-After: wait that many seconds and try again.
  • A request body can take up 64 KiB at most.

Creating tasks without duplicates

Creating a task requires the Idempotency-Key header: 1 to 100 characters, different for each task you want to create (for instance, the id of the row, email or form it comes from).

If you repeat the request with the same key, say after a network drop, no new task is created: you get the one that already exists, with 200 and Idempotent-Replayed: true.

If the task for that key was deleted, it doesn't come back: the answer is 410 tarea_borrada. The same key in another project creates another task.

Errors

An error answers with its HTTP status and the error field in the body; with 422, also field, the field that isn't valid.

401 token_invalido
The token is missing, doesn't exist, has been revoked or has expired (it doesn't say which).
403 ambito
The token lacks the scope the route asks for.
403 proyecto_fuera_del_token
The token is limited to other projects.
403 max_necesario
It's part of the Max plan and whoever shares the project doesn't have it (or you don't, when creating a project).
403 solo_lectura
In that project you can only look, not change.
403 en_pausa
The project is paused: whoever shares it no longer has the Team plan, so it can only be viewed.
404 proyecto_inexistente
The project doesn't exist or you can't see it.
404 tarea_inexistente
The task doesn't exist or you can't see it.
404 ruta_inexistente
That route isn't part of the API: check the method and the address.
404 webhook_inexistente
That notification doesn't exist or this token didn't create it.
409 id_ocupado
That Idempotency-Key belongs to a task you can't see: use another one.
409 horas_de_otros
It can't be deleted because it has other people's hours, as on the web.
409 adjuntos_de_otros
It can't be deleted because it has other people's files, as on the web.
409 entrada_facturada
It can't be deleted because it has hours that were already billed, as in the web app.
409 ciclo
That wait would close a loop: a task would end up waiting for itself.
409 webhooks_completo
You already have 20 notifications: delete one to create another.
410 tarea_borrada
That Idempotency-Key belongs to a task that was deleted: it isn't created again. To create another one, use another key.
413 cuerpo_grande
The body is over 64 KiB.
415 json_necesario
The body has to be JSON, with Content-Type: application/json.
422 peticion_invalida
A field isn't valid: field says which.
422 url_no_valida
A notification's address isn't valid: reason says why (https, puerto, usuario, local, tokidu, dns or ip_privada).
428 idempotencia_necesaria
Creating a task needs the Idempotency-Key header.
429 demasiadas_peticiones
You've gone over the limit: wait as long as Retry-After says.
429 demasiados_intentos
You've checked lots of notification addresses in a row: wait for what Retry-After says.
503 ocupado
The project was busy with another change: repeat the request after what Retry-After says.
503 no_disponible
The service couldn't answer right now: repeat the request after what Retry-After says.

Reference

Every route hangs off the base URL and answers in JSON. Project and task ids are the ones the API itself returns.

GET /api/v1/me

Your account, the token (name, scopes, projects and expiry) and what's left of the hour.

Scope: any

GET /api/v1/projects

The projects you see from people with Max: name, colour, who shares it, your role, traffic light, expected finish, plan snapshot and progress.

Scope: read

GET /api/v1/projects/{id}

One project, with its sprints.

Scope: read

GET /api/v1/projects/{id}/tasks

A project's tasks, without notes: what they wait for, whether they're blocked and when they're expected to finish. Filter with status (open, done or all) and updatedSince, and page with cursor.

Scope: read

curl "https://tokidu.com/api/v1/projects/$PROJECT_ID/tasks?status=open" \
  -H "Authorization: Bearer $TOKIDU_TOKEN"

GET /api/v1/tasks/{id}

One task with its notes, what it waits for and “Why that date?”.

Scope: read

GET /api/v1/next

“Up next”: your tasks that can start now.

Scope: read

POST /api/v1/projects

Creates a project: name and, if you like, color. Only if you have Max.

Scope: write

POST /api/v1/projects/{id}/tasks

Creates a task: title and, if you like, notes, priority, due, assignee, sprintId, estimateMin and after. Requires Idempotency-Key.

Scope: write

curl https://tokidu.com/api/v1/projects/$PROJECT_ID/tasks \
  -H "Authorization: Bearer $TOKIDU_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: form-42" \
  -d '{"title":"Call Ana","due":"2026-10-20"}'

PATCH /api/v1/tasks/{id}

Changes only the fields you send. Answers with the task, the ones that unlock and, if someone else changed the same thing at the same time, what was kept.

Scope: write

curl -X PATCH https://tokidu.com/api/v1/tasks/$TASK_ID \
  -H "Authorization: Bearer $TOKIDU_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"due":"2026-10-24"}'

POST /api/v1/tasks/{id}/done

Marks the task as done and answers with the ones that unlock.

Scope: write

curl -X POST https://tokidu.com/api/v1/tasks/$TASK_ID/done \
  -H "Authorization: Bearer $TOKIDU_TOKEN"

POST /api/v1/tasks/{id}/reopen

Reopens a finished task.

Scope: write

PUT /api/v1/tasks/{id}/after/{otherId}

Makes the task wait for another one in the same project.

Scope: write

DELETE /api/v1/tasks/{id}/after/{otherId}

Removes that wait.

Scope: write

DELETE /api/v1/tasks/{id}

Deletes the task, as on the web.

Scope: write

GET /api/v1/webhooks

The notifications to other apps this token has created: address, events, projects and status (never the secret).

Scope: webhooks

POST /api/v1/webhooks

Registers an https address to receive signed notifications: url, events and, optionally, projects (your own only). Answers with the secret, just once.

Scope: webhooks

DELETE /api/v1/webhooks/{id}

Deletes one of the notifications this token created and stops sending it.

Scope: webhooks

Notifications to other apps (webhooks)

When something happens in your projects, tokidu sends a signed POST to the address you give. Create them in Account → Integrations, or through the API with a token with the webhooks scope (what Zapier or Make use). Only the owner with Max, and only for their own projects; up to 20 per account.

What you can listen to

  • task.created · A task is created
  • task.done · A task is done
  • task.reopened · A task is reopened
  • task.unblocked · A task is unlocked
  • task.assigned · A task is assigned
  • task.deleted · A task is deleted
  • project.status · A project's traffic light changes

Each notification carries the type, an id for the event, the time, the project and, for a task, its title, status, assignee, deadline and link. Never notes, links, files, emails or hours.

Checking the signature

It follows Standard Webhooks: headers webhook-id, webhook-timestamp (seconds) and webhook-signature (v1, and a base64 HMAC-SHA256 of id.timestamp.body, with the key after whsec_). Check it against the body exactly as it arrives and reject anything older than 5 minutes. In Node:

import { createHmac, timingSafeEqual } from "node:crypto";

export function verifyTokidu(secret, headers, body, toleranceSeconds = 300) {
  const id = headers["webhook-id"], ts = headers["webhook-timestamp"], sigs = headers["webhook-signature"];
  if (!id || !ts || !sigs) return false;
  if (Math.abs(Date.now() / 1000 - Number(ts)) > toleranceSeconds) return false;
  const key = Buffer.from(secret.replace(/^whsec_/, ""), "base64");
  const expected = createHmac("sha256", key).update(`${id}.${ts}.${body}`).digest();
  return sigs.split(" ").some((s) => {
    const [version, sig] = s.split(",");
    const given = Buffer.from(sig ?? "", "base64");
    return version === "v1" && given.length === expected.length && timingSafeEqual(given, expected);
  });
}

Delivery and retries

Any 2xx is fine; redirects aren't followed. If it fails, it's retried after 1 min, 5 min, 30 min, 2 h, 6 h, 12 h and 24 h. After 20 failed deliveries in a row, or 3 days without a 2xx, the notification is turned off and we email you.

Only public https:// addresses, on port 443 or 8443, with no user or password: no localhost, internal networks or private IPs (also checked when sending).

OpenAPI

Every field of every request and response, in OpenAPI format, to generate a client or import them into your tool: /api/v1/openapi.json.

© 2026 tokidu
  • Pricing
  • Demo
  • API
  • Privacy
  • Terms
  • Español
  • Català
  • English
  • Galego
A Sinergia Barcelona product