# Seedance original-submission recovery

Scope: `seedance-2.0`, `seedance-2.0-fast`, `seedance-2.0-mini`, `seedance-2.5`; generation paths `/v1/videos`, `/v1/videos/generations`, `/v1/video/generations`. Keys: 8–128 visible ASCII characters, scoped to the RomaAPI account and generation operation. Another valid key in the same account may read the receipt, subject to authentication and IP restrictions. Atomic claims precede routing/billing/provider contact. Same-key equivalent-body replay is safe across concurrency/restarts; changed model/body/effective routing returns `409 idempotency_conflict`. JSON object ordering/whitespace and multipart boundary/filenames are ignored; array/file order, content, explicit defaults, numeric spelling and routing remain significant. Receipt retention is at least 30 days, with no automatic key reuse.

## 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.

## 受理、最终账务与人工处理（2026-10-21）

`GET /v1/video-submissions/by-key` 只读取已保存的本地回执，不发起供应商查询、不恢复任务、不预扣、不生成替代任务。支持原供应商核对的请求由现有后台独立处理。使用原服务、原账户的有效认证及原 `Idempotency-Key`；APIMaster 与 RomaAPI 不共享回执。保留原 API 基址和区域；使用独立数据库的区域部署不共享原子占用记录，跨区域或跨服务切换不属于同 key 恢复保证。

新增 `data.recovery`，明确区分已确认事实与未知状态：

| 字段 | 含义 |
| --- | --- |
| `acceptance_final` | 本地回执已为 `accepted` 或 `not_accepted`；受理最终态不等于任务成功或账务完成。 |
| `original_generation_billing_final`、`original_generation_zero_net` | 仅在已保存并校验原身份的供应商明确 `not_accepted`、无任务、无预留、四类账本均为 `not_applicable`，且客户退款完成时同时为 true。只证明这笔原生成，不包含独立素材认证费用。false 表示尚无此最终零净额证明。 |
| `safe_new_attempt` | 自动恢复的保守门槛：只有 `status=not_accepted` 且上述最终零净额证据齐全才为 true；旧 key 仍不能启动另一次生成。 |
| `independent_asset_fees_status` | `unverified`，不能由生成回执推断独立素材认证费用为零。 |
| `manual_review_required`、`escalation_status`、`review_after` | `submitting`、`acceptance_unknown` 或 `accepted` 但任务不可读的请求，自原创建时间满 30 分钟后显示 `manual_review_required` 并进入管理员待处理列表。不会自动拒绝、取消或重提。 |
| `support_reference`、`external_ticket_status` | 用提交 ID 联系现有客服渠道。外部供应商工单为 `not_tracked`；待处理条目不代表已经向供应商发送工单。 |
| `lookup_attempts`、`last_lookup_at`、`last_lookup_code` | 已保存的后台核对次数、最近时间和结构化诊断；旧记录可能无最近时间或诊断。`provider_observation_recorded` 表示已保存有效观察，观察仍可能是未知；`provider_reconciliation_unavailable` 表示发现、证据应用或原任务刷新未完成。两种诊断都不授权重提。 |
| `next_check_at`、`next_check_is_resolution_deadline` | 下次调度可处理时间，Unix 秒或 null，期限标记始终 false。退避、租约、排队及上游可用性可能推迟实际查询。 |
| `resolution_deadline`、`cancellation_supported` | null 和 false；没有已承诺的最终对账 SLA，也没有可保证封锁已发送未知请求的公开取消接口。 |
| `temporary_technical_failure`、`error_allows_new_submission` | 可识别临时技术失败，但错误本身永不授权新提交。 |

自动创建替代任务前，应同时要求认证后的原回执满足：`status=not_accepted`、`new_submission_safe=true`、`recovery.acceptance_final=true`、`recovery.safe_new_attempt=true`，以及两个原生成账务标记均为 true。对于缺少最终账务证明的本地发送前拒绝，保守门槛仍可为 false；旧字段 `new_submission_safe` 只描述受理安全，不代表最终账务。退款、客户净额为零、任务或面板行不存在，以及 HTTP 404/408/429/5xx 均不足以证明可重提。只有 `task_ready=true` 才查询原公开 task ID 的任务。

识别的技术错误为 `do_request_failed`、`read_response_body_failed`、`submission_storage_unavailable`、`refund_receipt_unavailable`、`build_request_failed`。通用 `video_service_error` 需具体检查，不仅凭名称认定临时失败。以上错误和核对诊断均不能证明未受理；保留原身份查询，不能按 30–60 秒超时推断安全重提。

lookup 404 后的同 key 交付仍要求首次请求已经处于受支持的账户、模型、操作和带 key 合同范围内，正文及有效路由相同；原子占用仍覆盖并发和重启。如果记录尚未建立，该 POST 可能成为第一次执行并预扣，并非只读查询。仅获准调查时不得发送 POST。原本不带 key、功能上线前或不支持的操作不能事后获得此保证；旧人像回执保持原有 schema。保留原路径、账户、正文、路由及 key。本次不改变既有 fallback 策略。

至少 30 天的保留期保护回执与 key 的对应关系，不是完成期限、结果链接有效期或旧 key 重用许可。网关可阻止发送前已过期的原执行者继续发送；已经发送且结果未知的请求，仍需原供应商权威证据或持久封锁证明。当前没有可为此情况提供确定性封锁的公开取消接口。

超过处理提醒阈值后，向现有客服渠道提供 submission ID、request ID、公开 task ID、模型及 UTC 时间，不提供 API key。人工应核对原尝试，要求原任务/结果和最终账本，或最终未受理、封锁及账务证据。调查期间不创建替代任务或新预留。管理员可认证访问 `GET /api/admin/video-submissions/reviews?page=1`，每页 50 条，按 `has_more` 继续翻页；仅列已启用核对的未决请求，不查询供应商、不写入数据。30 分钟是进入待处理列表的阈值，不是外部响应或最终结案承诺。
