signPayload example is built from. Each step
below pairs the exact curl from the linked route page with the exact JSON it answers. For the
concepts behind each step, start at API reference and
Concepts.
Before you start
Check these first:- You have a secret API key (
c8n_sk_…), made for your project in the hub dashboard, in theHUB_API_KEYvariable of your shell. Every call below sends it inx-api-key: there is no sign-in and no session (Authentication). - The paying wallet holds the source token (WETH here, at least
amount) and has approved it to Permit2 (0x000000000022D473030F116dDEE9F6B43aC78BA3, theverifyingContractof Step 2’ssignPayload). The hub checks neither: it quotes and forwards, and the solver then declines the signed order at Step 3 withEIN0021, referencehttp 422 (SOLVER_REJECTED). Nothing is opened or spent. - The quote names the paying wallet in
sourceAccount. Without it, as in Step 2, therecipientis quoted as the payer:witness.userand the payload’spayerare the recipient. A different wallet can still sign; the order then opens on the signer’s tokens, but the recipient becomes the order’s user, which is also who a refund pays. Step 2 omitssourceAccountonly because its signer is the recipient.
Base URL.
https://proxy-api.infinimesh.net/v1: the public test hub (test networks only),
which every call below uses; your production address comes with your integration access.POST sends a JSON body with its content type
(Conventions — request headers):
Nothing else: the gateway sets the headers the hub itself needs. Each answer’s
request_id (also in
the X-Request-Id header) is the gateway’s id for the call; keep it for support. The hub requires
the subject on the seven routes that read it, and keeps each subject’s quotes and orders apart:
send the same one for a quote, its order and its status
(Authentication — your users).
How the ids tie together, step to step:
Steps
1
Configure: your key, then the catalog
Make a secret API key in the
hub dashboard, and put it in your shell without
leaving it in the history. It is the only credential these calls need.
GET /catalog — build pickers from this, never a hand-kept table (full reference):2
Quote
POST /quote (full reference):executionTx or swapInput (this lane discloses neither); no auction (a firm quote, not a
decaying one).The deadlines inside the payloads (
deadline, expires, orderExpiresAt,
validUntil) fall in the year 2100 because this sample is built from a test fixture; the hub
refuses an orderExpiresAt more than 24 h ahead. A live quote carries orderExpiresAt and
witness.expires about 1 800 s after issuedAt. Neither extends the quote’s own expiresAt.A winner discloses at most one of
signPayload and executionTx — this walkthrough
is the signed lane. For the proxy lanes, the open flow, and what each one hands you:
Step execution.3
Execute: sign, then submit
Sign the disclosed
signPayload with eth_signTypedData_v4, verbatim — never rebuild it — after
checking it, then prefix the raw signature with the 0x00 scheme byte. With the SDK,
executeQuote runs this whole step, checks included
(SDK quickstart); its helpers do the parts:POST /order/openfor (full reference):state is the upstream’s initial state, not a fill guarantee.Declined?
EIN0021 means the solver refused the signed order and nothing was opened: re-quote
and sign again. Never re-post the declined body — the repeat answers EIN0050 and then locks the
quote on EIN0052.Expired?
EIN0005 on this call is normal flow — the quote’s ~30 s window passed;
re-quote and re-sign, don’t retry the same signature.Lost the answer?
hubOrderId is derivable from quoteId alone
(hex(sha256("infinity:v1:order:" + quoteId))) — read the status by that alias before re-posting.
Handling errors. The
gateway answers EPX0052 (504) when a submission takes longer than 10 s: that is a lost answer too,
with an unknown outcome. The gateway keeps a submission running if your client disconnects, but cuts
it at those 10 s, and a forward cut in flight leaves the quote answering EIN0052 until an operator
reconciles it (known issue). Give this call
a client timeout longer than 10 s, so that you get the gateway’s answer.4
Monitor
GET /order/{orderId}/status — the upstream’s own view of the order
(full reference):GET /onchain/tx/{chainDomain}/{txHash}/order — resolve the reported fill transaction into
what the hub’s chain observers actually saw (full reference):The upstream view above is advisory; this one is observed — show money to a user from
here, not from Step 4’s first call. Its
onchainOrderId is Step 3’s orderId: on this lane the
ack already carries the on-chain id, and GET /orders lists it as
onchainOrderId from submission. The Permit2 quote in Step 2 discloses none. Once the Open is
observed, watermarks covers only the Open’s output chain, here eip155-56.5
Optimize
No new call — three habits that keep you comfortably under the rate limit
(Handling rate limits) and off the wallet-prompt-for-nothing
path:
- Fetch
GET /catalogonce and cache it; it changes only when the deployment restarts. - Browse with
POST /quote/preview(indicative, no cost beyond your organization’s shared quote bucket) and debounce it while a wallet prompt is open; callPOST /quote/prepareonce, on confirmation (Step execution — preview, then prepare). - Prefer
@c8ntinuum/infinity-interop-sdkover hand-rolledfetch— it sends your key on every call, waits longer than the gateway before giving up, and readsHubError.retryableandretryAfterMs.
Status lifecycle
The three status views answer different questions and lag differently:GET /order/{orderId}/status is the upstream’s own advisory report;
GET /status/{orderId} is the hub’s own event-derived projection (open-flow
orders only have this one); GET /onchain/{orderId}/fill is what the hub’s
chain observers actually saw, and is the only one of the three that proves anything. Poll the first
by orderId (or the derivable hubOrderId) every 2–3 s; stop at finalized, failed or
refunded, and from executed on read the third as well: the upstream can stop reporting there
(known issue). Full detail, the id-to-view table, and the
terminal states per view:
Order lifecycle.
From a web page
The same flow runs in a browser with your public project id instead of the key: sendx-project-id (and Content-Type on a POST) in place of x-api-key, from an origin your project
lists. Every step works as above, the on-chain views included. Only the order history,
GET /orders, needs the key: a page keeps the ids of the orders
it submits, and reads the history through your backend
(Authentication — project ids).
See also
- Step execution — the lanes this walkthrough didn’t take
- Order lifecycle — the three status views, in full
- Troubleshooting — symptom → cause → fix, by phase
- SDK: SDK quickstart — the same flow as one TypeScript program
- Authentication — the secret key and the project id