Task Management API: The Developer's Field Guide

A good task management API needs fast capture, idempotent writes, real search, bulk operations, and signed webhooks. A field guide built on the quik.md API.

By Ege Beşe9 min read

A task management API is a REST interface that lets software create, organize, search, and update tasks without a human in the UI. The good ones share five traits: a low-friction capture endpoint, idempotent writes, filterable search, bulk operations, and signed webhooks. This guide walks each one using the quik.md API as the working example.

The reason to care is that tasks increasingly start as software output. Agents abandon half-finished work, scripts notice things, bots relay messages. A todo list API is where those signals land so a human can review them later. Every endpoint below is real and documented in the quik.md API reference; nothing here is aspirational.

Overhead flat-lay of a warm-paper desk with a closed laptop, an open notebook and blank index cards arranged in a precise ordered grid, a fountain pen beside.
A good API is an inbox that software can write to.

What does a good task management API need?

A good task management API needs five capabilities. Capture has to be one cheap POST with free-form text, because capture volume is where integrations live. Writes have to be idempotent, because retrying clients are a fact of networks. Search has to filter and paginate, because read traffic dwarfs write traffic. Bulk operations have to exist, because batch updates are how inboxes stay clean. Webhooks have to be signed, because unsigned callbacks are a spoofing invitation.

Two softer properties matter almost as much. The API should let you skip the AI layer, since a caller that already classified its own input should not pay for a second opinion. And the data model should be boring: items that are notes or todos, owned by projects, with tags. Boring models are the ones that survive three years of automation built on top of them.

How do you authenticate and stay inside rate limits?

Authentication is a bearer token. Create an API key in the app under Settings, then Developer; keys are prefixed qk_ and shown once. Send the key on every request:

Authorization: Bearer qk_...

Rate limits are enforced per user, per minute and per UTC day. Over the limit you get a 429 with a retry_after value in seconds in the body. Back off for that long and retry; do not hammer.

PlanPer minutePer day
Free601,000
Pro30010,000

How do you capture a task through the API?

Capture is one POST to /api/v1/capture with a text field. The body accepts text (required, up to 20,000 characters), type (note or todo, defaults to todo), project_id (a uuid, defaults to your inbox), organize (boolean, defaults to false, Pro-only when true), and client_id (a uuid you supply for idempotent retries).

curl https://quik.md/api/v1/capture \
  -H "Authorization: Bearer qk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "text":"Call the dentist tomorrow at 4pm",
    "type":"todo",
    "project_id":"<your-project-uuid>"
  }'

Two details carry most of the weight. First, organize defaults to off: the server stores the item without running the AI organizer, so no Pro requirement and no AI quota hit. Set organize: true and the server picks the project, extracts the due date, and classifies the item for you. Second, client_id makes retries safe. Send the same uuid twice and you get one item, which is what makes cron jobs and flaky networks boring instead of dangerous.

How do you read, update, and organize items?

Items are notes or todos owned by a project. The endpoints are REST-shaped and partial updates are the norm.

  • GET /api/v1/items?since=&limit=&cursor= lists items, cursor-paginated. Use since with an ISO timestamp for incremental sync.
  • GET /api/v1/items/:id reads one item.
  • PATCH /api/v1/items/:id updates only the fields you send, so an agent that parsed a due date writes it straight to the item with no AI round-trip.
  • POST /api/v1/items/:id/toggle with { "is_completed": true } completes or reopens an item. Subtasks cascade in both directions.
  • POST /api/v1/items/:id/archive, /unarchive, and DELETE (a soft delete that archives the row) handle lifecycle.
  • GET /api/v1/items/:id/children lists direct subtasks ordered by position.

Projects are the containers. GET|POST /api/v1/projects lists and creates; every account has an Inbox project marked is_default that cannot be deleted, and deleting another project moves its items to the Inbox. Tags work the same way at /api/v1/tags.

How do you search and bulk-update tasks?

