SX Users

Trading

Buy and sell crypto for a user—request a quote, execute it as an order, and track the order by id or in a list.

Buy and sell crypto on a user's behalf in two steps: request a quote for a pair and side, then place an order that executes that quote. Read any order back by its id, or list a wallet's orders to track them.

Authentication: every endpoint on this page accepts your Owner API Key (x-api-key) or a user token (Authorization: Bearer). The wallet in the path must belong to your customer and, with a user token, to that user. Any other wallet answers 404 WALLET_NOT_FOUND, so ids can't be probed across accounts.

Authorization: Bearer YOUR_USER_TOKEN

Every response uses the standard envelope and error shape. Amounts are decimal strings and pairs are always BASE/QUOTE. Both POST endpoints honor x-idempotency-key.


Lifecycle

A quote locks a price for a short window. An order executes exactly one quote.

ObjectStatusMeaning
QuoteOPENPriced and executable until expires_at.
QuoteEXECUTEDAn order already used it. It can't be executed again.
QuoteEXPIREDexpires_at passed before an order used it.
OrderCOMPLETEDThe trade settled. completed_at is set.
OrderPENDING / PROCESSINGAccepted but not settled yet.
OrderFAILEDThe trade didn't execute. status_reason says why.

Placing an order moves its quote to EXECUTED, even when the order ends FAILED. To retry, request a new quote. Most orders settle on execution and come back COMPLETED. An order keeps the status reported when it executed.


Request Quote

POSThttps://api.sandbox.sovera.io/sovx/v1/users/:wallet_id/trading/quotes

Price a trade for a pair and side. Send exactly one of quantity (in the base currency) or amount (in the quote currency). Pass the returned id to Place Order before expires_at. Quotes live for seconds, not minutes, so treat expires_at as the authority.

Path Parameters

ParameterTypeRequiredDescription
wallet_idstring (UUID)YesWallet that trades.

Request Body

FieldTypeRequiredDescription
pairstringYesPair as BASE/QUOTE, e.g. BTC/USD. The compact form (btcusd) is deprecated.
sidestringYesBUY or SELL. Lowercase is deprecated.
quantitystringOne ofBase-currency quantity as a positive decimal string, e.g. "0.50000000".
amountstringOne ofQuote-currency amount as a positive decimal string, e.g. "1000.00".

Send exactly one of quantity or amount; both or neither returns 422 pointing at /amount. JSON numbers are still accepted for quantity and amount but are deprecated.

The quote object

FieldTypeDescription
idstring (UUID)Quote id. Pass it as quote_id when you place the order.
quote_idstring (UUID)Same value as id.
objectstringAlways quote.
statusstringOPEN, EXECUTED, or EXPIRED.
wallet_idstring (UUID)Wallet the quote belongs to.
user_idstring (UUID)Owner of the wallet.
pairstringBASE/QUOTE, e.g. BTC/USD.
base_currencystringBase asset, e.g. BTC.
quote_currencystringQuote asset, e.g. USD.
sidestringBUY or SELL.
quantitystringQuantity in the base currency, at its scale.
amountstringAmount in the quote currency, at its scale.
buy_pricestring | nullPrice in the quote currency. Expect it on BUY quotes; read whichever price isn't null.
sell_pricestring | nullPrice in the quote currency. Expect it on SELL quotes.
feestring | nullFee in the quote currency.
idempotency_keystring | nullThe x-idempotency-key you sent.
created_atstringWhen the quote was priced (UTC).
expires_atstringWhen the quote stops being executable (UTC).
{
  "pair": "BTC/USD",
  "side": "BUY",
  "quantity": "0.50000000"
}

Success Response (201 Created):

