Seedance idempotency and submission recovery
Seedance idempotency and submission recovery — Idempotency-Key, HTTP 409, acceptance_unknown.
Seedance idempotency and submission recovery
For seedance-2.0, seedance-2.0-fast, seedance-2.0-mini, and seedance-2.5, add Idempotency-Key to generation requests. Supported paths are POST /v1/videos, POST /v1/videos/generations, and POST /v1/video/generations; they share one key namespace. Image generation, quotes, remix endpoints and other video models are not covered. Requests without a key retain existing behavior and have no general submission deduplication guarantee.
Scope and keys
Keys are scoped to the APIMaster account and Seedance video-generation operation, not to one API key or model. Use a unique random key of 8–128 visible ASCII characters for each new generation. A valid key from the same account can query the receipt. Exhausted tokens may query or replay existing receipts; expired, revoked or deleted keys and blocked accounts cannot. New generation still requires valid credentials and sufficient quota.
Atomic replay and conflicts
An atomic database claim is saved before routing, billing or contacting the generation provider. Same key and payload return HTTP 202 with the original receipt and preallocated task ID, without executing another submission or precharge, including concurrent requests and server restarts. A changed request returns HTTP 409 (idempotency_conflict). JSON object order and whitespace are ignored; array order, numbers, omitted versus explicit defaults, model, notification settings and routing group/channel are significant. Multipart boundaries and filenames are ignored, but upload bytes and their order are significant. Keep the original body and routing settings unchanged; JSON and multipart are distinct. Receipt records are retained for at least 30 days; this release has no automatic deletion or key reuse. Always use a new key for a new generation.
Responses
First requests retain the normal creation response. Save X-Video-Submission-Id, the request ID and task ID. Replays return a receipt, not necessarily the original response envelope. A preallocated task ID alone is not proof of upstream acceptance. accepted means provider acceptance, not completed generation. Only poll the task when task_ready=true; otherwise contact support without resubmitting.
Submission states
pending: recorded at the gateway, provider submission has not begun. submitting: provider submission has begun and the outcome is pending. accepted: a provider task ID was received. not_accepted: confirmed not accepted: the request was not sent, or the provider explicitly rejected it without returning a task ID. Correct the request and use a new key only when the receipt says new_submission_safe=true; HTTP 400 alone is insufficient. acceptance_unknown: the provider may have accepted the request, but confirmation is missing; do not create another generation. A receipt left unfinished by a crash is classified by background reconciliation after 30 minutes: pre-send becomes not_accepted, post-send becomes acceptance_unknown. No state automatically resubmits. These states describe submission, not billing; existing reservations, settlement and refund reconciliation still apply.
Recovery
After a timeout or 5xx, query by the same key, even if no task ID was received. Replaying the identical keyed request is safe within this scope, but it does not restart a failed submission. Lookup 404, an empty task list or absent billing logs do not prove non-acceptance: an original request can still be in flight, or may have been submitted without a key or before this feature. same_key_replay_safe refers to duplicate receipt retrieval; new_submission_safe is true only for a confirmed not_accepted receipt. For unknown outcomes or accepted with task_ready=false, contact support with the receipt/request ID, model and UTC time; never send your API key. Upstream idempotency is not promised, and sending the header directly to the official provider does not provide this gateway contract. Older portrait receipts remain on their original replay path and may return their legacy schema through lookup.
Examples
curl --fail-with-body 'https://apimaster.ai/v1/videos' \
-H "Authorization: Bearer $APIMASTER_KEY" \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: seedance-order-20261014-001' \
-d '{"model":"seedance-2.0","prompt":"A paper boat on a pond","duration":4,"resolution":"480p","generate_audio":false}'
curl --fail-with-body 'https://apimaster.ai/v1/video-submissions/by-key' \
-H "Authorization: Bearer $APIMASTER_KEY" \
-H 'Idempotency-Key: seedance-order-20261014-001'
{
"code": 200,
"data": {
"submission_id": "HASH",
"task_id": "task_PUBLIC_ID",
"request_id": "ORIGINAL_REQUEST_ID",
"model": "seedance-2.0",
"status": "accepted",
"task_ready": true,
"created_at": 1791936000,
"updated_at": 1791936001,
"next_action": "query_task",
"same_key_replay_safe": true,
"new_submission_safe": false,
"retention": "at_least_30_days_no_automatic_key_reuse"
}
}
curl --fail-with-body 'https://apimaster.ai/v1/videos/task_PUBLIC_ID' \
-H "Authorization: Bearer $APIMASTER_KEY"
curl --fail-with-body 'https://apimaster.ai/v1/videos/task_PUBLIC_ID/billing' \
-H "Authorization: Bearer $APIMASTER_KEY"
Authoritative acceptance, billing and escalation (2026-10-21)
GET /v1/video-submissions/by-key reads the saved local receipt only. It does not run provider discovery, restore a task, reserve funds or generate a replacement. Background reconciliation continues separately where the original provider supports it. Account authentication and the original Idempotency-Key are required; use the same service/account. APIMaster and RomaAPI do not share receipts. Keep the original API base and region. Independently stored regional deployments do not share claims; switching regions or services is outside the replay guarantee.
The additive data.recovery object distinguishes proof from unknown state:
| Field | Meaning |
|---|---|
acceptance_final |
The saved submission is accepted or not_accepted; acceptance is separate from task completion and billing. |
original_generation_billing_final, original_generation_zero_net |
Both are true only for a saved, validated provider not_accepted fence: original identity, no task, no reservation, all four ledger categories not_applicable, plus a completed customer refund. They cover this original generation only. False means this final zero proof is unavailable. |
safe_new_attempt |
Conservative automatic recovery gate: true only when status=not_accepted and the preceding final zero proof is complete. The original key still cannot create another generation. |
independent_asset_fees_status |
unverified; this generation receipt does not prove that independent material certification fees are zero. |
manual_review_required, escalation_status, review_after |
An unresolved submission (submitting, acceptance_unknown, or accepted without a readable task) becomes manual_review_required 30 minutes after its original creation time. This adds an operator review item; it does not reject, cancel or resubmit the original. |
support_reference, external_ticket_status |
Use the submission ID when contacting support. External provider tickets are not_tracked by this receipt; a review item is not proof that a ticket has been sent. |
lookup_attempts, last_lookup_at, last_lookup_code |
Saved background lookup diagnostics. Old records may have a null last time and empty code. provider_observation_recorded means a valid observation was saved, including an unknown outcome; provider_reconciliation_unavailable means discovery, evidence application or original-task refresh could not complete. Neither code permits replacement. |
next_check_at, next_check_is_resolution_deadline |
Next scheduled eligibility (Unix seconds, nullable), with deadline flag always false. Backoff, leases, queueing and provider availability may delay the actual check. |
resolution_deadline, cancellation_supported |
Null and false: no promised final reconciliation SLA or supported public fence/cancel for an already-sent unknown attempt. |
temporary_technical_failure, error_allows_new_submission |
A recognized technical failure can be temporary; the error alone never authorizes a new submission. |
For automatic replacement, require the authenticated original receipt to have status=not_accepted, new_submission_safe=true, recovery.acceptance_final=true, recovery.safe_new_attempt=true, and both original-generation billing flags true. This conservative gate can remain false for a local pre-send rejection lacking final billing evidence; new_submission_safe by itself describes acceptance safety, not final billing. A refund, customer net_amount=0, a missing task/dashboard row, or HTTP 404/408/429/5xx does not supply the gate. A returned task uses the original public task ID; query the original task only when task_ready=true.
Recognized technical codes are do_request_failed, read_response_body_failed, submission_storage_unavailable, refund_receipt_unavailable and build_request_failed. Generic video_service_error requires inspection and is not classified as temporary solely by its name. Neither these codes nor the lookup diagnostic codes prove non-acceptance. Preserve the original identity and query its receipt; do not infer safe replacement from a 30–60 second timeout.
Same-key delivery after lookup 404 remains covered only if the first submission was within this keyed contract and account/model/operation scope, with the same body and effective routing. Atomic claim still protects concurrency and restarts. If no claim exists yet, that POST may execute the first generation and reserve funds: it is not a read-only lookup. Do not POST when the caller permits only investigation. Originally unkeyed, pre-feature and unsupported operations do not acquire this guarantee retrospectively; legacy portrait receipts retain their documented schema. Preserve the original path, account, payload, routing and key. This release does not change the existing fallback policy.
Receipt retention of at least 30 days protects the identity/claim; it is neither a completion SLA, a result-URL lifetime nor permission to reuse an old key. A pre-send expired owner is fenced at the gateway send boundary; an already-sent unknown request requires authoritative original-provider evidence or a provider-side durable fence. No public cancellation endpoint is supplied for that case.
After the review threshold, contact the existing support channel with submission ID, request ID, public task ID, model and UTC timestamps. Never send API keys or credentials. Support should reconcile the original attempt and request either its original task/result and final ledger or authoritative non-acceptance/fencing and billing evidence. Do not create a replacement or new reservation during investigation. The local review queue is available to authenticated administrators at GET /api/admin/video-submissions/reviews?page=1 (50 items per page, has_more); it reads lookup-enabled unresolved receipts only and performs no provider calls or writes. Continue checking subsequent pages. The review threshold is a handling trigger, not an external response or resolution promise.
