vault

Mint an Invite Key

kygit-invite (design D1/D2/D3/D9) — the SECOND claim kind on the same shared row: a working agent mints a single-use Invite Key another agent redeems for membership at a narrow role, the exact checkpoint, and a shared coordination room, while the inviter keeps working. One shared claim engine with kygit-handoff, parameterized by kind, not a fork. The kgi1_<invite_id||master_secret> key is assembled entirely CLIENT-SIDE (kind-domain-separated HKDF — an invite secret never verifies a handoff hash and vice versa) — invite_id is client-generated and REQUIRED in the body, same coordinator amendment as handoff_id. Auth: principalAuth (control-plane session, SIWX wallet, or admin key) at invite.mint (developer+, no grant key — minting CONFERS MEMBERSHIP and a grant key is never a member). Never lifecycle-gated. Bounds are SHARED with handoffs (one population, not two independent caps): 20 open per vault, 100 mints per org per UTC day.

post/vaults/v1/{vault_id}/invites

Request

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

Path parameters

vault_idstring required

The vault id (src_<32 hex>); the wire field on the response is repo_id.

Headers

SIGN-IN-WITH-Xstring required

SIWX auth header — base64-encoded JSON payload containing a signed CAIP-122 (EIP-4361) message. See https://docs.x402.org/extensions/sign-in-with-x.

Request body

invite_idstring uuid required

Client-generated (any UUID version). Salts the HKDF derivation of auth_secret/wrap_key, so the client must mint it before deriving the key. Used as the row's own primary key — a collision refuses 409 INVITE_ID_CONFLICT rather than ever overwriting a row.

role'owner' | 'admin' | 'developer' | 'billing' | 'viewer'

Requested role. The stored minted_role is min(requested ?? developer, the minter's own fresh role) — an invite never grants MORE than the minter's own role. Defaults to developer when omitted — NOT the minter's own role (the handoff kind's default).

expires_in_secondsinteger

TTL in seconds. Default 3600 (1 hour).

room_keystring

Optional. The agent-messaging room the claim resolves inviter/live_presences/cursor against. Omitted defaults to the vault's own project id — its default room. Plaintext, not secret; a listed invite shows it.

inviter_presence_idstring

Optional. The minter's own prs_... presence id in that room, best-effort — the mint still succeeds when this is absent or stale; the claim's inviter simply resolves to null.

sealed_envelopestring byte required

Base64 ciphertext, opaque to the gateway: {v, kind:"invite", repo_id, epoch, k_e, checkpoint, note_schema} sealed under wrap_key with the vault's frame AEAD backend. Stored verbatim; never decrypted by the gateway.

envelope_kindstring required

Client-declared envelope format tag, opaque to the gateway (e.g. "kygit-invite-envelope-v1").

auth_hashstring required

64 lowercase hex chars (32 bytes) — SHA-256("kygit/invite/auth-hash/v1" || auth_secret). The gateway stores only this hash, never auth_secret itself.

writer_admission_grantobject required

vault-multi-writer rev 47, REQUIRED (no observe mode). The minter's own signed grant proving THEY are currently an active vault writer and binding this mint: {format, object_kind, suite, repo_id, handoff_id, auth_hash, checkpoint_generation, checkpoint_head_sha256, grantor_writer_key_id, handoff_admission_pubkey, minted_role, claim_not_after, created_at, signature}. The PROTOCOL noun stays handoff (kygit-invite design D11 — one frozen admission door with two product doors in front of it): the grant's handoff_id field carries THIS invite's id, and the admission seed is the third HKDF output under info "kygit/invite/writer-admission/v1". Verified synchronously server-side under the minter's OWN signing_pubkey — every field cross-bound against this mint request's own resolved values. Stored verbatim + its sha256; echoed back byte-for-byte from the matching claim response.

Response

Invite minted. The Invite Key itself is assembled and printed exactly once, client-side (the gateway never sees it).

invite_idstring uuid required
kind'invite' required
role'owner' | 'admin' | 'developer' | 'billing' | 'viewer' required

The stored minted_role — never wider than the minter's own fresh role at mint time.

expires_atstring date-time required
repo_idstring required
org_idstring uuid required
project_idstring nullable required
writer_admission_grant_sha256string

vault-multi-writer rev 47. SHA-256 of the EXACT writer_admission_grant bytes this mint stored, so the minting client can verify the gateway stored exactly what it sent (and can seal the same value into the v2 envelope the joiner cross-checks).

warningstring required

Verbatim blast-radius sentence, the SAME sentence the handoff mint uses with this invite's role: "Whoever claims this key first becomes a <role> of this org and a writer of this vault, permanently. The key works once and expires at <expires_at>."

Example response

{
  "next_actions": [
    {
      "method": "POST",
      "path": "/tiers/v1/hobby",
      "auth": "x402"
    }
  ]
}

Changes

No recorded changes to this operation across all 1 revision of this API.