{
  "success": true,
  "data": {
    "id": "be27cd3f-3276-523e-a48c-f0661a079e72",
    "quote_id": "be27cd3f-3276-523e-a48c-f0661a079e72",
    "object": "quote",
    "status": "OPEN",
    "wallet_id": "90f904da-dc14-535e-b2db-56be50db02c8",
    "user_id": "43ac9e63-96c4-5f50-b788-dfbc6b265375",
    "pair": "BTC/USD",
    "base_currency": "BTC",
    "quote_currency": "USD",
    "side": "BUY",
    "quantity": "0.50000000",
    "amount": "20000.0000",
    "buy_price": "40000.0000",
    "sell_price": null,
    "fee": "100.0000",
    "idempotency_key": "6f1c2a7e-9b3d-4f5a-8c2e-1d7b9a0e4c33",
    "created_at": "2026-10-12T14:30:00Z",
    "expires_at": "2026-10-12T14:30:15Z"
  },
  "meta": {
    "timestamp": "2026-10-12T14:30:00Z",
    "version": "v1",
    "trace_id": "4bf92f3577b34da6a3ce929d0e0e4736"
  }
}

Validation error (422 Unprocessable Entity), sending both quantity and amount:

{
  "success": false,
  "errors": [
    {
      "code": "VALIDATION_ERROR",
      "message": "Provide exactly one of 'quantity' or 'amount'.",
      "source": { "pointer": "/amount" }
    }
  ],
  "meta": {
    "timestamp": "2026-10-12T14:30:00Z",
    "version": "v1",
    "trace_id": "4bf92f3577b34da6a3ce929d0e0e4736"
  }
}
curl -X POST "https://api.sandbox.sovera.io/sovx/v1/users/{{walletID}}/trading/quotes" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_USER_TOKEN" \
  -H "x-idempotency-key: 6f1c2a7e-9b3d-4f5a-8c2e-1d7b9a0e4c33" \
  -d '{
    "pair": "BTC/USD",
    "side": "BUY",
    "quantity": "0.50000000"
  }'

Errors: 400 the quote can't be priced (BAD_REQUEST) · 401 UNAUTHORIZED · 404 WALLET_NOT_FOUND · 422 VALIDATION_ERROR (source.pointer names the field) · 429 RATE_LIMIT_EXCEEDED · 502 BAD_GATEWAY, pricing unavailable.


Place Order

POSThttps://api.sandbox.sovera.io/sovx/v1/users/:wallet_id/trading/orders

Execute an OPEN quote. Pass its id as quote_id; the order takes the pair and side from the quote, so you don't repeat them. The response carries the order and a Location header pointing at Get Order.

A quote rejected at execution still returns 201, with status: "FAILED" and status_reason.code: "QUOTE_REJECTED". That quote counts as executed: request a new one to retry.

Path Parameters

ParameterTypeRequiredDescription
wallet_idstring (UUID)YesWallet the quote was requested for.

Request Body

FieldTypeRequiredDescription
quote_idstring (UUID)Yesid from Request Quote.
quantitystringNoOverrides the quoted base-currency quantity. Positive decimal string.
amountstringNoOverrides the quoted quote-currency amount. Positive decimal string.

Send at most one of quantity or amount; both returns 422 pointing at /amount. Most orders send quote_id only. JSON numbers are still accepted for the overrides but are deprecated.

The order object

FieldTypeDescription
idstring (UUID)Order id.
order_idstring (UUID)Same value as id. Only on the Place Order response; Get Order and List Orders return id only.
objectstringAlways order.
statusstringPENDING, PROCESSING, COMPLETED, or FAILED.
status_reasonobject | null{ code, message } when the order failed, e.g. QUOTE_REJECTED. See statuses.
quote_idstring (UUID)Quote the order executed.
transaction_idstring (UUID) | nullLedger transaction for the trade in the wallet's history. null for a failed order.
user_idstring (UUID)Owner of the wallet.
wallet_idstring (UUID)Wallet that traded.
customer_idstring | nullYour customer id.
pairstringBASE/QUOTE, e.g. BTC/USD.
base_currencystringBase asset.
quote_currencystringQuote asset.
sidestringBUY or SELL.
quantitystring | nullExecuted quantity in the base currency.
pricestring | nullExecuted price in the quote currency.
amountstring | nullExecuted amount in the quote currency.
feestring | nullFee in the quote currency.
tx_hashnullAlways null: trades settle off-chain.
networknullAlways null: trades settle off-chain.
idempotency_keystring | nullThe x-idempotency-key you sent.
created_atstringCreation time (UTC).
updated_atstringLast change (UTC).
completed_atstring | nullWhen the order reached COMPLETED or FAILED (UTC).
created_bystring | nullActor that created the order.
updated_bystring | nullActor that last changed the order.
{
  "quote_id": "be27cd3f-3276-523e-a48c-f0661a079e72"
}