Search is one endpoint with a generous query string: GET /api/v1/items/search returns { items, nextCursor, serverTime }. The filters: q (case-insensitive substring on title and markdown content), status (backlog, todo, doing, done, archived; repeat for OR), type, tag, project_id, parent_id, is_completed, due_before and due_after as ISO datetimes, include_archived, and limit from 1 to 200 with a default of 50. Paginate by following nextCursor into ?cursor= until it comes back null.

const params = new URLSearchParams({
  q: "launch",
  status: "todo",
  tag: "quik",
  limit: "20",
})
const r = await fetch(
  `https://quik.md/api/v1/items/search?${params}`,
  { headers: { Authorization: `Bearer ${process.env.QUIK_KEY}` } },
)

Bulk operations are the other half of batch work. POST /api/v1/items/bulk takes { op, ids, payload? } for up to 100 ids per call, with ops toggle, archive, unarchive, delete, and move. Each id is processed independently, and partial failures come back in a failures array instead of aborting the request. The standard pattern is search to collect ids, then bulk to apply the op: one round-trip to find, one to change.

How do webhooks work for task events?

Webhooks push item lifecycle events to your endpoint so you do not have to poll. Registering a webhook is Pro-only; the free plan gets a 402 pro_required on create. The events are item.created, item.updated, item.completed, item.uncompleted, item.archived, and item.deleted.

POST /api/v1/webhooks takes { url, events[], description? } and returns the webhook plus a secret shown once. The URL must be public HTTPS; localhost, private ranges, and .local or .internal hostnames are rejected to prevent SSRF. Every delivery carries X-Quik-Event and an X-Quik-Signature: sha256=<hex> header, signed with HMAC-SHA256 keyed on the SHA-256 hash of your secret. Verify before you trust:

import crypto from "node:crypto"

function verify(secret, rawBody, header) {
  const [, sig] = (header ?? "").split("=")
  const key = crypto.createHash("sha256").update(secret).digest("hex")
  const expected = crypto
    .createHmac("sha256", key)
    .update(rawBody)
    .digest("hex")
  return crypto.timingSafeEqual(
    Buffer.from(sig, "hex"),
    Buffer.from(expected, "hex"),
  )
}

Delivery is best-effort with three attempts: immediate, plus one second, plus five seconds. Ordering is not guaranteed, so use the item's updated_at to break ties. The full contract, including the verification snippet in Python, lives in the webhooks section of the API docs.

Where does the API fit in a real workflow?

The API is the capture surface for anything that is not a human at a keyboard. The n8n task inbox workflows guide wires Telegram, Gmail, Slack, and weekly notes into capture payloads, and the ChatGPT and Codex automation inbox post covers the agent-fallback pattern, where an AI coding agent captures a follow-up task when it cannot finish safely. Both treat the API as transport into a reviewable inbox, which is the AI task manager model applied to machine-generated work.

FAQ

What should a task management API include?

Five things: a low-friction capture endpoint that accepts free-form text, idempotent writes so retries never duplicate, search with real filters and pagination, bulk operations for batch updates, and signed webhooks so your system learns about changes without polling. Anything beyond that is convenience.

How do you authenticate with the quik.md API?

Create a key in Settings, then Developer, inside the app, and send it as a bearer token on every request: Authorization: Bearer qk_.... Keys are prefixed qk_ and shown once at creation, so store them like passwords. Signed-in browser session cookies also work, but agents and scripts should use API keys.

What are the quik.md API rate limits?

Free plan: 60 requests per minute and 1,000 per UTC day. Pro plan: 300 per minute and 10,000 per day. Limits are per user. Over the limit you get a 429 with a retry_after value in seconds in the response body, so back off for that long and retry.

Does the quik.md API support webhooks?

Yes, on the Pro plan. You register a public HTTPS URL and a list of events such as item.created and item.completed. Every delivery is signed with HMAC-SHA256 and carries X-Quik-Event and X-Quik-Signature headers. Delivery is best-effort with three attempts: immediate, plus one second, plus five seconds.

Can I capture tasks through the API without AI organization?

Yes, and that is the default. POST /api/v1/capture stores the text as an item with organize off unless you opt in. AI organization is Pro-only and only runs when you pass organize: true. If your own agent already picked the project and due date, leave organize off and pass the fields directly.

References

ShareShare on X

Keep reading