# Receive a task completion notification `POST task.completed` Chenvoya sends task.completed when a task reaches succeeded, failed or cancelled. Successful tasks also wait for result delivery processing to finish. Delivery is at least once: retries keep the same event ID and original body bytes. Notifications have no download links. Read the task for current status and results. See Callbacks for signature verification, deduplication and retries. - Any 2xx response confirms receipt; other answers and timeouts are retried on schedule. - Verify `Chenvoya-Signature` before you handle the body. - Delivery is at least once: deduplicate on `event_id` in the verified body. - The event has no download link; read the task for the result. ## Headers | Field | Type | Requirement | Description | | --- | --- | --- | --- | | `Chenvoya-Event-Id` | string | Required | A convenience copy of the event ID. This header is not covered by the signature. After verifying the signature, deduplicate using event_id inside the signed body. Format: uuid. | | `Chenvoya-Signature` | string | Required | The notification signature contains t and v1. Check the timestamp as described in Callbacks, calculate HMAC-SHA256 over the original body bytes and compare in constant time. | ## Request body · application/json · Required | Field | Type | Requirement | Description | | --- | --- | --- | --- | | `event_id` | string | Required | The unique event ID inside the signed body. Deduplicate on this field after successful signature verification. Format: uuid. | | `object` | string | Required | The notification object type, always event. Always: event. | | `type` | string | Required | Whether this notification reports task completion or billing settlement. `task.completed`: The task reached a final state; `task.billing_settled`: The task billing has been settled; | | `schema_version` | integer | Required | The notification format version, currently the integer 1. Always: 1. | | `created_at` | integer | Required | Event creation time in whole Unix seconds. Check it separately from each delivery attempt's signature timestamp. Range: ≥ 0. | | `data` | object | Required | The customer task snapshot saved when this event was created. | | `data.task_id` | string | Required | The platform Task ID belonging to your team. Length: 4–128. Characters: A–Z a–z 0–9 _ -. | | `data.request_id` | string | Required | The Request ID associated with task creation. Length: 4–128. Characters: A–Z a–z 0–9 _ -. | | `data.billing_correlation_id` | string | Required | The billing correlation ID associated with task creation. Length: 4–128. Characters: A–Z a–z 0–9 _ -. | | `data.model` | string | Required | The public model ID used for this task. `dreamina-seedance-2-0-260128`: Seedance 2.0; `dreamina-seedance-2-0-fast-260128`: Seedance 2.0 Fast; `dreamina-seedance-2-0-mini-260615`: Seedance 2.0 Mini; | | `data.status` | string | Required | The final task status: succeeded, failed or cancelled. `succeeded`: Succeeded; `failed`: Failed; `cancelled`: Cancelled; | | `data.delivery_status` | string | Required | Result delivery status when the event snapshot was saved. `pending`: Not yet delivered; `materializing`: Preparing the download; `available`: Ready to download; `output_unavailable`: Result unavailable; | | `data.error` | object | Required, nullable | The task error object, or null when there is no error. | | `data.error.code` | string | Required | A code your application can use to handle the error. `no_common_asset_route`: Assets temporarily unavailable; `asset_not_ready`: A referenced asset is still processing; `asset_review_timeout`: Asset review timed out; `route_misconfigured`: Service configuration error; `route_temporarily_unavailable`: Temporarily unavailable; `generation_expired`: Generation expired; `generation_failed`: Generation failed; `input_fetch_failed`: An input could not be downloaded from its URL; `input_url_not_allowed`: An input URL is not allowed; `input_too_large`: An input exceeds its size limit; `input_unsupported`: An input format, dimensions or duration is unsupported; `input_rejected`: An input did not pass content review; `input_preparation_failed`: The inputs could not be prepared in time; `input_duration_exceeded`: The combined input duration exceeds the model limit; | | `data.error.message` | string | Required | A readable explanation of the error. Length: 1–1024. | | `data.error.details` | object | Optional | Optional fields with more information about the error. | | `data.error.details.content_index` | integer | Optional | Zero-based position of the failed input in the original content array, including text items. Range: 0–50. | | `data.settlement_status` | string | Required | The billing settlement status when the event snapshot was saved. `reserved`: Reserved; `pending`: Pending; `reconciliation_required`: Under review; `settled`: Settled; `settled_with_receivable`: Settled - amount due; | | `data.final_actual_cost` | string | Required, nullable | The final charge as a USD string with six decimal places, or null until determined. Format: 6 decimal places. | ## Your response The notification was received. Any 2xx response confirms delivery; other responses and timeouts cause scheduled retries. ### Retry schedule - after 10 seconds - after 1 minute - after 5 minutes - then every hour - for up to 7 days ### Verify the signature The full signature, deduplication and age rules are on [Verify callback signatures](./api-docs-en-callbacks-verify.md). ```python import base64 import hashlib import hmac import time def verify(signing_secret, header, body): fields = {} for item in header.split(","): name, _, value = item.strip().partition("=") fields[name] = value t, v1 = fields.get("t", ""), fields.get("v1", "") if not t.isdigit() or abs(time.time() - int(t)) > 300: return False key = base64.urlsafe_b64decode(signing_secret + "=" * (-len(signing_secret) % 4)) signed = b"chenvoya.v1." + t.encode() + b"." + body expected = hmac.new(key, signed, hashlib.sha256).hexdigest() return hmac.compare_digest(expected, v1) ``` ## Related guides - [Receive callbacks](./api-docs-en-callbacks.md) - [Verify callback signatures](./api-docs-en-callbacks-verify.md) ## Example body ```json { "event_id": "7f9c2ba4-e88f-4d2b-9a2f-0c3e5b8d1a64", "object": "event", "type": "task.completed", "schema_version": 1, "created_at": 1793167400, "data": { "task_id": "task_32ae2a5177b310d3bc1ec83a98f63889", "request_id": "req_6acd96894df9798feb0ddb21e5a52d70", "billing_correlation_id": "billcorr_2f6c57065a4404b27fb9b6b24ea9a0d0", "model": "dreamina-seedance-2-0-260128", "status": "succeeded", "delivery_status": "available", "error": null, "settlement_status": "pending", "final_actual_cost": null } } ```