Success Response (201 Created):

{
  "success": true,
  "data": {
    "id": "168fc813-35b8-5447-89ed-07ec366f33c6",
    "order_id": "168fc813-35b8-5447-89ed-07ec366f33c6",
    "object": "order",
    "status": "COMPLETED",
    "status_reason": null,
    "quote_id": "be27cd3f-3276-523e-a48c-f0661a079e72",
    "transaction_id": "be2fa389-4b35-5c80-a830-2e849e9df31d",
    "user_id": "43ac9e63-96c4-5f50-b788-dfbc6b265375",
    "wallet_id": "90f904da-dc14-535e-b2db-56be50db02c8",
    "customer_id": "corp-redundant-firewall",
    "pair": "BTC/USD",
    "base_currency": "BTC",
    "quote_currency": "USD",
    "side": "BUY",
    "quantity": "0.50000000",
    "price": "40000.0000",
    "amount": "20000.0000",
    "fee": "100.0000",
    "tx_hash": null,
    "network": null,
    "idempotency_key": "9a7c3e1f-5b2d-4c8e-a6f0-1d3b5e7f9a2c",
    "created_at": "2026-10-12T14:30:04Z",
    "updated_at": "2026-10-12T14:30:05Z",
    "completed_at": "2026-10-12T14:30:05Z",
    "created_by": "43ac9e63-96c4-5f50-b788-dfbc6b265375",
    "updated_by": "43ac9e63-96c4-5f50-b788-dfbc6b265375"
  },
  "meta": {
    "timestamp": "2026-10-12T14:30:05Z",
    "version": "v1",
    "trace_id": "4bf92f3577b34da6a3ce929d0e0e4736"
  }
}

Quote rejected at execution (201 Created):

{
  "success": true,
  "data": {
    "id": "5d0c7a91-2f4b-4e6a-9c13-8b7e2f1a0d44",
    "order_id": "5d0c7a91-2f4b-4e6a-9c13-8b7e2f1a0d44",
    "object": "order",
    "status": "FAILED",
    "status_reason": {
      "code": "QUOTE_REJECTED",
      "message": "The quote was rejected at execution. Request a new quote."
    },
    "quote_id": "be27cd3f-3276-523e-a48c-f0661a079e72",
    "transaction_id": null,
    "user_id": "43ac9e63-96c4-5f50-b788-dfbc6b265375",
    "wallet_id": "90f904da-dc14-535e-b2db-56be50db02c8",
    "customer_id": "corp-redundant-firewall",
    "pair": "BTC/USD",
    "base_currency": "BTC",
    "quote_currency": "USD",
    "side": "BUY",
    "quantity": "0.50000000",
    "price": "40000.0000",
    "amount": "20000.0000",
    "fee": "100.0000",
    "tx_hash": null,
    "network": null,
    "idempotency_key": null,
    "created_at": "2026-10-12T14:30:04Z",
    "updated_at": "2026-10-12T14:30:04Z",
    "completed_at": "2026-10-12T14:30:04Z",
    "created_by": "43ac9e63-96c4-5f50-b788-dfbc6b265375",
    "updated_by": "43ac9e63-96c4-5f50-b788-dfbc6b265375"
  },
  "meta": {
    "timestamp": "2026-10-12T14:30:04Z",
    "version": "v1",
    "trace_id": "4bf92f3577b34da6a3ce929d0e0e4736"
  }
}

