vault

Redeem a Handoff Key

kygit-handoff (design D3). Verifies auth_secret against the stored auth_hash (constant-time compare) and, on success, atomically flips the recipient into an active org member at the handoff's stored role and returns the sealed envelope for the recipient's own client to decrypt (the gateway never sees the plaintext). ONE transaction, no durable lease — first writer wins. A SAME-principal replay before expiry returns 200 deduplicated:true with the ORIGINAL sealed envelope (safe: only the key holder can derive wrap_key). Auth: SIWX WALLET ONLY — a control-plane session, grant key, or service key is refused 403 HANDOFF_REDEEM_REQUIRES_WALLET, because the keystore key published on this call is what makes the recipient a real key-holder. Tier-free: principalAuth resolves-or-provisions the caller's own org-of-one with no active tier required. Never lifecycle-gated. Response carries Cache-Control: no-store — it is never cached by an intermediary. vault-multi-writer rev 47, REQUIRED (no observe mode): the redeemer must ALSO submit writer_acceptance, its own double-signed acceptance of the mint-time writer_admission_grant — both signatures independently verified. On success the redeemer's directory signing half is published possession-verified in the SAME transaction.

post/vaults/v1/handoffs/{handoff_id}/redeem

Request

  • Base URL: https://api.run402.com
  • URL: https://api.run402.com/vaults/v1/handoffs/{handoff_id}/redeem
  • Auth: API key in header SIGN-IN-WITH-X

Path parameters

handoff_idstring uuid required

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

auth_secretstring required

Base64url — the HKDF-derived auth_secret half of the parsed kgh1_ key (64 lowercase hex characters are accepted as a permanent compatibility form: the public client 4.67.0–4.68.0 sent that). Client-derived only; a malformed value simply never matches any stored hash (never a distinguishing error).

writer_acceptanceobject required

vault-multi-writer rev 47, REQUIRED (no observe mode). The redeemer's own double-signed acceptance of the mint-time writer_admission_grant: {statement: {domain:"r402s/v0/handoff-writer-accept/v1", handoff_id, auth_hash, writer_key_id, signing_pubkey, encryption_pubkey, encryption_fingerprint}, acceptance_signature, possession_signature}. acceptance_signature verifies under the STORED grant's handoff_admission_pubkey; possession_signature verifies under the redeemer's OWN signing_pubkey — both over the identical preimage, genuinely independent proofs. A redeem under a DIFFERENT writer_key_id than an earlier successful redeem by the same principal refuses 409 HANDOFF_REDEEM_WRITER_KEY_MISMATCH.

Response

Claimed. On a same-principal replay before expiry, deduplicated is true and sealed_envelope is the ORIGINAL envelope (never a pretend re-redeem).

handoff_idstring uuid required
kind'handoff' required
deduplicatedboolean required
sealed_envelopestring byte required

Base64 ciphertext — decrypt client-side under the derived wrap_key. The gateway never sees the plaintext.

envelope_kindstring required
repo_idstring required
org_idstring uuid required
project_idstring nullable required
membersobject[] required

Every current member of the org, so the recipient sees whether the sender is still present.

expires_atstring date-time required
writer_admission_grantobject required

vault-multi-writer rev 47. The ORIGINAL writer_admission_grant from the mint, echoed back byte-for-byte for the client to persist/replay.

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.