ExchainDocs
DocsAPI

CosignRefusals and retries

Refusals and retries

Read a 409, retry safely, and rebuild a refused batch.

Every co-sign refusal is HTTP 409. Nothing is signed, and refused purchases consume no budget. This page applies to every co-sign endpoint: POST /v1/cosign, POST /v1/evm/cosign and POST /v1/x402/cosign.

Alarm codes page Exchain. body_mismatch, payee_unpinned and clock_skew page Exchain's on-call engineer. An honest, correctly built request never triggers them.

Two kinds of 409

Purchase-levelBatch-level
denied"member_denied"The code, for example "payee_unpinned"
members[]Each allowed or denied, with a code, reasonEnglish and numbersAll not_evaluated
Extrarebuild object (Cardano)alarm, optional detail

An EVM request carries one intent, so its purchase-level refusal has one member: read the code in members[0].denied.

409 Conflict, member_denied (Cardano batch)
{
  "decisionId": "dec_01J9XK3M4N5P6Q7R8S9T0V1W2X",
  "txBodyHash": "blake2b_256:<64 hex>",
  "requiredSigners": ["<agent key hash>", "<quorum key hash 1>", "<quorum key hash 2>", "<quorum key hash 3>"],
  "denied": "member_denied",
  "members": [
    { "purchaseId": "pur_1", "outputIndex": 0, "verdict": "allowed" },
    { "purchaseId": "pur_2", "outputIndex": 1, "verdict": "denied", "denied": "per_tx_cap",
      "reasonEnglish": "A single payment of 250 tADA exceeds the per-payment cap of 200 tADA.",
      "bound": "200000000", "used": "100000000", "attempted": "250000000" },
    { "purchaseId": "pur_3", "outputIndex": 2, "verdict": "allowed" }
  ],
  "rebuild": { "keep": ["pur_1", "pur_3"], "batchId": "7f0c3d2e-9a4b-4c1d-8e2f-000000000002",
               "heldUntil": "2026-11-05T10:02:01Z" },
  "alarm": false,
  "journalRef": "https://cosign.exchain.network/v1/decisions/dec_01J9XK3M4N5P6Q7R8S9T0V1W2X",
  "asOf": "2026-11-05T10:00:01.412Z",
  "schemaVersion": "1.1",
  "chainTip": { "slot": 138150155, "blockHash": "<64 hex>" }
}

Retries

Send Idempotency-Key equal to batchId on every request.

You sendExchain does
Same batchId, same bodyReturns the stored answer byte for byte. Nothing counts twice
Same batchId, new body, after a 200 (Cardano)Makes a new decision that counts again. The first budget returns only if its transaction never lands
Same signed authorization, different walletId or intent (EVM)409 idempotency_conflict
Same nonce, different typed data (EVM)409 body_mismatch, detail: "nonce_reused"

purchaseId is not a dedupe key.

When to retry, by code

CodeAction
daily_outflow, per_agent_capRetry at windowResetsAt or after retryAfterSec
per_seller_cap, velocity_burstRetry after retryAfterSec. A per_seller_cap refusal also allows paying another seller now
reservation_conflictRetry as soon as the hold clears (Cardano)
utxo_unknown with stale_refRebuild on the wallet's current UTxO (Cardano)
idempotency_conflictDo not retry. Sign a new authorization with a new nonce (EVM)
per_tx_cap, envelope_exhausted, registry_gate, price_above_published, counterparty_blocked, asset_not_listedDo not retry unchanged
body_mismatch, payee_unpinned, clock_skewAlarm. Investigate; do not retry

Every code: Errors and codes.

Rebuild a Cardano batch

A Cardano batch can carry several purchases. When some are refused:

  1. Exchain judges purchases in submission order, each against state that includes the earlier admitted ones.
  2. Admitted purchases are held until rebuild.heldUntil, 120 seconds after the refusal.
  3. Rebuild the body with exactly rebuild.keep and send it under the same batchId. While the hold lasts, those purchases fit.
During the holdExchain does
Same batchId, new bodySupersedes the old decision and evaluates the new body
Another batch for the wallet409 reservation_conflict. Retry after the hold (at most 120 seconds)

EVM answers

Besides 409, EVM co-sign requests can return:

AnswerMeaningAction
401 agent_signature_invalidThe agent signature does not recover to the agent over the Safe message hashSign the Safe message hash, raw 65 bytes
402 fee_dueFees reached the settlement threshold. Nothing was decidedSettle fees, then retry
400 batch_id_mismatchbatchId is not the authorization nonceSet batchId to the nonce
400 idempotency_key_mismatchIdempotency-Key differs from batchId (every rail)Send the same value in both
409 body_mismatch, detail: "nonce_reused"The nonce was already decided for another paymentSign a new authorization with a new nonce
409 body_mismatch, detail: "safe_nonce"A SafeTx is not at the Safe's current nonceSign it again at the current nonce
200 with relayErrorSigned, but Exchain could not send it (direct only)Send transaction from any account before it expires

When Exchain cannot decide

AnswerMeaningAction
503 quorum_unavailableFewer members of the attested quorum are reachable than the threshold; the body has reachable and threshold. Nothing consumedRetry after Retry-After: 5
503 quorum_unavailable, detail: "stopped"Exchain paused signingRetry after 60 seconds
503 quorum_unavailable, detail: "record" on POST /v1/cosign; 503 unavailable, detail: "record" on the EVM endpointsThe audit record could not be writtenRetry after Retry-After: 5
429 rate_limitedOver your node's request rate, 120 a minute by defaultRetry after retryAfterSec
400 clock_rejectedExchain's clock check failedContact Exchain

A signed payment that never lands has its budget returned: After you submit (Cardano) and EVM settlement.

On this page