Expired quote (400 Bad Request):

{
  "success": false,
  "errors": [
    {
      "code": "QUOTE_EXPIRED",
      "message": "The quote expired at 2026-10-12T14:30:15Z. Request a new quote.",
      "source": { "pointer": "/quote_id" }
    }
  ],
  "meta": {
    "timestamp": "2026-10-12T14:31:02Z",
    "version": "v1",
    "trace_id": "4bf92f3577b34da6a3ce929d0e0e4736"
  }
}
curl -X POST "https://api.sandbox.sovera.io/sovx/v1/users/{{walletID}}/trading/orders" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_USER_TOKEN" \
  -H "x-idempotency-key: 9a7c3e1f-5b2d-4c8e-a6f0-1d3b5e7f9a2c" \
  -d '{
    "quote_id": "be27cd3f-3276-523e-a48c-f0661a079e72"
  }'

Errors: 400 QUOTE_EXPIRED (source.pointer /quote_id), or BAD_REQUEST for another rejection at execution · 401 UNAUTHORIZED · 404 WALLET_NOT_FOUND or QUOTE_NOT_FOUND · 409 IDEMPOTENCY_IN_PROGRESS · 422 INVALID_STATE_TRANSITION (quote already executed, source.pointer /quote_id), VALIDATION_ERROR, or IDEMPOTENCY_KEY_REUSED · 429 RATE_LIMIT_EXCEEDED · 502 BAD_GATEWAY, execution unavailable (the quote stays OPEN, so retry it).


Get Order

GEThttps://api.sandbox.sovera.io/sovx/v1/users/:wallet_id/trading/orders/:order_id

Read one order of the wallet. Returns the same order object as Place Order.

Path Parameters

ParameterTypeRequiredDescription
wallet_idstring (UUID)YesWallet that placed the order.
order_idstring (UUID)YesOrder id.
GET https://api.sandbox.sovera.io/sovx/v1/users/{{walletID}}/trading/orders/{{orderID}}

Success Response (200 OK):

{
  "success": true,
  "data": {
    "id": "168fc813-35b8-5447-89ed-07ec366f33c6",
    "object": "order",
    "status": "COMPLETED",
    "status_reason": null,
    "quote_id": "be27cd3f-3276-523e-a48c-f0661a079e72",
    "transaction_id": "be2fa389-4b35-5c80-a830-2e849e9df31d",
    "user_id": "43ac9e63-96c4-5f50-b788-dfbc6b265375",
    "wallet_id": "90f904da-dc14-535e-b2db-56be50db02c8",
    "customer_id": "corp-redundant-firewall",
    "pair": "BTC/USD",
    "base_currency": "BTC",
    "quote_currency": "USD",
    "side": "BUY",
    "quantity": "0.50000000",
    "price": "40000.0000",
    "amount": "20000.0000",
    "fee": "100.0000",
    "tx_hash": null,
    "network": null,
    "idempotency_key": "9a7c3e1f-5b2d-4c8e-a6f0-1d3b5e7f9a2c",
    "created_at": "2026-10-12T14:30:04Z",
    "updated_at": "2026-10-12T14:30:05Z",
    "completed_at": "2026-10-12T14:30:05Z",
    "created_by": "43ac9e63-96c4-5f50-b788-dfbc6b265375",
    "updated_by": "43ac9e63-96c4-5f50-b788-dfbc6b265375"
  },
  "meta": {
    "timestamp": "2026-10-12T14:32:10Z",
    "version": "v1",
    "trace_id": "4bf92f3577b34da6a3ce929d0e0e4736"
  }
}
curl -X GET "https://api.sandbox.sovera.io/sovx/v1/users/{{walletID}}/trading/orders/{{orderID}}" \
  -H "Authorization: Bearer YOUR_USER_TOKEN"

