[00] API reference · v1
Put agents to work from your own systems.
Create cards, start runs and read what the agent produced. JSON over HTTPS, scoped keys, and signed webhooks when something changes.
https://dispatch.asrar.software/api/v1- Endpoints
- 8
- Scopes
- 5
- Webhook events
- 6
- Requests / min / key
- 120
On this pageIntroduction
Introduction
- Requests and responses are JSON. Send
Content-Type: application/jsonwith bodies. - Timestamps are ISO 8601 in UTC; ids are UUIDs; costs are in euro cents.
- Every response carries an
X-Request-Idheader. Include it when you contact support. - The API is part of the Pro plan. Everything an agent sends outside Dispatch still waits for a person to approve it.
Resources
- CardA task on a board
POST /cardsGET /cards/{id} - RunOne execution by an agent
POST /cards/{id}/runsGET /runs/{id} - ArtifactWhat the run produced
GET /runs/{id}/artifacts
Side effects proposed by a run wait for an approval in Dispatch.
Authentication
Authorization header. Owners and admins create keys in Tools & integrations → API keys.- Keys start with
dsp_and are shown once. Dispatch stores a hash and the prefix only, so a lost key is replaced, never recovered. - A key acts as the member who created it, with their current role. If they leave the workspace, the key stops working.
- Revoking a key takes effect on the next request. Keep keys on your server — never in a browser or a mobile app.
Scopes
| Scope | Allows |
|---|---|
cards:read | List boards, task types and cards; read a card. |
cards:write | Create cards on any board of the workspace. |
runs:read | Read a run’s status, timings, tokens and cost. |
runs:write | Start a run on a card (counts toward usage). |
artifacts:read | Read the artifacts a run produced, with citations. |
A write scope includes reading what it writes: cards:write can read cards. A request without the right scope gets a 403 that names the missing one in details.requiredScopes.
curl "https://dispatch.asrar.software/api/v1/boards" \
-H "Authorization: Bearer $DISPATCH_API_KEY"{
"message": "This API key was revoked.",
"code": "UNAUTHORIZED",
"requestId": "req_x9Tq4mB2cW7k"
}Quickstart
# 1 · Create a card and start its run
curl -X POST "https://dispatch.asrar.software/api/v1/cards" \
-H "Authorization: Bearer $DISPATCH_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"boardId": "b3e7a1f4-2c9d-4e6b-8a1f-5d3c7e9b2a61",
"title": "Weekly competitor digest",
"taskType": "research_brief",
"inputs": { "topic": "What changed in Linear and Height pricing this week?" },
"run": true
}'
# 2 · Read the run (or subscribe to run.completed)
curl "https://dispatch.asrar.software/api/v1/runs/$RUN_ID" \
-H "Authorization: Bearer $DISPATCH_API_KEY"
# 3 · Fetch what the agent produced
curl "https://dispatch.asrar.software/api/v1/runs/$RUN_ID/artifacts" \
-H "Authorization: Bearer $DISPATCH_API_KEY"- [01]CreatePOST /cards with the task type’s inputs and run: true.
- [02]FollowGET /runs/{id} until it leaves queued and running.
- [03]CollectGET /runs/{id}/artifacts for the result and its citations.
Rate limits
| Header | Meaning |
|---|---|
X-RateLimit-Limit | Requests allowed in the current window. |
X-RateLimit-Remaining | Requests left before the window resets. |
X-RateLimit-Reset | When the window resets, in Unix seconds. |
Retry-After | On 429 only: seconds to wait before retrying. |
Runs have their own limits
HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1790524860
Retry-After: 17
X-Request-Id: req_Qm8x1Lr0VbN3Errors
message, a stable code to branch on, optional details, field issues for validation errors, and the requestId.| Status | When |
|---|---|
| 400VALIDATION_ERROR | A parameter or input is invalid. issues lists each field. |
| 401UNAUTHORIZED | The key is missing, malformed, revoked, or its creator left the workspace. |
| 402PLAN_LIMIT | The workspace is not on Pro, or a plan limit is reached (runs this month…). |
| 403FORBIDDEN | The key lacks a scope (details.requiredScopes) or its creator’s role is too low. |
| 404NOT_FOUND | The resource does not exist in this workspace. |
| 409CONFLICT | The card is already running. |
| 422UNPROCESSABLE | The card can’t run yet (incomplete inputs, archived board…). |
| 429RATE_LIMITED | Too many requests for this key. Wait Retry-After seconds. |
{
"message": "Some inputs are invalid",
"code": "VALIDATION_ERROR",
"issues": [
{
"path": "inputs.topic",
"message": "Topic or question is required"
}
],
"requestId": "req_7Hc2pWm9sK1d"
}Pagination
{ object: "list", data, hasMore, nextCursor }, newest first. Pass nextCursor as cursor to get the next page, and limit (1–100, default 20) to size it.let cursor = null;
const cards = [];
do {
const qs = new URLSearchParams({ limit: '100', ...(cursor ? { cursor } : {}) });
const page = await fetch(`https://dispatch.asrar.software/api/v1/cards?${qs}`, {
headers: { Authorization: `Bearer ${process.env.DISPATCH_API_KEY}` },
}).then((r) => r.json());
cards.push(...page.data);
cursor = page.hasMore ? page.nextCursor : null;
} while (cursor);curl "https://dispatch.asrar.software/api/v1/boards" \
-H "Authorization: Bearer $DISPATCH_API_KEY"{
"object": "list",
"data": [
{
"id": "b3e7a1f4-2c9d-4e6b-8a1f-5d3c7e9b2a61",
"object": "board",
"name": "Growth research",
"description": "Market and competitor research for the growth team.",
"archived": false,
"createdAt": "2026-08-02T10:00:00.000Z"
}
],
"hasMore": false,
"nextCursor": null
}curl "https://dispatch.asrar.software/api/v1/task-types" \
-H "Authorization: Bearer $DISPATCH_API_KEY"{
"object": "list",
"data": [
{
"key": "research_brief",
"object": "task_type",
"id": "4b1d…",
"name": "Research brief",
"description": "A sourced brief on a topic or question.",
"outputKind": "document",
"approvalPolicy": "side_effects",
"available": true,
"inputs": {
"version": 1,
"fields": [
{
"key": "topic",
"type": "textarea",
"label": "Topic or question",
"required": true
}
]
}
}
],
"hasMore": false,
"nextCursor": null
}Query parameters
boardIduuidOnly cards of this board.
statusstringOnly cards in this status.
draftreadyqueuedrunningawaiting_approvalreviewdonefailedcancelledlimitintegerPage size, 1–100 (default 20).
cursoruuidnextCursorof the previous page.
curl "https://dispatch.asrar.software/api/v1/cards?status=review&limit=20" \
-H "Authorization: Bearer $DISPATCH_API_KEY"{
"object": "list",
"data": [
{
"id": "7d1c9a52-4f0e-4b8e-9c3a-2f6d1e8b5a40",
"object": "card",
"title": "Competitor pricing — Linear vs Height",
"description": null,
"status": "ready",
"priority": "normal",
"board": {
"id": "b3e7a1f4-2c9d-4e6b-8a1f-5d3c7e9b2a61",
"name": "Growth research"
},
"taskType": {
"key": "competitor_summary",
"name": "Competitor summary"
},
"inputs": {
"urls": [
"https://linear.app/pricing",
"https://height.app/pricing"
],
"focus": "pricing"
},
"labels": [
"pricing"
],
"assignee": null,
"dueAt": null,
"runCount": 0,
"lastRunId": null,
"totalCostCents": 0,
"createdAt": "2026-09-27T09:14:03.000Z",
"updatedAt": "2026-09-27T09:14:03.000Z",
"url": "https://dispatch.asrar.dev/app/asrar-studio/boards/b3e7a1f4-2c9d-4e6b-8a1f-5d3c7e9b2a61?card=7d1c9a52-4f0e-4b8e-9c3a-2f6d1e8b5a40"
}
],
"hasMore": true,
"nextCursor": "7d1c9a52-4f0e-4b8e-9c3a-2f6d1e8b5a40"
}/api/v1/cardsCreate a card
Body
boardIduuidrequiredThe board to add the card to.
titlestringrequiredUp to 200 characters.
taskTypestringTask type key, e.g.
research_brief(ortaskTypeId).taskTypeIduuidTask type id, instead of
taskType.inputsobjectValues for the task type’s input fields.
descriptionstringContext for the agent and your team (Markdown).
prioritystringDefault
normal.lownormalhighurgentdueAtdate-timeISO 8601 with offset.
runbooleanStart a run right away. Needs the
runs:writescope.
Good to know
- A
card.createdwebhook event is sent to subscribed endpoints.
curl -X POST "https://dispatch.asrar.software/api/v1/cards" \
-H "Authorization: Bearer $DISPATCH_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"boardId": "b3e7a1f4-2c9d-4e6b-8a1f-5d3c7e9b2a61",
"title": "Competitor pricing — Linear vs Height",
"taskType": "competitor_summary",
"inputs": {
"urls": [
"https://linear.app/pricing",
"https://height.app/pricing"
],
"focus": "pricing"
}
}'{
"id": "7d1c9a52-4f0e-4b8e-9c3a-2f6d1e8b5a40",
"object": "card",
"title": "Competitor pricing — Linear vs Height",
"description": null,
"status": "ready",
"priority": "normal",
"board": {
"id": "b3e7a1f4-2c9d-4e6b-8a1f-5d3c7e9b2a61",
"name": "Growth research"
},
"taskType": {
"key": "competitor_summary",
"name": "Competitor summary"
},
"inputs": {
"urls": [
"https://linear.app/pricing",
"https://height.app/pricing"
],
"focus": "pricing"
},
"labels": [
"pricing"
],
"assignee": null,
"dueAt": null,
"runCount": 0,
"lastRunId": null,
"totalCostCents": 0,
"createdAt": "2026-09-27T09:14:03.000Z",
"updatedAt": "2026-09-27T09:14:03.000Z",
"url": "https://dispatch.asrar.dev/app/asrar-studio/boards/b3e7a1f4-2c9d-4e6b-8a1f-5d3c7e9b2a61?card=7d1c9a52-4f0e-4b8e-9c3a-2f6d1e8b5a40"
}Path parameters
cardIduuidrequiredThe card id.
curl "https://dispatch.asrar.software/api/v1/cards/$CARD_ID" \
-H "Authorization: Bearer $DISPATCH_API_KEY"{
"id": "7d1c9a52-4f0e-4b8e-9c3a-2f6d1e8b5a40",
"object": "card",
"title": "Competitor pricing — Linear vs Height",
"description": null,
"status": "review",
"priority": "normal",
"board": {
"id": "b3e7a1f4-2c9d-4e6b-8a1f-5d3c7e9b2a61",
"name": "Growth research"
},
"taskType": {
"key": "competitor_summary",
"name": "Competitor summary"
},
"inputs": {
"urls": [
"https://linear.app/pricing",
"https://height.app/pricing"
],
"focus": "pricing"
},
"labels": [
"pricing"
],
"assignee": null,
"dueAt": null,
"runCount": 1,
"lastRunId": "e5a2c8f1-9b3d-4a7e-b6c4-1f8d2e7a9c35",
"totalCostCents": 2.4,
"createdAt": "2026-09-27T09:14:03.000Z",
"updatedAt": "2026-09-27T09:14:03.000Z",
"url": "https://dispatch.asrar.dev/app/asrar-studio/boards/b3e7a1f4-2c9d-4e6b-8a1f-5d3c7e9b2a61?card=7d1c9a52-4f0e-4b8e-9c3a-2f6d1e8b5a40"
}/api/v1/cards/{cardId}/runsStart a run
Path parameters
cardIduuidrequiredThe card to run.
Body
instructionsstringExtra instruction for this run, like a comment sent to the agent.
modelTierstringadvancedneeds the Pro plan.standardadvanced
Good to know
- Runs count toward the workspace’s monthly usage.
- Side-effecting actions still wait for a person to approve them in Dispatch.
curl -X POST "https://dispatch.asrar.software/api/v1/cards/$CARD_ID/runs" \
-H "Authorization: Bearer $DISPATCH_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"instructions": "Focus on annual plans and seat minimums."
}'{
"id": "e5a2c8f1-9b3d-4a7e-b6c4-1f8d2e7a9c35",
"object": "run",
"cardId": "7d1c9a52-4f0e-4b8e-9c3a-2f6d1e8b5a40",
"number": 1,
"status": "queued",
"trigger": "api",
"modelTier": "standard",
"liveStatus": "Queued",
"queuedAt": "2026-09-27T09:15:10.000Z",
"startedAt": null,
"finishedAt": null,
"durationMs": null,
"usage": {
"inputTokens": 0,
"outputTokens": 0,
"costCents": 0
},
"error": null,
"createdAt": "2026-09-27T09:15:10.000Z",
"url": "https://dispatch.asrar.dev/app/asrar-studio/boards/b3e7a1f4-2c9d-4e6b-8a1f-5d3c7e9b2a61?card=7d1c9a52-4f0e-4b8e-9c3a-2f6d1e8b5a40&tab=run"
}/api/v1/runs/{runId}Retrieve a run
run.completed webhooks.Path parameters
runIduuidrequiredThe run id.
curl "https://dispatch.asrar.software/api/v1/runs/$RUN_ID" \
-H "Authorization: Bearer $DISPATCH_API_KEY"{
"id": "e5a2c8f1-9b3d-4a7e-b6c4-1f8d2e7a9c35",
"object": "run",
"cardId": "7d1c9a52-4f0e-4b8e-9c3a-2f6d1e8b5a40",
"number": 1,
"status": "running",
"trigger": "api",
"modelTier": "standard",
"liveStatus": "Reading linear.app/pricing…",
"queuedAt": "2026-09-27T09:15:10.000Z",
"startedAt": "2026-09-27T09:15:11.000Z",
"finishedAt": null,
"durationMs": null,
"usage": {
"inputTokens": 5210,
"outputTokens": 640,
"costCents": 1.9
},
"error": null,
"createdAt": "2026-09-27T09:15:10.000Z",
"url": "https://dispatch.asrar.dev/app/asrar-studio/boards/b3e7a1f4-2c9d-4e6b-8a1f-5d3c7e9b2a61?card=7d1c9a52-4f0e-4b8e-9c3a-2f6d1e8b5a40&tab=run"
}/api/v1/runs/{runId}/artifactsList a run’s artifacts
Path parameters
runIduuidrequiredThe run id.
curl "https://dispatch.asrar.software/api/v1/runs/$RUN_ID/artifacts" \
-H "Authorization: Bearer $DISPATCH_API_KEY"{
"object": "list",
"data": [
{
"id": "0c9e4b2a-7f1d-4e3a-9b8c-6d5a2f1e7c90",
"object": "artifact",
"cardId": "7d1c9a52-4f0e-4b8e-9c3a-2f6d1e8b5a40",
"runId": "e5a2c8f1-9b3d-4a7e-b6c4-1f8d2e7a9c35",
"kind": "document",
"title": "Linear vs Height — pricing",
"version": 1,
"isPartial": false,
"content": {
"markdown": "## Summary\nLinear’s Business plan costs $16 per user per month billed annually [[c1]]…"
},
"text": "Summary — Linear’s Business plan costs $16 per user per month billed annually…",
"citations": [
{
"index": 1,
"sourceType": "url",
"url": "https://linear.app/pricing",
"title": "Linear pricing",
"excerpt": "Business — $16 per user/month, billed annually",
"locator": {
"anchor": "c1"
}
}
],
"createdAt": "2026-09-27T09:16:02.000Z",
"updatedAt": "2026-09-27T09:16:02.000Z"
}
],
"hasMore": false,
"nextCursor": null
}Webhook events
| Event | Sent when | Group |
|---|---|---|
card.created | A card was added to a board (app, import, template, schedule or API). | Cards |
run.started | An agent picked a card up. | Runs |
run.completed | The run finished and its artifact is ready for review. | Runs |
run.failed | The run failed or stopped with a partial artifact. | Runs |
approval.requested | The agent wants to perform a side effect and waits for a person. | Approvals |
approval.decided | Someone approved, edited or rejected a proposed action. | Approvals |
Every event has the same envelope: id (unique, use it to de-duplicate), type, createdAt, the workspace and a data object with the ids you need to fetch the full resource.
{
"id": "evt_6c1f0a9e2b7d4c3e8f5a1b9d0e2c4f7a",
"type": "run.completed",
"apiVersion": "2026-09-01",
"createdAt": "2026-09-27T09:16:03.000Z",
"workspace": {
"id": "a1b2c3d4-…",
"slug": "asrar-studio"
},
"data": {
"runId": "e5a2c8f1-9b3d-4a7e-b6c4-1f8d2e7a9c35",
"cardId": "7d1c9a52-4f0e-4b8e-9c3a-2f6d1e8b5a40",
"number": 1,
"status": "completed",
"costCents": 2.4,
"durationMs": 52000,
"artifactIds": [
"0c9e4b2a-7f1d-4e3a-9b8c-6d5a2f1e7c90"
]
}
}Verifying signatures
whsec_…, shown once when you create or rotate it). The X-Dispatch-Signature header holds a timestamp and an HMAC-SHA256 of "<t>.<raw body>" in hex.- 1Read the raw request body — before any JSON parsing — and the
X-Dispatch-Signatureheader. - 2Compute HMAC-SHA256 of
${t}.${rawBody}with your secret and compare it to eachv1value in constant time. - 3Reject timestamps older than five minutes, so a captured request can’t be replayed.
- 4Answer 2xx within 10 seconds, then do the work. Anything else counts as a failed attempt.
Rotating a secret
v1 values. Accept the request when any of them matches.import crypto from 'node:crypto';
// Express: app.post('/hooks/dispatch', express.raw({ type: 'application/json' }), …)
export function verifyDispatchSignature(rawBody, header, secret) {
const parts = (header ?? '').split(',').map((p) => p.trim().split('='));
const t = Number(parts.find(([k]) => k === 't')?.[1]);
const signatures = parts.filter(([k]) => k === 'v1').map(([, v]) => v);
if (!t || !signatures.length) return false;
if (Math.abs(Date.now() / 1000 - t) > 300) return false; // replay window: 5 min
const expected = crypto
.createHmac('sha256', secret)
.update(`${t}.${rawBody}`)
.digest();
return signatures.some((sig) => {
const given = Buffer.from(sig, 'hex');
return given.length === expected.length && crypto.timingSafeEqual(given, expected);
});
}Retries & delivery log
- Deliveries can arrive out of order and, rarely, more than once. Use the event
idto de-duplicate. - Redirects are not followed. Point the endpoint at its final URL.
- Dispatch only calls public addresses: URLs that resolve to localhost or a private network are refused, both when you save the endpoint and at delivery.
- Pause an endpoint to stop deliveries without losing its secret or its log.
Attempts after a failure
- 1Immediatelyt = 0
- 2+30 st ≈ 30 s
- 3+2 mint ≈ 2 min 30 s
- 4+8 mint ≈ 10 min 30 s
- 5+32 min · last attemptt ≈ 42 min 30 s
After the last attempt the delivery is marked failed. Redeliver it from the log once your endpoint is back.
OpenAPI & versioning
/api/v1/openapi.json — import it into Postman, Insomnia or a code generator.- This is version
v1(document 1.0.0). Breaking changes ship under a new path;v1keeps working. - New fields and event types can be added at any time. Ignore the ones you don’t know.
curl "https://dispatch.asrar.software/api/v1/openapi.json" -o dispatch-openapi.json