Extend a task's lease
The tasks.heartbeat operation: POST /api/v1/tasks/{id}/heartbeat in the REST API and the tasks_heartbeat tool in the MCP server.
/api/v1/tasks/{id}/heartbeatKeeps the caller's lease on a task alive: claimedUntil becomes now plus leaseSeconds (default 15
minutes). Send it well before the lease ends, for example every third of leaseSeconds. With
status: "in_progress", a claimed task is marked as being worked on.
Only the holder can extend a lease (task_not_claimed, task_claimed). After it ended the claim is lost
(task_lease_expired): claim the task again, unless someone else did meanwhile.
At a glance
- REST:
POST /api/v1/tasks/{id}/heartbeat - MCP tool:
tasks_heartbeat - Operation ID:
tasks.heartbeat - Scope: Organization, or one of its legal entities or brands
- Permission:
tasks:write - Risk tier:
write - Dry run: Supported (send
Ownrecord-Dry-Run: true) - Idempotency:
Idempotency-Keyrequired - Modes: Test and live
- Authentication: API key with the
tasks:writescope - Since: M10
Request
Path parameters
| Field | Type | Description |
|---|---|---|
id | task_… ID |
Body
A JSON object (Content-Type: application/json):
| Field | Type | Required | Description |
|---|---|---|---|
leaseSeconds | integer (60 to 3600) | No | How long the lease lasts, in seconds (60–3600, default 900). |
status | "in_progress" | No | Mark a claimed task as being worked on. |
Response
200 OK with a JSON object:
| Field | Type | Description |
|---|---|---|
id | task_… ID | |
object | "task" | |
type | one of 12 values, e.g. registration.prerequisites, registration.prepare, registration.submit (all in the OpenAPI document) | |
entityId | ent_… ID | |
livemode | boolean | |
regimeId | string or null | |
registrationId | regn_… ID or null | |
filingPeriodId | fp_… ID or null | |
prerequisiteCode | string or null | |
title | string | |
description | string or null | |
priority | one of low, normal, high, urgent | |
status | one of open, claimed, in_progress, awaiting_approval, done, failed, cancelled | |
reason | one of 11 values, e.g. auto_blocked, existing_customer_sale, prerequisite_open (all in the OpenAPI document) or null | |
dueAt | date-time or null | |
overdue | boolean | |
assignee | object or null | |
claimedUntil | date-time or null | |
leaseActive | boolean | |
completeWith | one of tasks.complete, tasks.submit | |
needsAuthorization | boolean | |
inputs | array of object | |
inputs[].kind | string | |
inputs[].fileId | file_… ID or null | |
inputs[].data | object or null | |
outputs | object or null | |
authorizationId | atz_… ID or null | |
approvalRequestId | apr_… ID or null | |
failure | object or null | |
checklist | array of object | |
checklist[].text | string | |
checklist[].done | boolean | |
createdAt | date-time | |
updatedAt | date-time | |
completedAt | date-time or null | |
completedBy | string or null | |
version | integer (at least 1) |
Examples
Keep working on the return
POST /api/v1/tasks/task_01m4ttwd3veh9apbewxheq5xa9/heartbeat
Authorization: Bearer or_test_…
Idempotency-Key: 3f1c9a52-7d0e-4b8f-9a61-0c2d5e8b7f14
Content-Type: application/json
{
"status": "in_progress"
}
Response (200):
{
"id": "task_01m4ttwd3veh9apbewxheq5xa9",
"object": "task",
"type": "filing.submit",
"entityId": "ent_01m4ttwd3veh9apbewxheq5xh4",
"livemode": true,
"regimeId": "EU_OSS_UNION",
"registrationId": "regn_01m4ttwd3veh9apbewxheq5xa8",
"filingPeriodId": "fp_01m4ttwd3veh9apbewxheq5xa7",
"prerequisiteCode": null,
"title": "File the One-Stop Shop, Union scheme 2026-Q3 return",
"description": "File the One-Stop Shop, Union scheme 2026-Q3 return with the authority using the filing package, by 2026-10-31. Then submit this task with the return's reference, the portal's confirmation and the authorization you acted under: the period becomes submitted.",
"priority": "high",
"status": "in_progress",
"reason": "period_ended",
"dueAt": "2026-10-31T22:59:59.000Z",
"overdue": false,
"assignee": {
"type": "agent",
"id": "agt_01m4ttwd3veh9apbewxheq5xa6"
},
"claimedUntil": "2026-10-15T09:40:00.000Z",
"leaseActive": true,
"completeWith": "tasks.submit",
"needsAuthorization": true,
"inputs": [
{
"kind": "filing_period",
"fileId": null,
"data": {
"filingPeriodId": "fp_01m4ttwd3veh9apbewxheq5xa7",
"regimeId": "EU_OSS_UNION",
"periodKey": "2026-Q3",
"dueDate": "2026-10-31",
"dueAt": "2026-10-31T22:59:59.000Z"
}
},
{
"kind": "filing_package",
"fileId": null,
"data": {
"filingPeriodId": "fp_01m4ttwd3veh9apbewxheq5xa7"
}
},
{
"kind": "playbook",
"fileId": null,
"data": {
"regimeId": "EU_OSS_UNION",
"playbookKind": "filing"
}
}
],
"outputs": null,
"authorizationId": null,
"approvalRequestId": null,
"failure": null,
"checklist": [
{
"text": "Download the filing package",
"done": false
},
{
"text": "File the return in the authority's portal",
"done": false
},
{
"text": "Submit this task with the reference, the confirmation and the authorization",
"done": false
}
],
"createdAt": "2026-10-01T00:23:00.000Z",
"updatedAt": "2026-10-15T09:25:00.000Z",
"completedAt": null,
"completedBy": null,
"version": 3
}
Errors
| Code | HTTP status | When | What to do |
|---|---|---|---|
validation_failed | 400 | leaseSeconds is out of range. | Fix the fields listed in details.issues and send the request again. |
resource_not_found | 404 | No task with this ID in this organization, entity and mode. | Check the ID and that your credentials are scoped to the right organization, entity, brand and mode. |
task_status_invalid | 409 | The task is finished, or it waits for an approval. | Reload the task: finished tasks (done, failed, cancelled) don't change, and a task waiting for an approval changes only through that approval. details.status is the task's status. |
task_not_claimed | 409 | You don't hold this task's lease. | Claim the task first with tasks.claim; only the holder can extend or release a lease. |
task_claimed | 409 | Someone else holds the task's lease. | Work on another task (tasks.list with claimable: true), or try again after details.claimedUntil: an expired lease frees the task. details.assignee is who holds it. |
task_lease_expired | 409 | Your lease ended: claim the task again. | Claim the task again with tasks.claim. If someone else claimed it meanwhile, work on another task. Send heartbeats well before claimedUntil. |
task_claim_not_allowed | 403 | The caller is an API key, which can't hold tasks. | People, organization agents and installed apps claim tasks. With an API key, work on tasks nobody holds without claiming them, or use an agent or app credential (OAuth). |
version_conflict | 409 | The task changed at the same moment. | Fetch the object again and retry the change. |
permission_denied | 403 | You can't work on compliance tasks here. | Ask an organization owner or admin for a role or scope that allows this action. |
It can also return these common errors: api_version_unsupported, invalid_json, unsupported_media_type, authentication_required, api_key_invalid, idempotency_key_required, idempotency_key_reused, idempotency_in_progress, approval_required, approval_rejected, approval_expired, stale_approval, approval_policy_denied, rate_limited, internal_error.