ExchainDocs
DocsAPI

APIAPI

API

Base URL, authentication, envelope, idempotency and limits, with one page per endpoint.

Everything every Exchain API call shares: one base URL, three credentials, one envelope and one set of limits.

Basics

  • Base URL: https://cosign.exchain.network.
  • JSON in and out. Amounts are minor-unit strings.
  • The OpenAPI document at /openapi.yaml and /openapi.json is the one the service validates requests against.
  • No CORS headers: call the API from a backend.

Network selection

There is no network in the URL. The Node Token's node decides it: a preprod node works on Cardano preprod and the EVM testnets, a mainnet node on Cardano mainnet and the EVM mainnets (Networks). A read token uses its wallet's network. See Networks and assets.

Authentication

Send Authorization: Bearer <credential>.

CredentialWorks onLifetime
Node TokenEvery /v1 contract and read route, for wallets this node registered only (others return 404)Until revoked, which takes effect at once. Rotation keeps the old token valid 10 minutes
Read tokenGET read routes of one wallet, and /protected/{walletId}?t=. Refused on POST15 minutes. An opaque string
Partner key/v1/partner/*Until reset or revoked. See Partner access

Envelope

Every JSON answer carries:

FieldValue
asOfUTC time, millisecond precision
schemaVersion"1.1"
chainTip{ slot, blockHash } or null

Errors add { error, detail? }: Errors and codes. Every response has an X-Request-Id header.

Idempotency

  • Idempotency-Key is required on POST /v1/cosign, POST /v1/evm/cosign and POST /v1/x402/cosign, and must equal batchId. On EVM chains, batchId is the authorization nonce (for a SafeTx, the Safe nonce) as 0x and 64 hex characters.
  • Registrations are idempotent by content: the same body returns 200, a different body for the same wallet 409 wallet_exists.

Replays, holds and rebuilds: Refusals and retries.

Limits

LimitValue
Rate120 requests per rolling minute per node on POST /v1/cosign, POST /v1/evm/cosign, POST /v1/wallets, POST /v1/x402/wallets, POST /v1/x402/cosign and POST /v1/x402/fees; partner routes per partner. Over it: 429 rate_limited with Retry-After. Read routes are not rate-limited
Request body64 KiB, else 413
txBodyHex32,768 hex characters
Purchases per request1 to 10 (Hydra: 1)
Assets per wallet1 to 16
ConnectionsOne request per connection, no keep-alive; 30 s socket timeout
Concurrency256 connections, then 503 {"error":"busy"} with no envelope

Measured in production in September to November 2026: Cardano co-sign about 1.3 s typical and under 2.5 s; x402 co-sign about 1 s median.

Endpoints

MethodPathAuthRate-limitedPurposeGuide
POST/v1/walletsNodeYesRegister a Cardano guarded wallet and its mandateWallets
POST/v1/wallets/{walletId}/read-tokenNodeNoMint a 15-minute read token for one walletPartner access
POST/v1/cosignNode + Idempotency-KeyYesCo-sign a Cardano agent spend (layer 1 or Hydra in-head)Co-sign
POST/v1/evm/cosignNode + Idempotency-KeyYesCo-sign a direct payment from a guarded SafeCo-sign a payment
GET/v1/wallets/{walletId}/mandateNode or readNoRead the wallet's mandateMandates
GET/v1/wallets/{walletId}/allowanceNode or readNoRemaining limits and the on-chain ceilingMandates
GET/v1/wallets/{walletId}/boundNode or readNoSigned worst-case statementBound statement
GET/v1/wallets/{walletId}/decisionsNode or readNoList decisions, newest firstVerify
GET/v1/decisions/{decisionId}Node or readNoOne decision with request and proofVerify
GET/v1/wallets/{walletId}/healthNode or readNoQuorum reachability, attestation age, PCR0Trust model
GET/v1/wallets/{walletId}/evidence.zipNode or readNoOffline evidence bundleEvidence bundle
GET/v1/x402/signersNodeNoEnclave addresses and pinned Safe contractsGuarded Safe
POST/v1/x402/walletsNodeYesRegister (and deploy) a guarded Safe, one or several assets on one chainRegister a Safe
POST/v1/x402/cosignNode + Idempotency-KeyYesCo-sign one x402 paymentCo-sign a payment
POST/v1/x402/feesNodeYesSettle fees dueSettle fees
GET/v1/x402/wallets/{walletId}/feesNodeNoFee status, per tokenFee status
GET/v1/partnerPartnerYesPartner profile, nodes, webhookPartner access
POST/v1/partner/signup-linksPartnerYesSigned 30-day sign-up link for a node operatorPartner access
POST/v1/partner/wallets/{walletId}/read-tokenPartnerYesRead token and embed URL for one walletPartner access
GET/v1/journal/rootsNoneNoSigned journal roots by wallet and timeJournal
GET/.well-known/did.jsonNoneNoDID document with the guard-receipt keyGuard receipt
GET/openapi.yaml, /openapi.jsonNoneNoThe OpenAPI documentThis page
GET/healthzNoneNoLiveness: 200 okThis page
GET/readyzNoneNoReadiness: 503 when the quorum is below thresholdThis page

GET /protected/{walletId}?t= serves the embeddable wallet page: Partner access.

Try it

Each endpoint page has a request playground. Its requests go through the docs' server-side proxy, because the API sends no CORS headers. Use a preprod Node Token.

On this page