Escrow API
The escrow routes, GET /key, POST /release and POST /handover.
The escrow routes exist on every coordinator. On one with ESCROW_MODE=off they answer 403 with code: "escrow_unavailable" (not retryable). They do not read the index, so they keep answering while it catches up. See Escrow and key release.
GET /key
The public key a client seals an open bid's seed to.
Auth: public · Index-backed: no
Response 200
{
"escrow_public_key": "<64 hex characters, no 0x>",
"evidence": { "type": "static-coordinator-v1", "report_data": "<64 hex characters>", "debug": false, "release": 1 },
"issued_at": 1786000000
}| Field | Meaning |
|---|---|
escrow_public_key | X25519 public key, hex without 0x. |
evidence.type | static-coordinator-v1 in production mode; mock-coordinator-v1 in development mode, which also carries measurement, tcb and quote. |
evidence.report_data | sha256(escrow_public_key ‖ utf8("vorq-coordinator-escrow-v1")), hex. |
evidence.release | The node's RELEASE_ORDINAL. |
issued_at | The node's clock, Unix seconds. |
Errors
| Status | code | Cause |
|---|---|---|
403 | escrow_unavailable | This coordinator hosts no escrow. |
503 | escrow_key_unminted | A joining development-mode instance holds no key yet. Retryable. |
curl -s https://api.vorq.co/keyPOST /release
Release an open-bid job's payload key to the provider holding its claim.
Auth: public (the signature and the chain are the authority) · Index-backed: no · Body limit: 2 KiB
Request
{
"job_id": "0x…",
"seed_wrap": "<base64, 80 bytes>",
"ct_hash": "0x<keccak256(ciphertext)>",
"response_pubkey": "<64 hex characters, no 0x>",
"issued_at": 1786000000,
"signature": "0x…"
}| Field | Rule |
|---|---|
job_id | The claimed job. |
seed_wrap | The container's 80-byte seed_wrap, canonical padded base64. |
ct_hash | keccak256 of the container's ciphertext. |
response_pubkey | A 32-byte X25519 public key, hex without 0x, to seal the answer to. |
issued_at | Unix seconds, within ±600 of the node's clock. |
signature | The claiming provider wallet's Release signature. |
The node reads the job from the chain and requires that it is Claimed, that seed_wrap and ct_hash reproduce its commitment, and that the signer is the registered wallet of the provider that claimed it.
Response 200
{ "dek_sealed": "<base64>" }The job's payload key (see Key derivation), sealed to response_pubkey.
Errors
| Status | code | Cause |
|---|---|---|
400 | stale_issued_at | issued_at outside ±600 seconds. |
400 | bad_container | Malformed seed_wrap or ct_hash. |
400 | wrap_mismatch | seed_wrap and ct_hash do not reproduce the job's commitment. |
400 | unseal_failed | No key this escrow holds opens the wrap. Fail the job within 300 seconds of the claim. |
400 | null | A malformed job_id, response_pubkey or issued_at. |
403 | wrong_wallet | The signature is malformed, or not from the provider holding the claim. |
403 | escrow_unavailable | This coordinator hosts no escrow. |
404 | no_claim | The chain has no such job. |
409 | not_claimed | The job is not in the Claimed state. |
410 | escrow_key_lost | Development mode only: the job was sealed to a key no live instance holds. Fail it within 300 seconds of the claim. |
503 | chain_unreachable, relay_unavailable (job_read, provider_id_read) | The chain read failed. Retryable. |
POST /handover
Key transfer between development-mode (ESCROW_MODE=mock) instances. It answers 403 escrow_unavailable when the escrow is off and 403 escrow_handover_disabled in production mode, where every instance already derives the same key.
Auth: an operator signature in the body · Index-backed: no · Body limit: 4 KiB
Request: {evidence, channel_pubkey, issued_at, operator_signature}, where operator_signature is a HandoverAuth(bytes32 channelPubkey,uint64 issuedAt) signature in the VORQ Escrow domain by an OPERATOR_KEY the holder accepts.
Response 200: {keys_sealed, key_count, holder_release}, the held keys sealed to channel_pubkey.
Errors: stale_issued_at, bad_binding, debug_evidence, stale_release, bad_operator_signature, operator_not_authorized, not_allowlisted, tombstoned, escrow_unavailable, escrow_handover_disabled, and retryable chain_unreachable / relay_unavailable (allowlist_status_read).