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

  • type  is manual  for a user-created task or recommendation  for an AI-derived task.
  • origin.type  is user_created  or ai_analysis .
  • origin.source  identifies the saved analysis source when available.
  • description , current_state  and recommended_action  are 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.
  • assignee  contains a display name only; WordPress user IDs are not exported.
  • has_draft  reports 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 same GET .
  • 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:


  1. Record the start time of the synchronization.
  2. Create and retrieve every page using the earlier successful synchronization time as updated_after .
  3. Store or update tasks by numeric id .
  4. Use a new idempotency key for each cursor page, but retain that key for technical retries of the same POST.
  5. 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.
  • done  remains 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: true  does 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 , doing  or done ; archived tasks are intentionally excluded.
  • Check whether updated_after  is later than the tasks’ last update.

An empty export is still successful and free.


The idempotency key is rejected

  • Send Idempotency-Key  as 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_url  and 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.
Did this answer your question? Thanks for the feedback There was a problem submitting your feedback. Please try again later.