Skip to content

Generation deletion

Delete a finished generation with DELETE /v1/generations/{id} and track the asynchronous deletion task with GET /v1/deletions/{task_id}.

Deleting a generation is asynchronous: DELETE accepts the request and returns a deletion task immediately (HTTP 202), then a background worker removes the generation’s content. Track progress by polling the task with GET /v1/deletions/{task_id} until it reaches a terminal state. The API Reference documents both routes: Delete a generation and Get a deletion.

Terminal window
curl -X DELETE https://agents.lumalabs.ai/v1/generations/$GENERATION_ID \
-H "Authorization: Bearer $LUMA_AGENTS_API_KEY"
Terminal window
curl -X DELETE https://agents.lumalabs.ai/v1/generations/0fa56b9a-1c10-4ad5-8a8c-9d23b9e1f0aa \
-H "Authorization: Bearer $LUMA_AGENTS_API_KEY"

Response (HTTP 202 Accepted): a DeletionTask describing the accepted task.

{
"id": "d4e5f6a7-b8c9-4012-8def-0123456789ab",
"resource_type": "generation",
"resource_id": "0fa56b9a-1c10-4ad5-8a8c-9d23b9e1f0aa",
"state": "scheduled",
"phase": null,
"blocked_reason": null,
"requested_at": "2026-10-08T12:00:00Z",
"updated_at": "2026-10-08T12:00:00Z",
"scheduled_at": "2026-10-08T12:00:00Z",
"delete_deadline": "2026-10-09T12:00:00Z",
"completed_at": null,
"overdue": false
}

The id is the task id — poll it with GET /v1/deletions/{task_id}. resource_type is always "generation" and resource_id is the generation id you asked to delete. A new task starts in state: "scheduled" (due to run immediately); a worker then moves it to queued, running, and finally completed. If a deletion task for the generation already exists, you get that task instead — see Repeating DELETE and Deletions Luma schedules automatically.

Depending on how deletion is configured for your API client, Luma can create a deletion task for a generation when it finishes, without any DELETE from you: for example once your client’s retention period has passed, or after a grace period for a failed generation (never longer than your client’s retention period). Such a task covers the same root generations DELETE accepts. Its requested_at is when the generation finished, it is due at the end of the retention or grace period, and its delete_deadline is 24 hours after that.

A first DELETE for such a generation returns that task (HTTP 202), not a new one:

  • While the task is active, its requested_at becomes the time of your DELETE. If the task is scheduled or queued, it also becomes due now at the latest, with a delete_deadline no later than 24 hours after your request; in any other active state (running, retry_wait, blocked) its schedule and deadline stay as they were.
  • Once the task has completed and the generation is gone, DELETE returns the completed task rather than 404. Its requested_at and scheduled_at are the ones Luma set when the generation finished, and completed_at can be days old.

While the earlier task is still active (any state other than completed or cancelled), issuing DELETE again for the same generation returns HTTP 202 with the same task. Once the generation itself is gone, a repeat DELETE also answers 202 with the most recent task for it rather than 404. If the earlier task was cancelled and the generation still exists, a new DELETE starts a new task with a new id. Always track the id from the latest 202. A caller cannot tell a first acceptance from a repeat by the status code.

The one distinct refusal: not yet terminal

Section titled “The one distinct refusal: not yet terminal”

A generation is deletable only once its whole tree is terminal (every session in the tree has finished) and no session in the tree holds an unsettled billing reserve. If you delete a generation that is still running or still settling, you get:

HTTP 409 GENERATION.NOT_TERMINAL — “Generation is still running or settling; delete it after it completes or fails.”

{
"detail": {
"code": "GENERATION.NOT_TERMINAL",
"message": "Generation is still running or settling; delete it after it completes or fails."
}
}

This is the only refusal that distinguishes a generation you own from one you do not. A generation owned by another client, a non-existent id, and a non-UUID path all return the same HTTP 404 {"detail": "Generation not found"} — except that your own generation already removed by a deletion task answers 202 with its latest task (see Repeating DELETE). If generation deletion is not enabled for your client, a request that passes authentication returns HTTP 404 {"detail": "Not Found"} before the id is looked at.

Terminal window
curl https://agents.lumalabs.ai/v1/deletions/d4e5f6a7-b8c9-4012-8def-0123456789ab \
-H "Authorization: Bearer $LUMA_AGENTS_API_KEY"

Response (HTTP 200): the same DeletionTask shape, now reflecting the task’s current state.

{
"id": "d4e5f6a7-b8c9-4012-8def-0123456789ab",
"resource_type": "generation",
"resource_id": "0fa56b9a-1c10-4ad5-8a8c-9d23b9e1f0aa",
"state": "completed",
"phase": null,
"blocked_reason": null,
"requested_at": "2026-10-08T12:00:00Z",
"updated_at": "2026-10-08T12:02:17Z",
"scheduled_at": "2026-10-08T12:00:00Z",
"delete_deadline": "2026-10-09T12:00:00Z",
"completed_at": "2026-10-08T12:02:17Z",
"overdue": false
}