Errors: 401 UNAUTHORIZED · 404 WALLET_NOT_FOUND or ORDER_NOT_FOUND · 429 RATE_LIMIT_EXCEEDED.


List Orders

GEThttps://api.sandbox.sovera.io/sovx/v1/users/:wallet_id/trading/orders

List the wallet's orders, newest first. A wallet without orders returns an empty data array. The list uses cursor pagination and the filter grammar; each item is an order object.

Query Parameters

ParameterTypeRequiredDescription
filter[limit]integerNoPage size. Default 25, maximum 100.
cursorstringNoOpaque token from meta.pagination.navigation. Echo it back unchanged.
filter[order]stringNocreated_at or updated_at, then ASC or DESC. Default created_at DESC.
filter[where][status][eq]stringNoPENDING, PROCESSING, COMPLETED, FAILED, or CANCELLED. Also [inq][].
filter[where][pair][eq]stringNoBASE/QUOTE, e.g. BTC/USD. Also [inq][].
filter[where][idempotency_key][eq]stringNoFinds the order created with that x-idempotency-key.
filter[where][created_at][gte]stringNoUTC date-time ending in Z. Also [lte] and [between][].

Up to six filter conditions per request. Any other field, operator, or filter[skip] returns 422 with source.parameter naming the parameter.

GET https://api.sandbox.sovera.io/sovx/v1/users/{{walletID}}/trading/orders?filter[where][pair][eq]=BTC/USD&filter[where][status][inq][]=PENDING&filter[where][status][inq][]=PROCESSING&filter[limit]=25

Success Response (200 OK):

{
  "success": true,
  "data": [
    {
      "id": "168fc813-35b8-5447-89ed-07ec366f33c6",
      "object": "order",
      "status": "PENDING",
      "status_reason": null,
      "quote_id": "be27cd3f-3276-523e-a48c-f0661a079e72",
      "transaction_id": "be2fa389-4b35-5c80-a830-2e849e9df31d",
      "user_id": "43ac9e63-96c4-5f50-b788-dfbc6b265375",
      "wallet_id": "90f904da-dc14-535e-b2db-56be50db02c8",
      "customer_id": "corp-redundant-firewall",
      "pair": "BTC/USD",
      "base_currency": "BTC",
      "quote_currency": "USD",
      "side": "BUY",
      "quantity": "0.50000000",
      "price": "40000.0000",
      "amount": "20000.0000",
      "fee": "100.0000",
      "tx_hash": null,
      "network": null,
      "idempotency_key": "9a7c3e1f-5b2d-4c8e-a6f0-1d3b5e7f9a2c",
      "created_at": "2026-10-12T14:30:04Z",
      "updated_at": "2026-10-12T14:30:04Z",
      "completed_at": null,
      "created_by": "43ac9e63-96c4-5f50-b788-dfbc6b265375",
      "updated_by": "43ac9e63-96c4-5f50-b788-dfbc6b265375"
    }
  ],
  "meta": {
    "timestamp": "2026-10-12T14:35:00Z",
    "version": "v1",
    "trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
    "pagination": {
      "records": { "limit": 25, "has_next": false, "has_previous": false },
      "navigation": { "next": null, "previous": null }
    }
  }
}

When more orders exist, has_next is true and navigation.next holds the path for the next page, with your filters and a cursor.

curl -G "https://api.sandbox.sovera.io/sovx/v1/users/{{walletID}}/trading/orders" \
  -H "Authorization: Bearer YOUR_USER_TOKEN" \
  --data-urlencode "filter[where][pair][eq]=BTC/USD" \
  --data-urlencode "filter[limit]=25"

Errors: 401 UNAUTHORIZED · 404 WALLET_NOT_FOUND · 422 VALIDATION_ERROR (source.parameter names the filter) · 429 RATE_LIMIT_EXCEEDED.

On this page