Org

Publish the caller's own vault directory key (human or agent principal)

Self-only, custody-eligible principals only (human | agent; a ci caller is refused NOT_A_RECIPIENT_PRINCIPAL): publishes the caller's own X25519 public key + ek_ fingerprint to the org-scoped encryption-key directory (vault-human-envelopes, widened by vault-agent-envelopes). The private key never reaches the gateway. custody_scheme: keystore_v1 is the CLI keystore's own key (no wrappers — the keystore file is the custody): the row is created PENDING and the response carries activation (an ECDH possession challenge) — answer it on POST /agent/v1/whoami/encryption-key/activate; a pending key is a recipient nowhere. Republishing the principal's CURRENT key is an idempotent 200 (deduplicated: true). A DIFFERENT key is refused 409 KEY_ROTATION_REQUIRED — rotation is never automatic (a stolen wallet key must not replace a member's decryption identity); remedies: restore the keystore backup, have an org owner revoke the stale key (DELETE /orgs/v1/:org_id/members/:principal_id/encryption-key), or — only for a principal that is the sole custody-eligible member of every org it belongs to — republish with replace_current: true (otherwise 403 KEY_ROTATION_NOT_SELF_AUTHORIZABLE). Credential-gated: SIWX or a control-plane session only — a grant key bearer, CI session, service key, or admin key never reaches this route. The SDK runs this automatically on the first vault operation of a keystore with no published key (run402 repos …, git clone/push); there is no enrollment verb.

post/agent/v1/whoami/encryption-key

Request

  • Base URL: https://api.run402.com
  • URL: https://api.run402.com/agent/v1/whoami/encryption-key
  • Auth: one of:
    • API key in header SIGN-IN-WITH-X
    • HTTP bearer

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

public_keystring required

Canonical base64url-encoded 32-byte X25519 public key.

ek_fingerprintstring required

ek_<32 hex> — first 16 bytes of SHA-256(raw pubkey).

suitestring

Defaults to r402s-1.

key_idstring uuid

Client-minted key row UUID — required when wrappers[] is supplied (it is bound inside every wrapper's sealed context).

custody_scheme'legacy_direct_prf_v1' | 'wrapped_legacy_scalar_v1' | 'wrapped_random_v1' | 'keystore_v1'

EXPLICIT custody declaration (consult round 1: never inferred from wrapper count). keystore_v1 — the CLI keystore's key, no wrappers, pending until the possession proof; wrapped_* require wrappers[]; omit for a legacy direct-PRF browser enrollment.

replace_currentboolean

vault-agent-envelopes D3: replace a DIFFERENT current key. Honored only when the caller is the sole custody-eligible member of every org it belongs to; otherwise 403 KEY_ROTATION_NOT_SELF_AUTHORIZABLE. Never implied.

signing_pubkeystring

vault-multi-writer rev 47. Canonical base64url-encoded 32-byte Ed25519 public key — the vault-WRITER signing half, unrelated to public_key above (the encryption half). OPTIONAL, and ALL-OR-NONE with signing_fingerprint/possession_signature: omitting all three publishes only the encryption half, byte-identical to a pre-rev-47 client.

signing_fingerprintstring

vault-multi-writer rev 47. vk_<32 hex> derived from signing_pubkey via the same keyFingerprint convention add_writer_key/p0062 use — a self-consistency check, not a separate derivation. Mismatched against a re-derivation from signing_pubkey → 400 VALIDATION_FAILED naming possession_signature.

possession_signaturestring

vault-multi-writer rev 47. Ed25519 signature over JCS{domain:"r402s/v0/signing-key-possession/v1", principal_id, signing_pubkey, encryption_pubkey}, verified SYNCHRONOUSLY under signing_pubkey — no challenge round-trip, since a valid signature already IS possession. The signing half is NEVER rotation-gated: publishing a new signing key grants nothing by itself (becoming a vault writer still needs an existing writer's cooperation or a handoff grant+acceptance), so there is no KEY_ROTATION_REQUIRED analog here.

Response

Key published — state: pending for keystore_v1 (answer activation on /activate) or when wrappers were supplied (activate the first wrapper); active for a legacy direct-PRF publish. A 200 with deduplicated: true means the submitted key already IS the principal's current key (no write).

principal_idstring uuid
encryption_key_idstring uuid
ek_fingerprintstring
suitestring
custody_schemestring
state'pending' | 'active'
created_atstring date-time
signing_fingerprintstring nullable

vault-multi-writer rev 47. vk_<32 hex> for the signing half just published/refreshed, or the principal's existing one if this call omitted the signing fields entirely (byte-identical to a pre-rev-47 response, and null if no signing half has ever been published). Never the raw signing_pubkey.

signing_possession_verified_atstring date-time nullable

vault-multi-writer rev 47. Timestamp the possession_signature was verified — synchronous with this call, so equal to created_at/now on a fresh signing-half publish; carried forward unchanged when this call didn't touch the signing half.

deduplicatedboolean

True when the publish matched the principal's current key exactly and nothing was written.

next_actionsobject[]

Changes

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