status: "error" response, and business-level errors that appear inside response.data.statuses[] even when status is "ok". Both levels are documented here.
HTTP-Level Error Codes
These errors are returned with a non-200 HTTP status code when the server rejects the request before or during processing. The response body containsstatus: "error", a machine-readable code, and a human-readable message.
Business-Level Errors
These errors appear insideresponse.data.statuses[] when the request envelope is valid and authenticated, but the matching engine or risk engine rejects one or more operations within the batch. The outer status is "ok" and the HTTP status is 200.
Troubleshooting
I keep getting SIGNATURE_INVALID
I keep getting SIGNATURE_INVALID
This is the most common error when integrating for the first time. Work through this checklist:
- Right signing path — Funds/permission actions (
registerAccount,approveAgent,revokeAgent,lockCollateral,unlockCollateral,transferBetweenDeployers) use the EIP-712 typed struct; everything else uses the Agent path. Signing an action via the wrong path always fails. See Authentication. - Typed path — include every struct field in the wire JSON — For a typed action, every field the struct declares must be present in the request JSON, even the business-optional ones.
approveAgentin particular must carryagentName(""when unset) andvalidUntil(0for no expiry); if you omit them, the server reads the JSON as-sent and computes a different digest than the one you signed, so recovery fails. Inject the defaults into the action before signing. See Authentication. - Canonical JSON (Agent path) — Keys must be sorted alphabetically with compact separators and no whitespace:
json.dumps(action, sort_keys=True, separators=(",", ":")). A single extra space produces a differentactionHash. - Correct domain & nonce encoding — Use the fixed domain (
name="Exchange",version="1",chainId=9767,verifyingContract=0x0). The nonce is a big-endian 8-byte suffix inside the AgentactionHash, but a 32-byteuint64field in a typed struct — mixing these up is a common cause. - No double-hashing — The EIP-712
digestis already the final hash. Pass the 32-byte digest directly to the signing function (prehash = false); do not hash again. - Correct
vvalue — Ensurev = sig.v if sig.v >= 27 else sig.v + 27. Some libraries returnvas 0 or 1; you must add 27. - Right private key — The
SIGNATURE_INVALIDmessage includes the recovered address. If it doesn’t match your expected address, you are signing with a different private key than the one whose address you registered.
My order returns status ok but has an error in statuses
My order returns status ok but has an error in statuses
This is a business-level rejection, not an HTTP error. The request was correctly signed and delivered to the matching engine, but the engine rejected the order.Check
response.data.statuses[0].error for the rejection reason. Common causes:size must be positive— You passed"s": "0"or a negative string.price exceeds tick range (maxTicks x tickSize)— The price is outside the contract’s permitted tick range; readmaxTicksandtickSizefromconfigs.signer has no registered account— You need to callregisterAccountfirst.orderId not found— Theoidyou tried to cancel doesn’t exist or was already filled.
statuses array when placing batch orders — some items in the batch may succeed while others fail.I get DOWNSTREAM_TIMEOUT
I get DOWNSTREAM_TIMEOUT
A
DOWNSTREAM_TIMEOUT (HTTP 504) means the backend chain node did not return a result within the server’s 5-second window. The request’s outcome is unknown — reconcile before retrying rather than assuming it was dropped.What to do:- Wait 1–2 seconds.
- Query
POST /infowithuserOrders— andorderHistoryif the order may already have terminated — to establish the actual state. - Only if the order is genuinely absent, retry with a fresh nonce.
- If you continue to see timeouts, check the UpsideMAX status page or contact support with your
requestId.
registerAccount fails with ACCOUNT_ALREADY_EXISTS
registerAccount fails with ACCOUNT_ALREADY_EXISTS
This means the address has already been registered in this environment. You do not need to register again — proceed directly to placing orders.If you are generating a new keypair each time in your test scripts, each new address will need its own
registerAccount call. Consider persisting your test wallet’s private key between runs.registerAccount fails with INVITE_CODE_INVALID
registerAccount fails with INVITE_CODE_INVALID
Some environments require a valid alpha test invitation code to register. Make sure you:
- Place the
inviteCodefield at the top level of the envelope — not inside theactionobject. - Do not include
inviteCodeinside the signed message (it is outsideaction). - Check whether the code was already used (
ALREADY_USED) or is simply wrong/expired (NOT_FOUND).
