Action Board API
The Action Board API exports an immutable page of accessible tasks already stored in a Wheremore workspace. Tasks may be user-created or derived from Wheremore AI analysis. Creating an export does not run analysis, create tasks or modify the board.
Endpoints
POST https://app.wheremore.com/api/v2/exports/action-board
GET https://app.wheremore.com/api/v2/exports/{export_id}
POST creates a saved snapshot and is free. The first successful GET of a non-empty snapshot costs 0.5 credits. Later GET requests for the same export return the same saved data for free. Empty snapshots are always free.
Exports remain available for seven days.
Authentication
Send an API key with every request:
X-API-Key: sk_live_your_key_here
Bearer authentication is also supported:
Authorization: Bearer sk_live_your_key_here
Every POST also requires an idempotency key containing 8 to 128 permitted characters:
Idempotency-Key: action-board-sync-2026-08-25-page-1
Reuse that key only when retrying the identical POST . A retry returns the same export_id . Reusing it with a different body returns HTTP 409.
Permitted characters are letters, numbers, periods, underscores, colons, slashes and hyphens. Do not include personal data or secrets. Unknown JSON fields are rejected.
Create an export
Send filters as a JSON object.
| Field | Required | Description |
|---|---|---|
workspace_id |
Yes | Public workspace ID in ws_... format. |
project_id |
No | One accessible project ID. |
status |
No | todo , doing or done . |
priority |
No | immediate , near-term or can-wait . |
tag_id |
No | One accessible tag ID. |
updated_after |
No | ISO-8601 timestamp including a timezone. |
limit |
No | Page size from 1 to 100; default 50. |
cursor |
Next pages | Opaque cursor from the preceding snapshot. |
callback_url |
No | Public HTTPS URL notified when a pending export becomes ready. |
curl -X POST "https://app.wheremore.com/api/v2/exports/action-board" \
-H "X-API-Key: sk_live_your_key_here" \
-H "Idempotency-Key: action-board-sync-2026-08-25-page-1" \
-H "Content-Type: application/json" \
-d '{
"workspace_id": "ws_your_workspace_id",
"status": "doing",
"priority": "immediate",
"limit": 100
}'
Action Board snapshots are normally ready immediately. Creation returns HTTP 201:
{
"success": true,
"export": {
"id": "exp_0123456789abcdef0123456789abcdef",
"type": "action-board",
"status": "ready",
"created_at": "2026-08-25T18:00:00Z",
"ready_at": "2026-08-25T18:00:00Z",
"expires_at": "2026-09-01T18:00:00Z",
"status_url": "/api/v2/exports/exp_0123456789abcdef0123456789abcdef"
},
"credits_used": 0,
"balance": null,
"billing_status": "not_charged",
"meta": {
"request_id": "req_example",
"api_version": "v2",
"data_contract": "2026-08-25",
"duration_ms": 31.12
}
}
The creation response deliberately contains no task data and creates no debit.
Retrieve the saved snapshot
curl "https://app.wheremore.com/api/v2/exports/exp_0123456789abcdef0123456789abcdef" \ -H "X-API-Key: sk_live_your_key_here"
The first non-empty retrieval returns billing_status: "deducted" and credits_used: 0.5 . A later retrieval returns the same data , billing_status: "already_deducted" , credits_used: 0 and balance: null . Repeat responses do not replay the historic account balance.
{
"success": true,
"export": {
"id": "exp_0123456789abcdef0123456789abcdef",
"type": "action-board",
"status": "ready",
"created_at": "2026-08-25T18:00:00Z",
"ready_at": "2026-08-25T18:00:00Z",
"expires_at": "2026-09-01T18:00:00Z",
"status_url": "/api/v2/exports/exp_0123456789abcdef0123456789abcdef"
},
"credits_used": 0.5,
"balance": 999.5,
"billing_status": "deducted",
"data": {
"workspace_id": "ws_your_workspace_id",
"filters": {
"project_id": null,
"status": "doing",
"priority": "immediate",
"tag_id": null,
"updated_after": null,
"limit": 100
},
"tasks": [
{
"id": 115,
"type": "recommendation",
"title": "Add customer reviews to product pages",
"description": "Customer reviews can strengthen trust.",
"current_state": "Product pages do not show reviews.",
"recommended_action": "Add ratings and verified reviews.",
"status": "doing",
"priority": "immediate",
"position": 1,
"due_date": null,
"section": "User experience",
"page_url": "https://example.com/products/widget",
"project": {"id": 12, "name": "Website growth"},
"keyword": null,
"assignee": {"name": "Alex"},
"tags": [{"id": 4, "name": "Conversion"}],
"origin": {"type": "ai_analysis", "source": "page_audit"},
"has_draft": false,
"created_at": "2026-08-24T10:00:00Z",
"updated_at": "2026-08-25T09:30:00Z"
}
],
"total_returned": 1,
"pagination": {"next_cursor": null}
},
"meta": {
"request_id": "req_example",
"api_version": "v2",
"data_contract": "2026-08-25",
"duration_ms": 18.42
}
}
Tasks and origins
typeismanualfor a user-created task orrecommendationfor an AI-derived task.origin.typeisuser_createdorai_analysis.origin.sourceidentifies the saved analysis source when available.description,current_stateandrecommended_actionare saved task text, not fresh output generated by the API request. Because tasks can be based on analysis, that text may contain explanatory measurement language.assigneecontains a display name only; WordPress user IDs are not exported.has_draftreports whether draft content exists without exporting the draft.
Privacy and active-task contract
The API returns only accessible todo , doing and done tasks. It does not export archived tasks.
Access is checked again when the saved export is retrieved. If the key's user no longer has access to the workspace, or to any project or tag represented in the saved snapshot, the API does not return that stale snapshot.
It intentionally excludes dedicated lifecycle fields for:
- Evidence payloads or evidence-review state.
- Implementation checks or implementation status.
- Outcomes or outcome history.
- Measurements, baselines, current values or deltas.
- Confidence values and raw checker results.
- Full draft or outline content.
- WordPress user IDs.
These structured outcome and measurement records are outside the API contract. This does not strip ordinary explanatory language from saved task text: a task description, current state or recommended action may refer to measurements when that context forms part of the work instruction.
Pagination
If pagination.next_cursor is not null , create a new export with the same workspace and filters, that cursor, and a new idempotency key. Each non-empty page costs 0.5 credits when it is first retrieved. Stop when next_cursor is null .
Because each page is saved when its POST is processed, retrying its GET cannot change its contents. Tasks added or edited later appear only in a new export.
Callbacks and pending exports
If callback_url is supplied, Wheremore sends an export.ready notification containing the export ID, type, status URL and expiry time. The callback never contains the exported task data. Retrieve the data with the authenticated GET endpoint.
If a creation response has HTTP 202 and status: "pending" , poll its status_url . A pending GET is free and also returns HTTP 202.
An empty snapshot is successful and free. It returns an empty tasks array, credits_used: 0 , balance: null and billing_status: "not_charged_empty_export" .
Common errors
400: invalid JSON, filter, cursor or idempotency key.401: missing, invalid, revoked or expired API key.402: insufficient shared account credits; add credits and retry the sameGET.403 export_access_revoked: workspace, project or tag access changed after the export was created. If the export had already been charged, retain the request ID when contacting support.404: the export, workspace, project or tag does not exist in the requested scope.409: idempotency conflict or another retrieval is currently completing.410: the seven-day export retention period has ended.413: the saved export would exceed the maximum payload size; narrow the filters.503: billing or another required service is temporarily unavailable.
Incremental synchronization
Use updated_after to request tasks updated after a known timestamp. Always include a timezone.
For a reliable integration:
- Record the start time of the synchronization.
- Create and retrieve every page using the earlier successful synchronization time as
updated_after. - Store or update tasks by numeric
id. - Use a new idempotency key for each cursor page, but retain that key for technical retries of the same POST.
- Advance the saved synchronization time only after every page succeeds.
The API is active-only. A task disappearing from a later export does not by itself prove deletion: it may have been archived, moved to a different project, or moved outside the caller’s accessible scope.
Important limitations
- The export contains saved board data and does not create or refresh AI analysis.
- Archived tasks cannot be requested, and the API does not provide archive history or a deletion feed.
doneremains part of the active export contract.- Project and tag access control task visibility at retrieval time.
- An AI-derived recommendation records a proposed action; it is not proof that the action was implemented or produced an outcome.
has_draft: truedoes not expose or grant access to draft content.- Assignee names are display values, not durable user identifiers.
Troubleshooting
No tasks are returned
- Remove optional filters temporarily.
- Confirm the project belongs to the supplied workspace and the key’s user can access the relevant projects and tags.
- Confirm tasks use
todo,doingordone; archived tasks are intentionally excluded. - Check whether
updated_afteris later than the tasks’ last update.
An empty export is still successful and free.
The idempotency key is rejected
- Send
Idempotency-Keyas an HTTP header, not in the JSON body or query string. - Use 8 to 128 permitted characters.
- Reuse a key only for an identical POST body.
- Generate a new key for each new logical export or cursor page.
A request appears to have been charged again
Confirm that the integration retrieved the same export.id . Repeat GETs of one export ID are free, but a new export or non-empty cursor page creates a separately billable snapshot.
No next cursor is returned
The current page contains the final matching tasks. No further export is required.
The charge is higher than expected
Count non-empty pages rather than tasks. A smaller limit does not lower the price per page and may increase the number of paid pages. Use up to 100 tasks per page when minimizing page charges is more important than response size.
Security
- Keep API keys server-side and out of URLs.
- Store keys in a protected secret manager and revoke exposed or unused keys.
- Treat task titles, descriptions and analysis-derived text as untrusted display content and escape it before rendering.
- Validate
page_urland other exported links before displaying or opening them. - Store cursors as opaque values; do not decode or execute them.
- Restrict downstream access because task content can contain commercially sensitive plans.
- Do not infer access to excluded evidence, drafts, outcomes or measurement records from task text.