---
title: "Admit a signed head (the push)"
method: POST
path: "/vaults/v1/{vault_id}/admissions"
tags: ["vault"]
---

# Admit a signed head (the push)

`POST /vaults/v1/{vault_id}/admissions`

## Request

- Base URL: `https://api.run402.com`
- URL: `https://api.run402.com/vaults/v1/{vault_id}/admissions`
- Auth: one of:
  - API key in header `SIGN-IN-WITH-X`
  - HTTP bearer
  - HTTP bearer

THE write path. `stored_bytes` is canonical base64url of the **exact** signed object as it will be stored; `stored_bytes_sha256` is your own hash of those bytes and is checked before the protocol machine sees anything, so a transport corruption reads as a request-shape refusal rather than a signature failure. The generation is won by a create-only compare-and-swap on the admission record: a loser gets `409 HEAD_CAS_CONFLICT` carrying `details.winner` as hashes only — re-read the winner from `GET /vaults/v1/{vault_id}/admissions/{generation}`, verify it yourself, rebase, and push again. `201` means the generation is yours. `202` means the record write is not yet resolved and the platform reconciler is driving it to completion — poll, never re-push. A head carrying a `repair` descriptor additionally requires `gitvault.repair` (owner + step-up), decided from the signed bytes rather than from the URL.

## Path parameters

- `vault_id` string, required

## Headers

- `SIGN-IN-WITH-X` string, required

## Request body

- object
  - `generation` string, required: 16 lowercase hex. MUST equal the generation inside the signed object.
  - `stored_bytes` string, required: Canonical base64url of the exact stored bytes (the signed head or vault_genesis).
  - `stored_bytes_sha256` string, required: SHA-256 of those bytes, 64 lowercase hex.
  - `allocation_generation` integer: Genesis only: the allocation this genesis was prepared under.
  - `maintenance` object: Maintenance-kind admissions only: the proposed cycle binding.

## Response `201`

The generation is won (the admission record CAS succeeded)

- object
  - `admission_id` string
  - `repo_id` string
  - `generation` string
  - `admitted_object_kind` 'head' | 'vault_genesis'
  - `admitted_sha256` string, nullable
  - `state` string
  - `resource_binding_kind` 'ordinary_push' | 'maintenance_cycle' | 'repair_attempt'
  - `admission_record_sha256` string, nullable
  - `effective_admitted_at` string, date-time, nullable
  - `capture_receipt` object, nullable: Present when the head declared a capture. Exchange it at POST /vaults/v1/{vault_id}/activation-tokens.
  - `next_actions` object[]

## Other responses

- `202`: Accepted — the record write is not yet resolved; the reconciler drives it and never aborts it
- `400`: VALIDATION_FAILED — malformed bytes, a hash that does not match, or a generation that disagrees with the signed object
- `403`: VAULT_ACCESS_DENIED / REPAIR_NOT_AUTHORIZED (a repair descriptor without owner + step-up). Or (vault-multi-writer rev 47) VAULT_WRITER_NOT_ADMITTED — an authenticated active member of the vault's org whose head is signed by a key that is not in the chain's writer set at the predecessor generation and carries no valid add_writer_key transition; next_actions: sync_writers (you are a writer elsewhere — run402 repos access sync) or request_writer_sync (every current writer was told via gitvault_writer_pending; their next push, view, or access sync admits your key). Non-members keep the indistinguishable VAULT_ACCESS_DENIED.
- `409`: HEAD_CAS_CONFLICT (details.winner) / GENERATION_REGRESSION / CHAIN_BROKEN / ALLOCATION_SUPERSEDED / TRANSITION_NOT_ACTIVE / REPAIR_FENCE_PENDING / CUT_STORAGE_INTEGRITY_FAILURE
- `429`: RATE_LIMITED — the per-vault admitted-generations-per-day cap
- `503`: SERVICE_UNAVAILABLE — the vault bucket or the control-plane service signing key is not provisioned

---

[API](https://skmtc.dev/run402/apis/run402-api.md) · [All operations](https://skmtc.dev/run402/apis/run402-api/llms.txt) · [OpenAPI document](https://skmtc.dev/run402/apis/run402-api/revisions/893607557f50?raw)
