Behaviour of the hub, or of the stack around it, that you would not expect from the rest of this reference. Each entry says what happens and what to do. Route pages link here where it matters. Contents:

Submitting orders

A POST /order/openfor cut during its forward locks the quote (EIN0052)

  • What happens.
    1. The hub forwards the order upstream on the incoming call’s request context.
    2. If that call is cut while the forward is in flight, the upstream call is cancelled.
    3. The forward reservation stays pending, with its outcome unknown.
    4. From then on every re-post answers EIN0052, until an operator reconciles the reservation. Reading the order by its hubOrderId answers EIN0009 meanwhile.
    A cut before the forward starts is harmless: the re-post forwards afresh. The hub’s caller is the gateway. It keeps its call to the hub running when your client times out or disconnects, so your client giving up does not cut the forward. It does cut the call at its own limit, 10 s on a submission, and answers EPX0052 (504); the hub’s own upstream budget is 30 s, so a forward still in flight at 10 s is cancelled that way.
  • What to do.
    • Treat EPX0052 on a submission as a lost answer with an unknown outcome: read the status by hubOrderId, then re-post the same body (Handling errors — a lost answer). The re-post answers the original ack if the order was recorded, a fresh ack if nothing had been forwarded, and EIN0052 if the forward was cut in flight.
    • Give openFor a client timeout longer than the gateway’s 10 s, so that you get the gateway’s answer rather than none. The SDK waits 15 s on submissions by default, and 35 s through a partner proxy; don’t lower it.
    • If a quote is stuck on EIN0052, an operator has to reconcile its forward reservation: report it with the request_id.

Proxy-lane registration is refused after expiresAt, and the deposit completes unregistered

  • What happens.
    • The hub keeps a proxy-lane quote (oif-wrap-native, oif-swap-token) registrable for 20 minutes after issue.
    • The aggregator, however, refuses a registration once the quote’s expiresAt has passed (about 30 s). The hub answers EIN0007 with reference fail-closed rejected: upstream refused: http 400 (QUOTE_EXPIRED).
    • The user’s deposit is not lost: the solver fills and settles it on chain anyway. But the hub never records the order, so it is missing from GET /orders and from the hub’s status routes.
    • Past the hub’s own 20-minute window the answer is EIN0005.
  • What to do.

A proxy-lane quote can be registered without its deposit

  • What happens. openFor on a proxy-lane quote whose transaction was never sent is acked, with state created. The order then stays created upstream. Neither the hub nor the aggregator checks that the deposit exists.
  • What to do.
    • Register only after the transaction is sent.
    • Don’t treat a created ack as proof of the deposit. The open fact on GET /onchain/{orderId}/fill is the proof.

POST /order refuses OIF-lane quotes

  • What happens. POST /order registers create-flow winners only. On a deployment whose corridors run through the OIF aggregator, every quote sent to POST /order answers EIN0007 fail-closed rejected at the hub’s re-approval step, before the artifact, signer and signature checks.
  • Why it rarely matters. OIF lanes complete through POST /order/openfor.
  • What to do. Send a quote to POST /order only when its lane is the open flow (the SDK’s quote.lane.kind is "open-flow").

Re-posting a declined order answers EIN0050

  • What happens.
    • A signed-lane order declined by the solver answers EIN0021, and nothing is opened.
    • Re-posting the same body gets a 502 from the aggregator, which the hub surfaces as EIN0050 (upstream unavailable: http 502).
    • The hub then treats that forward as outcome-unknown.
  • What to do. Don’t re-post a declined quote. Re-quote and sign again.

Following an order

Upstream status can stop at executed

  • What happens. An EVM gasless order that filled and settled on chain stayed executed in GET /order/{orderId}/status for a long time. Syncs were fresh, upstreamStale was false, and there was no fillTransaction. settled was never emitted. Solana-origin orders did reach finalized.
  • What to do.
    • Don’t wait forever for a terminal upstream state.
    • Once the order is executed, read GET /onchain/{orderId}/fill. Its filled and settled facts are the chain’s answer.
    • Give the polling loop a stall rule, for example: hand off after a few minutes without progress.
    • The SDK’s trackOrder, which executeQuote uses, reads the chain facts on every round and ends on them (Tracking). The chain facts are open to your project id too, so a page follows such orders itself.

The hub’s own /status view does not progress for openFor orders

  • What happens.
    • GET /status/{orderId} shows the intent as CREATED and every other domain empty, even after the order filled and settled on chain.
    • Orders of execution class PROVIDER_NATIVE_UNCOVERED, which covers every lane openFor accepts on current deployments, have no admissible domain transitions after creation, so this view cannot move.
    • Its watermarks are per chain, and move only when the reconciler processes a new observation on that chain. On a quiet chain they can be far behind the observer watermarks of the on-chain views.
  • What to do. Follow openFor orders with the upstream status and the on-chain views. Use /status only for the intent record.

On-chain views

On-chain ids are not validated

  • What happens.
    • GET /onchain/{orderId}/fill accepts any id. A miscased, unprefixed or unknown id answers 200 with no facts and a watermark for every chain.
    • That answer can’t be told apart from “not filled yet”, so the withdraw rule would offer a withdraw for an order that is in fact filled and settled.
    • GET /onchain/{orderId}/order answers EIN0009 for such ids.
  • What to do.
    • Pass onchainOrderId exactly as the hub serves it (0x + 64 lowercase hex), and check the format before calling.
    • Before offering a withdraw, confirm with GET /onchain/{orderId}/order that the order exists.

A Solana Open signature does not resolve by transaction

No escrow tuple for non-EVM origins

  • What happens. GET /onchain/{orderId}/order answers EIN0009 permanently for a non-EVM-origin order, even when its Open, fill and settle are all observed. The withdraw steps in Refunds need that tuple, so they work for EVM-origin orders only.
  • What to do. Refund a Solana-origin order through GET /onchain/{orderId}/refund: the hub builds the unsigned transaction for the order’s user to sign and send (SDK — Refunds).

Quoting

Preview answers EIN0050 when there is no offer

  • What happens.
    • POST /quote/preview answers EIN0050 (upstream unavailable, retryable) instead of 200 with an empty offers whenever a provider refuses the request.
    • The cases seen: an amount below the provider’s minimum, an exact-output request above maxAmountIn, and a Solana source without sourceAccount.
    • Preview reports any provider error this way.
  • What to do.
    • Read a preview EIN0050 as “no offer right now” and don’t retry it in a loop.
    • Check the amount and sourceAccount first.
    • POST /quote gives the reason: EIN0008 with a reference.

SDK

The SDK needs a secure context in the browser

  • What happens. A page served over plain http from anywhere other than localhost has no crypto.subtle. The SDK needs it in the browser for a prepared quote’s fresh preparationId, the Solana pre-signing checks, and the lost-answer recovery (deriveHubOrderId). Those calls throw an Error saying Web Crypto is not available.
  • What to do. Serve the page over https, or from localhost.