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. - 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 <n> exceeds maxTicks— On testnet, price must be ≤ 10000.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 matching engine did not return a result within the server’s 5-second timeout window. Critically, this means the operation was not applied — you will not find a new order or cancellation as a result of that request.What to do:- Wait 1–2 seconds.
- Query
POST /infowithuserOrdersto confirm the current state of your orders. - If the order does not exist, retry the request with a fresh nonce.
- If you continue to see timeouts, check the Upside 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 invite 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).