wait_for_completion: false, are rejected
before provider dispatch. Tools without that lifecycle return
IDEMPOTENCY_NOT_SUPPORTED; the error explains the supported alternative.
TypeScript
Use a caller-owned key when a worker may restart. Save both the key and the original input in your application’s job record before calling Deepline.Deepline.connect() context’s
tools.execute(toolId, input, options) accepts the same recovery options.
For a short-lived script, { recover: true } generates a key.
Save a caller-owned key when recovery must survive the script itself.
To persist a generated key before any network request, provide an awaited
onExecution callback:
recoveryTimeoutMs changes it. The first request keeps its normal timeout.
Exhausting the local
wait returns EXECUTION_RECOVERY_TIMEOUT with the key in publicDetails. It does
not cancel the provider job. Resume later with the same key.
The SDK retries connection failures between your client and Deepline, and
EXECUTION_IN_PROGRESS responses. A terminal provider error is returned to the
caller; recovery does not repeatedly submit a finished failed execution.
Inspect after a lost response
tools.execute with the original tool, input, and key. The SDK’s recovery path
does this using the original key. It never substitutes a new key after an error.
CLI
Supply a key when your scheduler already owns an execution identity:emails.json contains the tool’s normal input, for example:
--recover to generate a key before dispatch. The CLI reports it on stderr
so stdout remains machine-readable JSON. Keep that key to recover the same
execution from another process. Running a fresh command with --recover
reuses its saved key while an identical invocation is unfinished. After the
command successfully writes its output, that pending record is removed; a subsequent --recover
invocation starts new work. Use --idempotency-key for an explicit cross-process
or cross-machine identity. --recovery-timeout-ms changes the recovery wait
budget without changing execution identity.
If local output generation fails after the server completes, the pending key
is retained. Retry with the same input and response format to retrieve the
saved result. For the same response format, changing a file destination does
not create a new execution.
Raw HTTP
SendIdempotency-Key with the normal execute request:
X-Deepline-Idempotency-Supported: true, including for
an unused key’s 404 EXECUTION_NOT_FOUND. Check this before first dispatch
when integrating with a server whose recovery support is unknown. A generic
404 from an older server does not establish support.
Key and input rules
The server hashes the canonical request with SHA-256. Object property order
does not create a conflict; array order and values do. The fingerprint includes
the tool and execution-affecting options. Keep the original payload when
retrying, including wait behavior and metadata.
Resume through the same SDK, CLI, or HTTP call shape. Response format and
metadata headers also participate in comparison, so switching between the
high-level SDK’s dataset response and the raw HTTP response can conflict.
Key lookup can inspect the saved response without resubmitting those options.
Use the original API key or caller identity for recovery. Another caller in
the same workspace cannot read the execution; attempting to submit the same
key from that caller conflicts. Rotating an API key does not transfer its
saved executions to the new key.
The key stays short even for a large batch. Send the normal payload once per
HTTP attempt; the server computes its digest. A digest cannot reconstruct your
input, and idempotency does not increase HTTP or provider batch limits.
--input @file reads local JSON; it does not enable an unsupported provider
file-upload action.
States and errors
Completed responses are replayable for 24 hours after completion. The key’s
record remains after replay expiry, so reusing an expired key produces an
explicit error. Active and ambiguous executions never age into permission to
launch another call. Save results in your own durable store if you need them
beyond the replay window.
An idempotency key cannot guarantee an external provider’s outcome when the
provider accepts work and the process dies before its job ID can be saved.
Deepline preserves that uncertainty and refuses duplicate dispatch. Once a
recoverable async job ID is durably saved, recovery follows that job.
Billing and Plays
Replay returns the original response and its Deepline billing fields. It does not create a new paid execution. Recovery state describes execution delivery; it does not change billing finality or turn missing billing into a zero charge. Use the billing status and amount in the execution response. For a recovered async job, the completed response refers to the original execution’s billing identity. Status and result-fetching calls do not replace the parent execution’s cost. Replaying a saved response does not refresh its settlement status: a savedqueued observation can remain queued even after
the charge posts.
To read current usage for the result above, use its job_id with the client’s
exact billing lookup:
GET /api/v2/usage/events?request_id=<job_id>. This reads
usage; it does not resume execution. A missing event or an unset credit amount
does not establish a zero charge. Use an explicit recorded amount, including
zero and its outcome reason, when available.
After a lost response, executions.getByKey(key) also returns requestId, the
same server-owned ID as the original response’s job_id. You can pass it to
client.billing.usageEvent() while the execution is running or its result is
unknown. This lets you investigate billing without resubmitting paid work.
Idempotency is scoped to one execution. It does not impose a shared spending
limit across different keys or concurrent workers.
Inside a Play, continue using ctx.tools.execute({ id, tool, input }). Plays
already own run and call identities. A Play call’s id is not a public API
idempotency key. Use the Play’s run ID and run APIs to recover the workflow;
this direct-tool API does not change Play authoring syntax.