Approve a push request
Approves a requested push request: the platform pushes the pinned commit to the request's branch. git_commit must be the commit the approver reviewed; an approval naming any other is refused. An approval is also refused when the session has checkpointed since the request was made, so what is approved is what the session last committed; reject the request and ask again.
Only a verified credential that holds sessions:approve approves or rejects: an API key or a signed-in user. A workspace key (personal or agent) that started the session never approves or rejects its requests (403, refusal: self_approval); another key or a person does. Worker credentials are not accepted on /v1 at all (401). Every attempt, refused ones included, leaves a resolve_push receipt carrying the actor, the verdict and the refusal reason; a refusal's error.details.receipt_id names it. A request is approved or rejected once: a second answer, by either path, is 409 PUSH_REQUEST_RESOLVED. An Idempotency-Key is shared with /reject: replayed on either with the same answer and body, it answers the request as it is now (once the platform has taken it to push, state reads pushing, pushed or failed, while resolved_by, resolved_at and resolution_receipt_id still name this answer); with another answer or body it is 409 IDEMPOTENCY_CONFLICT.
Scope: sessions:approve (API key or cookie session). Idempotency-Key: required.
AuthorizationBearer <token>For servers and scripts: an API key sent as an HTTP bearer token, Bearer <key>. It holds exactly the scopes it was issued with; a key issued before scopes existed holds none. It never needs the CSRF header, and it cannot manage agents, members, teams or API keys. Issue one in the web console under Settings → API keys; each operation names the scope it needs.
Scope: sessions:approve
id*stringThe session's id.
^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$uuidpush_request_id*stringThe push request's id.
^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$uuidIdempotency-Key*stringRequired, 1–255 characters; a UUID per user intent works. A retry with the same key and the same body returns the original response and runs the command once; the same key with a different body answers 409 IDEMPOTENCY_CONFLICT. A missing or invalid key answers 400 BAD_REQUEST, after the body is read.
1 <= length <= 255X-Requested-With?"werft-web"Required with a cookie session: the literal werft-web.
"werft-web"application/json- body
git_commit*string^[0-9a-f]{40}$reason?string1 <= length <= 1000The request as answered.
application/json- response
id*string^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$uuidsession_id*string^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$uuidrepository_id*string1 <= lengthcheckpoint_revision*integer0 <= value <= 2147483647git_commit*string^[0-9a-f]{40}$target_branch*string1 <= lengthstate*string"requested""approved""rejected""pushing""pushed""failed"requested_by*requested_at*string^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d(?:\.\d+)?(?:Z))$date-timeresolved_by*||nullresolved_at*|nullresolution_reason*string|nullrequest_receipt_id*string^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$uuidresolution_receipt_id*|nullfinished_at*|nullpush_receipt_id*|nullorigin*string"direct""direct""intent"flow*string"legacy""legacy""actions"pr_state*|nullpr_error*|nullpr_number*|nullpr_url*|nullcurl -X POST 'https://example.com/v1/sessions/497f6eca-6276-4993-bfeb-53cbbbba6f08/push-requests/497f6eca-6276-4993-bfeb-53cbbbba6f08/approve' \ -H 'Idempotency-Key: string' \ -H 'Content-Type: application/json' \ -d '{ "git_commit": "4f2a9c1e7b3d5a8f0c6e2b9d1a4f7c3e5b8d0a2c"}'{ "id": "5b9e2c17-4f3a-4d6e-8a1b-7c0d9e2f3a41", "session_id": "0f8b6a52-3d1e-4c7a-9b2f-5e6d7c8a9b01", "repository_id": "sample-app", "checkpoint_revision": 3, "git_commit": "4f2a9c1e7b3d5a8f0c6e2b9d1a4f7c3e5b8d0a2c", "target_branch": "agent/0f8b6a52-3d1e-4c7a-9b2f-5e6d7c8a9b01", "state": "approved", "requested_by": { "principal": { "kind": "user", "id": "3e7f1a90-5c2d-4b8e-8f61-2a9d0c4b7e35" }, "actor_user_id": "3e7f1a90-5c2d-4b8e-8f61-2a9d0c4b7e35", "agent_id": null }, "requested_at": "2026-10-11T08:30:00Z", "resolved_by": { "principal": { "kind": "user", "id": "3e7f1a90-5c2d-4b8e-8f61-2a9d0c4b7e35" }, "actor_user_id": "3e7f1a90-5c2d-4b8e-8f61-2a9d0c4b7e35", "agent_id": null }, "resolved_at": "2026-10-11T08:35:00Z", "resolution_reason": null, "request_receipt_id": "c4a1e9d2-7b3f-4e8a-a6c5-1d2e3f4a5b6c", "resolution_receipt_id": "e1d2c3b4-a5f6-4789-9abc-def012345678", "finished_at": null, "push_receipt_id": null}