Skip to main content
UpsideMAX returns errors at two levels: HTTP-level errors that appear in the top-level 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 contains status: "error", a machine-readable code, and a human-readable message.

Business-Level Errors

These errors appear inside response.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

This is the most common error when integrating for the first time. Work through this checklist:
  1. 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.
  2. 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. approveAgent in particular must carry agentName ("" when unset) and validUntil (0 for 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.
  3. 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 different actionHash.
  4. 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 Agent actionHash, but a 32-byte uint64 field in a typed struct — mixing these up is a common cause.
  5. No double-hashing — The EIP-712 digest is already the final hash. Pass the 32-byte digest directly to the signing function (prehash = false); do not hash again.
  6. Correct v value — Ensure v = sig.v if sig.v >= 27 else sig.v + 27. Some libraries return v as 0 or 1; you must add 27.
  7. Right private key — The SIGNATURE_INVALID message 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.
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; read maxTicks and tickSize from configs.
  • signer has no registered account — You need to call registerAccount first.
  • orderId not found — The oid you tried to cancel doesn’t exist or was already filled.
Always iterate over the entire statuses array when placing batch orders — some items in the batch may succeed while others fail.
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:
  1. Wait 1–2 seconds.
  2. Query POST /info with userOrders — and orderHistory if the order may already have terminated — to establish the actual state.
  3. Only if the order is genuinely absent, retry with a fresh nonce.
  4. If you continue to see timeouts, check the UpsideMAX status page or contact support with your requestId.
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.
Some environments require a valid alpha test invitation code to register. Make sure you:
  1. Place the inviteCode field at the top level of the envelope — not inside the action object.
  2. Do not include inviteCode inside the signed message (it is outside action).
  3. Check whether the code was already used (ALREADY_USED) or is simply wrong/expired (NOT_FOUND).
Contact the UpsideMAX team to obtain a valid alpha test invitation code for restricted environments.