A task id that is not a UUID, does not exist, belongs to another client, or is not a generation deletion returns HTTP 404 {"detail": "Deletion not found"} — the route does not say which. If generation deletion is not enabled for your client, it returns HTTP 404 {"detail": "Not Found"} instead.

Poll GET /v1/deletions/{task_id} for state until it is terminal. There is no webhook for deletion completion. A reasonable cadence is a short backoff (a few seconds, then lengthening).

Terminal window
# Poll until the task is completed, cancelled or blocked; only "completed" means the content was removed.
for attempt in $(seq 1 60); do
body=$(curl -s -w '\n%{http_code}' https://agents.lumalabs.ai/v1/deletions/$TASK_ID \
-H "Authorization: Bearer $LUMA_AGENTS_API_KEY")
code=$(printf '%s' "$body" | tail -n1)
if [ "$code" != "200" ]; then
echo "HTTP $code: $(printf '%s' "$body" | sed '$d')" >&2
exit 1
fi
state=$(printf '%s' "$body" | sed '$d' | jq -r .state)
echo "state=$state"
case "$state" in
completed) exit 0 ;;
cancelled)
echo "deletion cancelled before it completed" >&2
exit 1 ;;
blocked)
echo "blocked: $(printf '%s' "$body" | sed '$d' | jq -r .blocked_reason)" >&2
exit 1 ;;
esac
sleep 5
done
echo "still $state after 60 attempts" >&2
exit 1

Do not poll GET /v1/generations/{generation_id} to track deletion. Once a deletion is accepted, the generation’s outputs and then the generation itself are removed while the task is still running, so that route can return partial content, or 404, before the task reaches completed. Only state: "completed" on the deletion task confirms the removal was verified.

state moves through an asynchronous lifecycle. Every state other than completed and cancelled is active; those two are terminal.

StateMeaning
waitingAccepted; not yet scheduled to run.
scheduledScheduled to run. A task created by DELETE starts here.
queuedDue and waiting for, or claimed by, the worker.
runningA worker is executing the deletion.
retry_waitThe previous run ended before finishing; the task is due to be picked up again.
blockedStopped — see blocked_reason. Not terminal, but the worker does not retry it (see below).
completedTerminal. The generation’s content was removed. completed_at is set.
cancelledTerminal. The deletion was cancelled before its irreversible step began. This API cannot cancel tasks.

completed and cancelled are terminal: stop polling once you see either. Only completed means the content was removed. After cancelled, contact support, or issue DELETE again — while the generation still exists, that starts a new task.

phase reports the last execution phase the task reached:

PhaseMeaning
stoppingConfirming every session in the generation’s tree is terminal and holds no unsettled billing reserve.
discoveringEnumerating what the deletion will remove.
waiting_for_childrenWaiting for child deletion tasks to remove the generation’s artifacts.
deletingRemoving the generation’s session rows.
verifyingEvery removal has run; checking them before completing the task.

phase is null until the task first runs, and again once it is completed. In queued, retry_wait, blocked, and cancelled it keeps the phase where the last run stopped.

When state is blocked, blocked_reason says why. Some failures are retried automatically, with backoff, while the task stays running; others block the task at once. A failure removing one of the generation’s artifacts does not block the generation’s task: it stays active (phase waiting_for_children) until that artifact is removed — contact support if a task is still active past its delete_deadline. The worker never picks up a blocked task. Apart from dependency_cancelled, which clears when a replacement child task is attached, a blocked task stays blocked until Luma acts on it — contact support as soon as you see blocked.

blocked_reasonMeaning
settlement_pendingWhen content removal ran, a session in the tree was still running or still held an unsettled billing reserve.
shared_bytesNot produced for generation deletions today.
fk_dependencyNot produced for generation deletions today.
external_errorRemoving or checking content kept failing after the automatic retries, or a session in the tree was still running or held an unsettled billing reserve when the task started or tried to complete.
dependency_cancelledA child task this deletion waited on was cancelled.
operator_holdAn internal check refused a step; the task is held for Luma to review.

Each accepted task carries a delete_deadline — the time by which Luma targets completion. When DELETE creates a new task, its deadline is 24 hours after that request and the task is due to run immediately (scheduled_at ≈ requested_at). A repeat DELETE returns the existing task with the clocks it already has. A task Luma created automatically is due at the end of its retention or grace period; a first DELETE can only move it earlier (see Deletions Luma schedules automatically).

overdue is true once delete_deadline has passed without the task completing, or when it completed after the deadline — so a completed task can carry overdue: true permanently, and a cancelled task turns overdue once its deadline passes. overdue does not change state: a blocked task stays blocked whether or not it is overdue, so do not wait for overdue before contacting support about a blocked task.

What a deletion removes — and what it does not

Section titled “What a deletion removes — and what it does not”

Deleting a generation removes the content the generation itself produced and owned:

  • The output artifacts the generation’s own jobs produced (images, videos, and their storage objects). An output that a job outside the generation also produced is not removed, and stored bytes another live artifact still references are kept.
  • The artifacts born into the generation as fresh inputs (api_attachment_sessions) — for example inline or URL inputs you supplied with the request. These artifacts are deleted with the generation even if something else still references them; as with outputs, stored bytes another live artifact still references are kept. Files referenced by file_id are not in this set.
  • The session rows for the generation tree, torn down in foreign-key order.
  • Access to the generation — child artifacts are removed first, then the session row is hard-deleted while the task is still running, so GET /v1/generations/{id} returns 404 before the task reaches completed.

Billing records are kept. The credits charged for the generation are not removed when its content is deleted. In GET /v1/usage grouped by tenant_id or metadata, a deleted generation’s credits are reported under unattributed_credits, because the session that carried those tags no longer exists.

Not removed — uploaded files are independent

Section titled “Not removed — uploaded files are independent”

To remove an uploaded file, delete it directly:

Terminal window
curl -X DELETE https://agents.lumalabs.ai/v1/files/0fa56b9a-1c10-4ad5-8a8c-9d23b9e1f0aa \
-H "Authorization: Bearer $LUMA_AGENTS_API_KEY"

See the Files guide for how file deletion works.

Both DELETE /v1/generations/{generation_id} (202) and GET /v1/deletions/{task_id} (200) return the same envelope.

FieldTypeMeaning
idUUIDThe deletion task id. Poll GET /v1/deletions/{id}.
resource_type"generation"Always generation on this surface.
resource_idstringThe generation id the task deletes.
statestringThe deletion state — see States.
phasestring | nullThe last execution phase reached — see Phases; null before the first run and once completed.
blocked_reasonstring | nullWhy the task is blocked — see Blocked reasons; null unless state is blocked.
requested_attimestampWhen your first DELETE was accepted; for an automatic task you never deleted, when the generation finished.
updated_attimestampWhen the task last changed — a state transition or execution progress.
scheduled_attimestamp | nullWhen the task became due to run; ≈ requested_at for a task created by DELETE.
delete_deadlinetimestamp | nullThe target completion deadline (24 h after the request for a task created by DELETE).
completed_attimestamp | nullSet when state is completed.
overduebooleantrue when delete_deadline passed before completion, or completion came after it.
HTTPCodeWhen
202—Deletion accepted: a new task, an idempotent re-accept, or a task Luma created automatically for the generation.
401—Missing or invalid API key — see Error handling.
403—The request was made with an admin read-only API key, which cannot call these routes, or your API client is suspended or deactivated.
404— ("Not Found")The path did not match a route (for example an empty id), or generation deletion is not enabled for your client.
404— ("Generation not found")DELETE /v1/generations/{generation_id}: the id is not a UUID, or the generation is not yours, does not exist, or is not a root generation (for example a child session). Your own generation already removed by a deletion task answers 202 with that task instead.
404— ("Deletion not found")GET /v1/deletions/{task_id}: the id is not a UUID, or the task is not yours, not a generation deletion, or does not exist.
409GENERATION.NOT_TERMINALYour own generation is still running or still holds an unsettled reserve.
429—Rate limited — see Error handling.

A 404 carries no code field, only detail. Within each route the not-found body is the same whether the id is foreign, missing, or malformed, so a caller cannot tell another client’s id from one that does not exist.

Can I delete a generation that is still running?

No. DELETE returns 409 GENERATION.NOT_TERMINAL until every session in the generation’s tree is terminal and no session holds an unsettled billing reserve. Poll the generation to completion (or failure) first, then delete; a 409 right after completion means billing is still settling, so retry after a short delay.

What happens if I call DELETE twice?

While the first task is active, or once the generation is gone, the second call returns 202 with the same task. Even a first call can return an existing task, active or completed, if Luma had already scheduled the generation for deletion — see Deletions Luma schedules automatically. If the first task was cancelled and the generation still exists, the second call starts a new task with a new id; always track the id from the latest 202.

How do I know the deletion finished?

Poll GET /v1/deletions/{task_id} until state is completed or cancelled; only completed means the content was removed. There is no deletion-completion webhook. Do not poll the generation itself — it can return partial content or 404 while the task is still running.

Are my uploaded files deleted too?

No. Files uploaded via /v1/files are independent of the generations that reference them by file_id; deleting a generation never deletes the file. Delete files you no longer need with DELETE /v1/files/{file_id} directly — see the Files guide.

Is the billing history kept?

Yes. The credits charged for a deleted generation stay in your billing records; usage grouped by tenant_id or metadata reports them under unattributed_credits.

Why did I get a 404 when I can see the generation in the playground?

"Not Found" means the request did not reach a deletion: the path did not match a route (for example an empty id), or deletion is not enabled for your client; "Generation not found" means the id is not a UUID, is not yours, does not exist, or is not a root generation; your own generation already removed by a deletion task answers 202 with that task instead.

What does overdue: true mean?

The task passed its delete_deadline before completing, or completed after it — a completed task keeps overdue: true. overdue does not change state; a blocked task needs Luma to act whether or not it is overdue, so raise it with your support contact as soon as you see blocked.

Is this in the SDK?

No. The deletion routes are in the API Reference (Delete a generation, Get a deletion) but not yet in the SDKs. Call them over HTTP as shown on this page.