AXIS Docs

DevelopersAXIS API

REST API

The AXIS API is a hosted HTTP service that serves quotes, depth, candles, tickers, orders and trade history for AXIS.

Base URLs#

Network REST WebSocket
Testnet https://demo-api.axis.markets wss://demo-api.axis.markets/ws
Mainnet Not available yet Not available yet

Every endpoint is a GET request relative to the base URL. The push API is described in WebSocket API. Contract addresses and token contracts per network are in Networks and deployments.

The AXIS API and the indexer#

The AXIS API embeds the open-source indexer and adds routing and market data on top of it. The order, account and history endpoints come from the indexer, so you can serve them yourself by running the indexer with apiPort. Quotes, depth, candles, the 24h ticker and the WebSocket API exist only in the hosted service.

Endpoint AXIS API Self-hosted indexer
GET /quote Yes No
GET /depth Yes No
GET /candles Yes No
GET /ticker/24h Yes No
GET /contract Yes Yes
GET /markets Yes Yes
GET /order/:id Yes Yes
GET /order Yes Yes
GET /account/:address Yes Yes
GET /backing Yes Yes
GET /order-history Yes Yes
GET /trades Yes Yes
GET /failures Yes Yes
WebSocket /ws Yes No

The API is not a Horizon drop-in. It has its own paths and response shapes: /depth replaces /order_book, /quote replaces /paths/strict-send and /paths/strict-receive, and /candles replaces /trade_aggregations. The full mapping is in Migrating from the Classic DEX.

Conventions#

Requests and responses#

  • Responses are JSON (Content-Type: application/json). CORS is open (Access-Control-Allow-Origin: *), so a browser app can call the API directly.
  • Add pretty_print to any query string (?pretty_print) to get indented JSON.
  • There is no authentication. The Testnet service publishes no rate limits and gives no availability guarantee. Cache what you can and retry failed requests with a backoff.

Errors#

A failed request returns an HTTP error status and a JSON body with the same status:

{
  "error": "Bad request. Invalid parameter: \"amount\". Invalid asset amount: 1.5",
  "status": 400
}
Status When
400 A parameter is missing or invalid. The message usually names it, Invalid parameter: "<name>"., using source_asset and destination_asset for the quote assets and owner for /account/:address. A quote with the same asset on both sides answers Invalid parameter: "buyingAsset". Buying asset can't be the same as selling asset. /candles with to not after from answers Bad request. Parameter "to" should be larger than "from".
404 The order is not live, or the backing record is not tracked
409 /quote while the service is not ready (Trading error. Server currently is not ready to quote prices.) or when routing failed (Trading error. <message>)
500 Internal error: Internal server error

An unknown path returns 404 with the plain-text body API endpoint was not found, not JSON.

Numbers, amounts and prices#

  • Integers that may not fit a JSON number are strings: order IDs, amounts, prices, balances, allowances, trade IDs and cursors. Parse them with BigInt().
  • Amounts in orders, trades, quotes and backing records are integer base units of the token. For a 7-decimal asset 1 token is 10000000 base units (stroops), so "10000000" XLM is 1 XLM.
  • Order price and quote worstPrice are contract prices in the maker's terms: the order's buying base units per 1 selling base unit, times 10^18, as integer strings. For a quote hop, worstPrice is units of the hop's selling asset per 1 unit of its buying asset. The "4533027867695422232" of an XLM to USDC hop means 4.533 XLM per USDC, which is also the token price when both assets have 7 decimals. See Prices and rounding.
  • rprice (orders) and price (trades and swaps) are floating-point approximations for display. Never compute with them.
  • The market data endpoints /depth, /candles and /ticker/24h return decimal strings in token units, with prices in quote asset per base asset. They convert with 7 decimals, which covers every Testnet asset.

Assets#

  • Input. /quote and the market parameter of /depth and /candles accept XLM (also xlm or native), CODE:ISSUER, CODE-ISSUER or a token contract address (C...). The asset and pair filters of the order and history endpoints accept contract addresses only.
  • Output. Every asset in a response is a token contract address. A Classic asset appears as the address of its Stellar Asset Contract (SAC). The Testnet addresses are listed in Networks and deployments.
  • Market keys. Markets use the contract's canonical pair order base/quote: the base asset is the first of the pair, comparing the XDR bytes of the addresses, not their strings. On Testnet EURC (CCUU...) comes before CETES (CC72...). /ticker/24h, /markets and /contract report pairs as base/quote in that order, while the pair filters accept either order. /depth and /candles answer in the orientation you request. Take the pair order from the API or from canonicalPair in the JS client instead of sorting strings.

Timestamps#

Format Example Used by
YYYY-MM-DD HH:MM:SS, UTC "2026-10-03 13:22:22" Order created, updated and expires, trade, swap and failure timestamp, backing updated and skipped, market created and refreshed
UNIX seconds, number 1791033489 timestamp of /depth and /ticker/24h, candle times, the from and to parameters of /candles
ISO 8601, UTC "2026-10-03T13:02:57Z" ts of GET /
Ledger sequence, number 5001797 ledger, liveUntil

The JS client exports parseApiDate, which turns the first format into UNIX milliseconds.

Pagination#

List endpoints take a limit and an exclusive cursor. To get the next page, pass the cursor field of the last row you received: rows up to and including it are skipped. A missing, invalid or non-positive limit falls back to the default, and a larger one is capped at the maximum without an error.

Endpoint Sort order Cursor Default limit Max limit
GET /markets Canonical pair order cursor field, <base>-<quote> 20 1000
GET /order Oldest first, by creation cursor field 20 200
GET /order-history Newest first, by creation cursor field 20 500
GET /trades Newest first cursor field, equal to id 20 500
GET /failures Newest first cursor field, equal to id 20 500

An order cursor is the position of the event that created the order, not the order ID. Order IDs are hashes and cannot be used for paging. There is no order parameter on these endpoints.

Status#

GET /#

Service status with 24-hour activity totals. No parameters.

Field Type Description
status string loading while the orderbook is empty, for example during startup. active otherwise.
ts string Server time, ISO 8601 UTC
ledger number Last ledger processed. Only when active.
frozen boolean Whether the safety admin froze the contract. Only when active.
trades number Fills in the last 24 hours across all markets. Only when active.
volumes array Per token: symbol, quoteVolume (tokens traded in 24 hours, summed over every market) and volume (indicative USD value of that amount, from fixed reference prices). Only when active.
curl "https://demo-api.axis.markets/?pretty_print"
{
  "status": "active",
  "ts": "2026-10-03T13:02:57Z",
  "ledger": 5001797,
  "frozen": false,
  "trades": 7407,
  "volumes": [
    {
      "symbol": "XLM",
      "volume": "337.8988296",
      "quoteVolume": "1535.9037711"
    },
    {
      "symbol": "USDC",
      "volume": "176.8586151",
      "quoteVolume": "176.8586151"
    }
  ]
}

Notes:

  • trades and volumes are display statistics for the Testnet demo. Use GET /ticker/24h for per-market numbers.
  • A self-hosted indexer answers / with a different body. See Indexer.

Quotes#

GET /quote#

Finds the best routes to sell or buy an amount and returns, for every hop, the order IDs to list in the contract call. Routes cross AXIS orders only, with up to 3 hops and at most 20 orders per route.

Parameter Type Default Description
sellingAsset asset required Asset the trader pays. Aliases selling_asset, source_asset.
buyingAsset asset required Asset the trader receives. Aliases buying_asset, destination_asset.
amount integer required Positive integer in base units, decimals are rejected. With strict_send the amount to sell, with strict_receive the amount to buy. Aliases source_amount, destination_amount.
direction string strict_send strict_send (exact input) or strict_receive (exact output)
direct boolean false true or 1 limits routing to the direct market of the two assets (one hop)
maxPrice integer none Requires direct. The highest maker price to cross, as a contract price (18 decimals) in the units of worstPrice: sellingAsset per 1 unit of buyingAsset. Quotes the crossing of a limit order: orders priced above it are left out, and the route may trade less than amount. Alias max_price.
Field Type Description
id string Quote ID, informational
status string success, unfeasible or rejected
direction string Direction used
sellingAsset, buyingAsset string Token contract addresses
ledger number Ledger of the orderbook the quote was computed on
paths array Up to 10 alternative routes, best first. Empty unless success.
paths[].sold string Amount the trader pays, base units
paths[].bought string Amount the trader receives, base units
paths[].path array Hops in execution order
paths[].path[].selling string Asset paid at this hop
paths[].path[].buying string Asset received at this hop
paths[].path[].orders string array Maker order IDs to list for this hop, in matching order
paths[].path[].worstPrice string Highest maker price among the listed orders (maker buying per selling, 18 decimals). A limit at this price crosses every listed order.
error string Reason, when status is not success

Best first means the largest bought for strict_send and the smallest sold for strict_receive.

Sell 1 XLM for USDC:

curl "https://demo-api.axis.markets/quote?sellingAsset=XLM&buyingAsset=CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA&amount=10000000&pretty_print"

The response had five routes. The first two are shown: the direct market, then a route through CETES.

{
  "id": "11SeGAvxf58UkqTUmFqYVug4kFP1C5b",
  "status": "success",
  "direction": "strict_send",
  "sellingAsset": "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC",
  "buyingAsset": "CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA",
  "ledger": 5002005,
  "paths": [
    {
      "sold": "9999997",
      "bought": "2214341",
      "path": [
        {
          "selling": "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC",
          "buying": "CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA",
          "orders": [
            "137718931818025766751180795007231811965",
            "184698105807936084996517827088767859297",
            "299866619951502789575135247958256408905"
          ],
          "worstPrice": "4533027867695422232"
        }
      ]
    },
    {
      "sold": "10000000",
      "bought": "2155581",
      "path": [
        {
          "selling": "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC",
          "buying": "CC72F57YTPX76HAA64JQOEGHQAPSADQWSY5DWVBR66JINPFDLNCQYHIC",
          "orders": [
            "175245839230035109306050965350899990272",
            "89852153929209626508254613737130759476",
            "232378621713006620607546476115974255717"
          ],
          "worstPrice": "306278225835597445"
        },
        {
          "selling": "CC72F57YTPX76HAA64JQOEGHQAPSADQWSY5DWVBR66JINPFDLNCQYHIC",
          "buying": "CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA",
          "orders": [
            "313816668188901862683843128148848998865",
            "129296712244998878869388841874484106102",
            "114712043550087556363802578784900576007"
          ],
          "worstPrice": "15385141000000000000"
        }
      ]
    }
  ]
}

Buy exactly 0.1 USDC with XLM on the direct market:

curl "https://demo-api.axis.markets/quote?sellingAsset=XLM&buyingAsset=CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA&amount=1000000&direction=strict_receive&direct=true&pretty_print"
{
  "id": "11SeGB56R1VGqHNnQr4AB4ruhZcTjWy",
  "status": "success",
  "direction": "strict_receive",
  "sellingAsset": "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC",
  "buyingAsset": "CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA",
  "ledger": 5002015,
  "paths": [
    {
      "sold": "4505409",
      "bought": "1000000",
      "path": [
        {
          "selling": "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC",
          "buying": "CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA",
          "orders": [
            "137718931818025766751180795007231811965",
            "184698105807936084996517827088767859297"
          ],
          "worstPrice": "4515608426305947824"
        }
      ]
    }
  ]
}

An amount the book cannot fill returns HTTP 200 with unfeasible:

{
  "id": "11SeGB58Ds24A7Zr7LyyZ5WvdV9qDrK",
  "status": "unfeasible",
  "direction": "strict_send",
  "sellingAsset": "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC",
  "buyingAsset": "CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA",
  "ledger": 5002016,
  "paths": [],
  "error": "Not enough liquidity on the DEX."
}

Notes:

  • The quote mirrors contract settlement. It admits a fill only when the maker's remaining backing covers all of it, and skips a partially backed order otherwise (see Effective depth). It rounds like the contract (the taker's output down, the cost up) and leaves out orders the contract would skip: makers without backing, makers that cannot receive the asset you pay, makers whose trustline has no room for the payment (which would fail the whole call), orders close to expiration, dust orders and makers the contract skipped recently. Multi-hop routes, executed as a strict swap, also leave out makers whose backing record still awaits confirmation.
  • unfeasible means no route fills the whole amount with backed liquidity within 20 orders. With maxPrice, it means that no backed order is priced within the limit.
  • With maxPrice, the quote is the crossing of a limit order rather than a swap: one hop over the orders priced up to the limit, best first, at most 20 of them. A partial fill is a valid result, so sold and bought can be well below amount. The rest of the limit order goes on the book. For a limit sell at contract price p, pass maxPrice = floor(10^36 / p). For a limit buy, pass p itself. These are the thresholds the contract compares maker prices with.
  • With strict_send, sold can be slightly below amount. Input worth less than one base unit of the output at the route's prices stays with the trader. Above, the direct route uses 9999997 of the 10000000 stroops.
  • direction accepts strict_receive as the only alternative. Any other value, including a typo, silently becomes strict_send.
  • While the contract is frozen, every quote returns status: "rejected", empty paths and the error Trading is suspended: the AXIS contract is frozen.
  • A quote whose buyingAsset requires issuer authorization the AXIS contract does not have is rejected too, with an error that explains it. The makers' assets pass through the contract, so buying such an asset fails with IntermediaryCannotReceive (712) until the issuer authorizes the contract. No route buys such an asset at an intermediate hop either.
  • HTTP 409 means the service is not ready, for example while its orderbook is still empty after a restart, or that routing failed. While the service is not ready, every /quote call returns 409, even an invalid one. Retry later.
  • Routes are alternatives computed independently and can share orders. Use one route per transaction.
  • A quote reserves nothing. Orders can be filled, changed or removed before your transaction lands, and the contract skips the ones that are gone. Re-quote right before you ask for a signature. See Using a quote in a contract call.

Market data#

GET /depth#

Aggregated orderbook of one market around the mid price, counting only backed amounts.

Parameter Type Default Description
market string required BASE/QUOTE, each side in any asset format. The book is returned in this orientation.
depth number 20 Band around the mid price in percent, greater than 0 and at most 100
step decimal automatic Price step of the levels, for example 0.001. Positive, at most 18 fractional digits. By default 5 significant digits of the mid price.
limit integer 100 Levels per side, 1 to 500
Field Type Description
ledger number Ledger of the orderbook state
timestamp number Server time, UNIX seconds
step string or null Step used. null when the book is empty and no step was requested.
bestBid, bestAsk string or null Best prices before rounding to levels, 8 significant digits
bids array [price, quantity] levels, highest price first
asks array [price, quantity] levels, lowest price first

Prices are in quote asset per base asset and quantities in base asset tokens, both decimal strings.

curl "https://demo-api.axis.markets/depth?market=XLM/CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA&limit=3&pretty_print"
{
  "ledger": 5002320,
  "timestamp": 1791035191,
  "step": "0.00001",
  "bestBid": "0.22259541",
  "bestAsk": "0.22630216",
  "bids": [
    [
      "0.22259",
      "0.3322822"
    ],
    [
      "0.22108",
      "0.3362188"
    ],
    [
      "0.21885",
      "0.11365"
    ]
  ],
  "asks": [
    [
      "0.22631",
      "0.5910125"
    ],
    [
      "0.22682",
      "0.5362911"
    ],
    [
      "0.22689",
      "0.8402956"
    ]
  ]
}

Notes:

  • Levels are conservative. A bid is rounded down and an ask up to its level, so a limit order at a level price crosses every order in that level. With step=0.05, a bid at 0.33333 shows at 0.3 and an ask at 0.342 at 0.35.
  • Only backed amounts count. A maker's budget, min(balance, allowance) in the token they sell, is shared by their orders in price order within the market. Orders the contract would skip are left out here too. Unlike a quote, depth does not check the maker's trustline room for the payment or whether the AXIS contract can hold the asset, so a quote can list fewer orders than depth shows.
  • AXIS does not match on-chain, so the book can be crossed. In a crossed book, levels on the wrong side of the mid price are left out of bids and asks, while bestBid and bestAsk still report the best prices.

GET /candles#

OHLCV candles of one market, built from indexed fills.

Parameter Type Default Description
market string required BASE/QUOTE, each side in any asset format. Candles are returned in this orientation.
from UNIX seconds 0 Window start. Always set it.
to UNIX seconds from plus 200 candles Window end, exclusive. Must be greater than from.
resolution seconds or alias chosen from the window 300, 900, 1800, 3600, 7200, 14400, 43200, 86400, 259200, 604800, 1209600, or 5m, 15m, 30m, 1h, 2h, 4h, 12h, 1d, 3d, 1w, 2w
order string desc asc or desc by candle time

The response is an array of tuples:

Index Value Type
0 Bucket start, UNIX seconds number
1 Open price decimal string
2 High price decimal string
3 Low price decimal string
4 Close price decimal string
5 Base volume, tokens decimal string
6 Quote volume, tokens decimal string
7 Number of fills number

Hourly XLM/USDC candles since a given hour:

curl "https://demo-api.axis.markets/candles?market=XLM/CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA&resolution=1h&from=1791018000&pretty_print"

The response had five candles. The two newest are shown:

[
  [
    1791032400,
    "0.2230679",
    "0.2250866",
    "0.2220688",
    "0.2221951",
    "3.2746726",
    "0.7308724",
    13
  ],
  [
    1791028800,
    "0.2201979",
    "0.2259326",
    "0.2159081",
    "0.2223594",
    "9.6849475",
    "2.1374418",
    36
  ]
]

Notes:

  • Always pass from. It defaults to 0, so a request without it covers a window in 1970 and returns [].
  • A window holds at most 200 candles. A longer one is coarsened to the smallest standard resolution that fits: 24 hours at 5m (288 candles) comes back as 15m candles. Check the spacing of the timestamps when you request wide windows.
  • Without resolution, the service picks one from the window. With neither resolution nor to, it uses 2w.
  • Buckets are aligned to multiples of the resolution since the UNIX epoch, and from and to apply at 5-minute granularity. Align from to the resolution to get a complete first candle.
  • A period without fills has no candle. Fill the gaps in your chart.
  • Candles count fills (trade records) only. The fills of a multi-hop swap count in the market of each hop, and the swap record itself is not counted. The taker order fill of a crossfill (crossfill: true) is left out too, since its amounts mirror the makers' fills.
  • The reverse orientation inverts the prices (high and low swap places) and swaps the two volumes.

GET /ticker/24h#

24-hour statistics of every market. No parameters.

Field Type Description
ledger number Last ledger processed
timestamp number End of the window, UNIX seconds
ticker array One entry per market, most fills first
ticker[].symbol string Market base/quote in canonical order
ticker[].openPrice, highPrice, lowPrice, lastPrice string Prices in quote per base
ticker[].volume string base tokens traded
ticker[].quoteVolume string quote tokens traded
ticker[].change number Change from open to last price, percent with 3 decimals
ticker[].avgPrice string Volume-weighted average price, quoteVolume / volume
ticker[].trades number Fills in the window
curl "https://demo-api.axis.markets/ticker/24h?pretty_print"

The response had six entries. The first two are shown:

{
  "ledger": 5001979,
  "timestamp": 1791033489,
  "ticker": [
    {
      "symbol": "CC72F57YTPX76HAA64JQOEGHQAPSADQWSY5DWVBR66JINPFDLNCQYHIC/CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC",
      "openPrice": "0.3077308",
      "highPrice": "0.3140691",
      "lowPrice": "0.2879428",
      "lastPrice": "0.3046354",
      "volume": "2732.610373",
      "quoteVolume": "819.7259556",
      "change": -1.006,
      "avgPrice": "0.2999791",
      "trades": 2890
    },
    {
      "symbol": "CCUUDM434BMZMYWYDITHFXHDMIVTGGD6T2I5UKNX5BSLXLW7HVR4MCGZ/CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC",
      "openPrice": "5.450887",
      "highPrice": "5.715252",
      "lowPrice": "5.274388",
      "lastPrice": "5.555403",
      "volume": "66.5128764",
      "quoteVolume": "364.2570939",
      "change": 1.917,
      "avgPrice": "5.47649",
      "trades": 1248
    }
  ]
}

The first entry is CETES/XLM: 2,732.6 CETES traded at a last price of 0.3046 XLM per CETES.

Notes:

  • The window is the last 24 hours, exact to the fill.
  • Every known market is listed: the markets opened on-chain and every pair with live orders. A market without fills in the window reports "0" prices and volumes and trades: 0.
  • Entries are sorted by trades descending, then by symbol.
  • Symbols use the canonical orientation, which may not be the one you display. Invert the prices to show quote/base. The JS client exports invertTicker for that.
  • Like candles, the ticker counts fills only, never swap records or the taker order fill of a crossfill.

Contract and markets#

GET /contract#

Contract state rebuilt from contract events: the freeze switch, the configuration and the markets opened on-chain. No parameters.

Field Type Description
address string AXIS contract address
frozen boolean Whether the contract is frozen
config object Absent until the indexer has seen a config event
config.safetyAdmin string Safety admin address
config.oracle string Reflector oracle contract
config.listingMinDays number Days of oracle price feeds a new market must buy. 0 opens markets without a fee.
config.marketListingFee string XRF base units burned to open a market: the oracle's daily fee times listingMinDays
config.minTradeSize string Minimum order value in USD with 7 decimals (10000 is 0.001 USD). 0 disables it.
config.ledgerTime number Expected ledger close time in seconds, which the contract uses to turn lifetimes into ledgers
markets array Markets opened with subsidize, from refresh events, in the order they were first seen
markets[].base, markets[].quote string Market assets in canonical order
markets[].created string Time of the first refresh event seen for the market
markets[].refreshed string Time of the last oracle check (requote or subsidize)
curl "https://demo-api.axis.markets/contract?pretty_print"

The response listed six markets. The first two are shown:

{
  "address": "CA6P26K4QNNIMTYP22ILTSCXQQDEKNWJIZJPC34YEZYOLBNT7YUPX7XS",
  "frozen": false,
  "config": {
    "safetyAdmin": "GBDCULE53LUPK4XHUCXBI35MAZFQHENMZ3JRKAJS2PPYBV646M6XKVHG",
    "oracle": "CDEIQLTE3Y3XQMYPSZFJC2OXIS67F4MURGP73NCE2C2NZZ22RNSPV7ZI",
    "listingMinDays": 90,
    "marketListingFee": "180000000000",
    "minTradeSize": "10000",
    "ledgerTime": 5
  },
  "markets": [
    {
      "base": "CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA",
      "quote": "CCUUDM434BMZMYWYDITHFXHDMIVTGGD6T2I5UKNX5BSLXLW7HVR4MCGZ",
      "created": "2026-10-05 21:12:47",
      "refreshed": "2026-10-05 21:12:47"
    },
    {
      "base": "CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA",
      "quote": "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC",
      "created": "2026-10-05 21:12:52",
      "refreshed": "2026-10-05 21:12:52"
    }
  ]
}

Notes:

  • This is the market registry. A market can exist without live orders. GET /markets lists only pairs that have live orders.
  • The same data is pushed on the WebSocket contract channel. See WebSocket API.

GET /markets#

Pairs that currently have live orders.

Parameter Type Default Description
cursor string none cursor of the last market received, <base>-<quote>
limit integer 20 Maximum 1000
Field Type Description
baseAsset string Base asset of the canonical pair
quoteAsset string Quote asset of the canonical pair
cursor string <base>-<quote>, the cursor for the next page
orderTypes string array Always ["LIMIT"]
curl "https://demo-api.axis.markets/markets?limit=2&pretty_print"
[
  {
    "baseAsset": "CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA",
    "quoteAsset": "CCUUDM434BMZMYWYDITHFXHDMIVTGGD6T2I5UKNX5BSLXLW7HVR4MCGZ",
    "cursor": "CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA-CCUUDM434BMZMYWYDITHFXHDMIVTGGD6T2I5UKNX5BSLXLW7HVR4MCGZ",
    "orderTypes": [
      "LIMIT"
    ]
  },
  {
    "baseAsset": "CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA",
    "quoteAsset": "CC72F57YTPX76HAA64JQOEGHQAPSADQWSY5DWVBR66JINPFDLNCQYHIC",
    "cursor": "CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA-CC72F57YTPX76HAA64JQOEGHQAPSADQWSY5DWVBR66JINPFDLNCQYHIC",
    "orderTypes": [
      "LIMIT"
    ]
  }
]

Notes:

  • The list is cached for 30 minutes. A new pair can take up to 30 minutes to appear, and a pair whose last order is gone stays listed until the cache refreshes.
  • A pair is listed when it has at least one live order, backed or not. Use GET /contract for the markets opened on-chain.
  • A cursor in the <base>-<quote> form that matches no listed pair restarts the list from the first market.

Orders and accounts#

GET /order/:id#

One live order by ID.

Parameter Type Description
id path, decimal integer Order ID (u128)

The response is an Order.

curl "https://demo-api.axis.markets/order/44605595615823183937087476473264348631?pretty_print"
{
  "id": "44605595615823183937087476473264348631",
  "status": "ACTIVE",
  "buying": "CC72F57YTPX76HAA64JQOEGHQAPSADQWSY5DWVBR66JINPFDLNCQYHIC",
  "selling": "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC",
  "price": "3479416000000000000",
  "rprice": 3.479416,
  "quote": "2908352",
  "amount": "2908352",
  "owner": "GACVXELMTE6JXAQCMR4OJOYBZFD6VUDLV4YZGUR2ONN77EGZVY4YCLY5",
  "backed": "2908352",
  "backing": {
    "balance": "69249433628",
    "allowance": "373054724",
    "liveUntil": 5520444,
    "authorized": true,
    "updated": "2026-10-03 13:23:38"
  },
  "created": "2026-10-03 09:42:42",
  "updated": "2026-10-03 09:42:42",
  "cursor": "1407204591193443794944"
}

Notes:

  • Only live orders are returned. An unknown, filled, removed or expired order returns 404 with Not found. Order not found. Look up finished orders in GET /order-history.
  • An ID that is not a non-negative integer returns 400 with Bad request. Invalid order ID.
  • An expired order keeps its entry on-chain until its owner removes or revives it, but the API treats it as gone, like the contract's order view.

GET /order#

Live orders, oldest first, optionally filtered by owner and assets.

Parameter Type Default Description
owner address none Maker address, G... or C...
asset contract address none Repeat the key for two assets. Every listed asset must be one of the order's two assets, so two values select a pair in both directions.
cursor string none cursor of the last order received
limit integer 20 Maximum 200

The response is an array of Orders.

curl "https://demo-api.axis.markets/order?owner=GACVXELMTE6JXAQCMR4OJOYBZFD6VUDLV4YZGUR2ONN77EGZVY4YCLY5&limit=1&pretty_print"
[
  {
    "id": "153390214124585565809379122683319801444",
    "status": "ACTIVE",
    "buying": "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC",
    "selling": "CC72F57YTPX76HAA64JQOEGHQAPSADQWSY5DWVBR66JINPFDLNCQYHIC",
    "price": "319006000000000000",
    "rprice": 0.319006,
    "quote": "10341628",
    "amount": "10341628",
    "owner": "GACVXELMTE6JXAQCMR4OJOYBZFD6VUDLV4YZGUR2ONN77EGZVY4YCLY5",
    "backed": "10341628",
    "backing": {
      "balance": "489427040739",
      "allowance": "589201950",
      "liveUntil": 5520714,
      "authorized": true,
      "updated": "2026-10-03 13:46:13"
    },
    "created": "2026-10-03 10:04:52",
    "updated": "2026-10-03 10:04:52",
    "cursor": "1407279463540738490369"
  }
]

Notes:

  • The asset filter compares contract addresses as given. XLM or CODE:ISSUER match nothing here.
  • Expired orders are not listed.

GET /account/:address#

Every live order of an account and the backing tracked for it, per token.

Parameter Type Description
address path Account address, G... or C...
Field Type Description
address string The account
ledger number Last ledger processed
orders array Every live Order of the account, oldest first, not paginated
backing object Backing records keyed by token contract address
curl "https://demo-api.axis.markets/account/GACVXELMTE6JXAQCMR4OJOYBZFD6VUDLV4YZGUR2ONN77EGZVY4YCLY5?pretty_print"

The account had 99 live orders and four backing records. One order and one backing record are shown:

{
  "address": "GACVXELMTE6JXAQCMR4OJOYBZFD6VUDLV4YZGUR2ONN77EGZVY4YCLY5",
  "ledger": 5002051,
  "orders": [
    {
      "id": "44605595615823183937087476473264348631",
      "status": "ACTIVE",
      "buying": "CC72F57YTPX76HAA64JQOEGHQAPSADQWSY5DWVBR66JINPFDLNCQYHIC",
      "selling": "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC",
      "price": "3479416000000000000",
      "rprice": 3.479416,
      "quote": "2908352",
      "amount": "2908352",
      "owner": "GACVXELMTE6JXAQCMR4OJOYBZFD6VUDLV4YZGUR2ONN77EGZVY4YCLY5",
      "backed": "2908352",
      "backing": {
        "balance": "69249433628",
        "allowance": "373054724",
        "liveUntil": 5520444,
        "authorized": true,
        "updated": "2026-10-03 13:23:38"
      },
      "created": "2026-10-03 09:42:42",
      "updated": "2026-10-03 09:42:42",
      "cursor": "1407204591193443794944"
    }
  ],
  "backing": {
    "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC": {
      "owner": "GACVXELMTE6JXAQCMR4OJOYBZFD6VUDLV4YZGUR2ONN77EGZVY4YCLY5",
      "asset": "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC",
      "balance": "69249433628",
      "allowance": "373054724",
      "liveUntil": 5520444,
      "authorized": true,
      "budget": "373054724",
      "updated": "2026-10-03 13:23:38"
    }
  }
}

Notes:

  • backing covers the tokens of the account's live orders, both the token each order sells and the one it buys. While the account is subscribed on the WebSocket account channel, it covers every token of the open markets, orders or not.
  • Records that have not loaded yet are left out. An account without orders or subscription returns empty orders and backing.

GET /backing#

The tracked balance and allowance of one owner in one token.

Parameter Type Default Description
owner address required G... or C...
asset contract address required Token contract address

The response is a Backing record.

curl "https://demo-api.axis.markets/backing?owner=GACVXELMTE6JXAQCMR4OJOYBZFD6VUDLV4YZGUR2ONN77EGZVY4YCLY5&asset=CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC&pretty_print"
{
  "owner": "GACVXELMTE6JXAQCMR4OJOYBZFD6VUDLV4YZGUR2ONN77EGZVY4YCLY5",
  "asset": "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC",
  "balance": "69249433628",
  "allowance": "373054724",
  "liveUntil": 5520444,
  "authorized": true,
  "budget": "373054724",
  "updated": "2026-10-03 13:23:38"
}

Notes:

  • The service tracks a pair only while the owner has a live order in that token (on either side) or an open WebSocket account subscription. Otherwise the endpoint returns 404 with Not found. Backing is not tracked for the owner and asset.
  • Right after tracking starts, the record can be returned before it has loaded, with zero amounts, authorized: false and no updated. Treat a record without updated as unknown.
  • The record is an indexed view. When a decision must be exact, read the allowance from the token contract and the spendable balance from the account or trustline entry. The token's balance() includes amounts locked by selling liabilities and, for XLM, the reserve.

History#

GET /order-history#

Archived orders: filled, removed and expired.

Parameter Type Default Description
owner address none Maker address, G... or C...
pair contract address none Exactly two token contract addresses as repeated keys, pair=<x>&pair=<y>, in either order
cursor string none cursor of the last order received
limit integer 20 Maximum 500

The response is an array of Orders without backed and backing, newest first by creation time, not by the time they were archived.

curl "https://demo-api.axis.markets/order-history?owner=GACVXELMTE6JXAQCMR4OJOYBZFD6VUDLV4YZGUR2ONN77EGZVY4YCLY5&limit=1&pretty_print"
[
  {
    "id": "244077557362344635759726310078879391963",
    "status": "FILLED",
    "buying": "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC",
    "selling": "CC72F57YTPX76HAA64JQOEGHQAPSADQWSY5DWVBR66JINPFDLNCQYHIC",
    "price": "296915534537630660",
    "rprice": 0.29691553453763064,
    "quote": "24390422",
    "amount": "0",
    "owner": "GACVXELMTE6JXAQCMR4OJOYBZFD6VUDLV4YZGUR2ONN77EGZVY4YCLY5",
    "created": "2026-10-03 13:43:12",
    "updated": "2026-10-03 13:44:47",
    "cursor": "1408016927976499183616"
  }
]

Notes:

  • FILLED orders have amount "0". CANCELED orders (removed by their owner) keep the amount that was still open. EXPIRED orders keep the unfilled amount.
  • An EXPIRED order goes back to the live orders if its owner revives it with update.
  • Order IDs can be reused once an order is gone, so the archive can hold several records with the same id. Their cursor tells them apart.
  • Use repeated keys for pair. The bracket form pair[]= is not recognized, and the request returns unfiltered results.

GET /trades#

Fills and swaps, newest first.

Parameter Type Default Description
trader address none Matches the taker or the maker of a fill, or the trader of a swap
pair contract address none Exactly two token contract addresses as repeated keys, in either order
cursor string none cursor of the last record received
limit integer 20 Maximum 500

The response is an array of Trade and Swap records, told apart by type.

curl "https://demo-api.axis.markets/trades?limit=2&pretty_print"
[
  {
    "type": "trade",
    "id": "1407946559234737438722",
    "order": "33373580251613825955093796938150226715",
    "taker": "GB32JP5GNOQLW4NUMV6H2UBOSMB4DROL7YNDBWAHYXMVFLLJOH3LXKHK",
    "maker": "GB32JP5GNOQLW4NUMV6H2UBOSMB4DROL7YNDBWAHYXMVFLLJOH3LXKHK",
    "soldAsset": "CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA",
    "boughtAsset": "CCUUDM434BMZMYWYDITHFXHDMIVTGGD6T2I5UKNX5BSLXLW7HVR4MCGZ",
    "sold": "974786",
    "bought": "832170",
    "price": 0.8536950674301846,
    "cursor": "1407946559234737438722",
    "timestamp": "2026-10-03 13:22:22",
    "left": "368016"
  },
  {
    "type": "trade",
    "id": "1407945433334293725188",
    "order": "263834615734212946979442271082514120154",
    "taker": "GBDCULE53LUPK4XHUCXBI35MAZFQHENMZ3JRKAJS2PPYBV646M6XKVHG",
    "maker": "GB32JP5GNOQLW4NUMV6H2UBOSMB4DROL7YNDBWAHYXMVFLLJOH3LXKHK",
    "soldAsset": "CCUUDM434BMZMYWYDITHFXHDMIVTGGD6T2I5UKNX5BSLXLW7HVR4MCGZ",
    "boughtAsset": "CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA",
    "sold": "113052",
    "bought": "132097",
    "price": 1.1684623005342674,
    "cursor": "1407945433334293725188",
    "timestamp": "2026-10-03 13:22:02",
    "left": "1124020"
  }
]

Notes:

  • There is one trade record per fill. A swap call adds one swap record on top of the fills of its hops, so never add swap amounts to fill volumes.
  • A swap is filed under the pair of its first and last asset, for example EURC/XLM, in canonical order, for an XLM to EURC route through USDC.
  • In a multi-hop swap, the fills after the first hop list the AXIS contract as taker, because the contract pays those hops with what the previous hop delivered.
  • A crossfill adds, after its maker fills, the fill of its taker order with crossfill: true. Its taker is the caller, who keeps the surplus, and its amounts mirror the makers' fills, so leave it out of volume sums.
  • Trades and swaps have no on-chain ID. Their id is the position of the event (ledger, transaction and event index), which also orders them.
  • Use repeated keys for pair, as for /order-history.

GET /failures#

Failed AXIS calls, newest first. The records are diagnostics only: a failed call changes nothing on-chain, so it never counts against a maker or a taker, and the AXIS API does not use these records for routing.

Parameter Type Default Description
account address none Matches the caller and both parties of the failed token transfer
fn string none Contract function called, for example trade, swap or crossfill. Lowercase letters and underscores, at most 32.
cursor string none cursor of the last record received
limit integer 20 Maximum 500

The response is an array of Failure records.

curl "https://demo-api.axis.markets/failures?account=GB32JP5GNOQLW4NUMV6H2UBOSMB4DROL7YNDBWAHYXMVFLLJOH3LXKHK&limit=1&pretty_print"

An illustrative record of a trade whose payment to a maker failed:

[
  {
    "type": "failure",
    "id": "1408023584926158962688",
    "txHash": "5d0c2bb6e4a1f7a3c9e85b1d2f4a6c8e0b3d5f7a9c1e3b5d7f9a1c3e5b7d9f1a",
    "ledger": 5002410,
    "timestamp": "2026-10-03 14:02:17",
    "fn": "trade",
    "caller": "GB32JP5GNOQLW4NUMV6H2UBOSMB4DROL7YNDBWAHYXMVFLLJOH3LXKHK",
    "orders": [
      "33373580251613825955093796938150226715"
    ],
    "result": "invokeHostFunctionTrapped",
    "reason": "transfer",
    "error": {
      "contract": "CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA",
      "code": 10
    },
    "transfer": {
      "token": "CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA",
      "fn": "transfer_from",
      "from": "GB32JP5GNOQLW4NUMV6H2UBOSMB4DROL7YNDBWAHYXMVFLLJOH3LXKHK",
      "to": "GACVXELMTE6JXAQCMR4OJOYBZFD6VUDLV4YZGUR2ONN77EGZVY4YCLY5",
      "amount": "974786"
    },
    "cursor": "1408023584926158962688"
  }
]

Here the taker's USDC payment to a maker failed with the token's BalanceError (#10): either the taker could not pay or the maker's trustline had no room for the payment. The record names both parties and blames neither.

Notes:

  • The AXIS API streams every network transaction and reads the call tree of the ones touching the contract from their diagnostic events. A failed AXIS call is recorded whether the transaction called the contract or another contract did (a router), and whether the transaction failed or a calling contract caught the failure (caught). A transaction that fails in another contract after its AXIS call returned is not recorded: the AXIS call itself succeeded.
  • When no failed AXIS call shows in the call tree, for example because the RPC server returns no diagnostic events, a failed transaction calling the contract directly is still recorded from its envelope. Its reason then comes from the result code: resources for a resource problem, unknown otherwise.
  • reason tells what failed: contract (a contract error: an AXIS error named in error.name, or an error of another contract the call invoked, such as the oracle), transfer (a token transfer failed, see transfer), resources (a resource limit, the refundable fee or an archived entry), auth (an authorization failure) or unknown (the cause could not be determined).
  • A crossfill lists its taker order in takerOrder. Its payments to the makers come from the taker order's owner, so a failed transfer there involves the owner and a maker, never the caller.

Data shapes#

Order#

Field Type Description
id string Order ID, a decimal u128 derived from the owner and a nonce. Not sequential.
status string ACTIVE, FILLED, CANCELED (removed by its owner) or EXPIRED
selling string Token the maker sells
buying string Token the maker receives
price string buying base units per 1 selling base unit, times 10^18
rprice number price / 10^18 as a float, for display
quote string Selling amount when the order was created. Updates do not change it.
amount string Selling amount left
owner string Maker address
backed string Part of amount the maker's budget covers. Orders with a tracked backing only, "0" once the order is no longer live.
backing object The maker's backing in the selling token, see below. Orders with a tracked backing only.
expires string Expiration time, UTC. Absent when the order never expires.
created string Creation time, UTC
updated string Time of the last change, UTC. For an expired order, its expiration time.
cursor string Position of the creation event, the pagination cursor

The embedded backing object:

Field Type Description
balance string Amount the maker can transfer: for Classic accounts, the balance minus Classic DEX selling liabilities and, for XLM, the reserve
allowance string Allowance the maker granted to the AXIS contract
liveUntil number Ledger sequence the allowance lives until, 0 without an allowance
authorized boolean Whether the maker can send and receive the token
updated string When the values were last loaded, UTC. Absent until the record has loaded.
pending boolean Present and true while a reload confirming the latest change is still due. The values may predate that change.

backed comes from the maker's budget in the token, min(balance, allowance), or zero when the maker is not authorized or the allowance has expired. The budget is split across the maker's live orders selling that token, oldest first. The contract has no priority between these orders, so backed estimates which of them a fill would skip. See Settlement and allowances.

A live order:

{
  "id": "44605595615823183937087476473264348631",
  "status": "ACTIVE",
  "buying": "CC72F57YTPX76HAA64JQOEGHQAPSADQWSY5DWVBR66JINPFDLNCQYHIC",
  "selling": "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC",
  "price": "3479416000000000000",
  "rprice": 3.479416,
  "quote": "2908352",
  "amount": "2908352",
  "owner": "GACVXELMTE6JXAQCMR4OJOYBZFD6VUDLV4YZGUR2ONN77EGZVY4YCLY5",
  "backed": "2908352",
  "backing": {
    "balance": "69249433628",
    "allowance": "373054724",
    "liveUntil": 5520444,
    "authorized": true,
    "updated": "2026-10-03 13:23:38"
  },
  "created": "2026-10-03 09:42:42",
  "updated": "2026-10-03 09:42:42",
  "cursor": "1407204591193443794944"
}

This order sells 0.2908352 XLM for CETES at 3.479416 CETES per XLM, and the maker's budget covers all of it.

Backing#

Returned by GET /backing and as the values of backing in GET /account/:address.

Field Type Description
owner string Account address
asset string Token contract address
balance string Amount the account can transfer: for Classic accounts, the balance minus Classic DEX selling liabilities and, for XLM, the reserve
allowance string Allowance granted to the AXIS contract
liveUntil number Ledger sequence the allowance lives until, 0 without an allowance
authorized boolean Whether the account can send and receive the token
budget string min(balance, allowance), or 0 when not authorized or once the allowance has expired
headroom string Amount the account can still receive in the token: the trustline limit minus the balance and buying liabilities. Present for trustline assets, absent for XLM, contract balances and when unknown.
updated string When the values were last loaded, UTC. Absent until the record has loaded.
skipped string Time of the last skip event of an order of this owner selling this token, UTC. Absent when there was none.
pending boolean Present and true while a reload confirming the latest change is still due
{
  "owner": "GACVXELMTE6JXAQCMR4OJOYBZFD6VUDLV4YZGUR2ONN77EGZVY4YCLY5",
  "asset": "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC",
  "balance": "69249433628",
  "allowance": "373054724",
  "liveUntil": 5520444,
  "authorized": true,
  "budget": "373054724",
  "updated": "2026-10-03 13:23:38"
}

Trade#

One fill of a maker order.

Field Type Description
type string trade
id string Trade ID, the event position
order string Maker order ID
taker string The trader for trade and the first hop of a swap, the AXIS contract for later swap hops, the taker order's owner for crossfill maker fills, and the caller for the taker order's own fill
maker string Order owner
soldAsset string Token the taker paid, which the maker received
boughtAsset string Token the taker received, which the maker delivered
sold string Amount of soldAsset, base units
bought string Amount of boughtAsset, base units
left string Amount the maker order has left after the fill. "0" means filled and removed.
crossfill boolean true on the fill of a crossfill taker order, absent otherwise. Candles and the ticker leave such fills out.
price number bought / sold as a float, for display
cursor string Same as id
timestamp string Ledger close time, UTC
{
  "type": "trade",
  "id": "1407946559234737438722",
  "order": "33373580251613825955093796938150226715",
  "taker": "GB32JP5GNOQLW4NUMV6H2UBOSMB4DROL7YNDBWAHYXMVFLLJOH3LXKHK",
  "maker": "GB32JP5GNOQLW4NUMV6H2UBOSMB4DROL7YNDBWAHYXMVFLLJOH3LXKHK",
  "soldAsset": "CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA",
  "boughtAsset": "CCUUDM434BMZMYWYDITHFXHDMIVTGGD6T2I5UKNX5BSLXLW7HVR4MCGZ",
  "sold": "974786",
  "bought": "832170",
  "price": 0.8536950674301846,
  "cursor": "1407946559234737438722",
  "timestamp": "2026-10-03 13:22:22",
  "left": "368016"
}

AXIS allows self-trades, so taker and maker can be the same address, as here.

Swap#

One swap call, recorded once on top of the fills of its hops.

Field Type Description
type string swap
id string Swap ID, the event position
trader string Address that called swap
soldAsset string Token the trader paid
boughtAsset string Token the trader received
sold string Amount paid, base units
bought string Amount received, base units
price number bought / sold as a float, for display
cursor string Same as id
timestamp string Ledger close time, UTC
{
  "type": "swap",
  "id": "1407466362922858446860",
  "trader": "GB7TZS65DOB3KJLRPT2EDTMZQSCORUIQGCKP7XVNZ77VNKOTKQEY7F23",
  "soldAsset": "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC",
  "boughtAsset": "CCUUDM434BMZMYWYDITHFXHDMIVTGGD6T2I5UKNX5BSLXLW7HVR4MCGZ",
  "sold": "9999996",
  "bought": "1844614",
  "price": 0.18446147378458952,
  "cursor": "1407466362922858446860",
  "timestamp": "2026-10-03 11:00:12"
}

This swap sold 0.9999996 XLM for 0.1844614 EURC through USDC.

Failure#

One failed AXIS call.

Field Type Description
type string failure
id string Position of the transaction (ledger and application order) plus the index of the failed call, which also orders the records
txHash string Transaction hash
ledger number Ledger sequence
timestamp string Ledger close time, UTC
fn string Contract function called
caller string Address that authorized the call (its trader or sponsor argument), otherwise the transaction source
orders string array Order IDs the call listed: maker orders for trade, swap and crossfill, the updated orders for update, none for subsidize
takerOrder string Taker order ID of a crossfill. Absent for other functions.
result string Operation or transaction result code, for example invokeHostFunctionTrapped. invokeHostFunctionSuccess for a caught failure.
caught boolean true when the transaction succeeded because a calling contract caught the failed AXIS call. Absent otherwise.
reason string contract, transfer, resources, auth or unknown
error object {contract, code, name?}: the contract error that failed the call, when known. name is set for AXIS errors.
transfer object {token, fn, from, to, amount}: the token transfer that failed, when the diagnostic events show it. fn is transfer or transfer_from.
cursor string Same as id

A failed payment fails with the token's own error whether the payer could not pay or the recipient could not be credited, for example on a full trustline. The contract does not tell the two apart, so neither party is at fault from a transfer record alone. See Failure modes.

Using a quote in a contract call#

A quote tells you which orders to list. Your transaction calls the AXIS contract directly, through Stellar RPC, and the contract checks every price and backing again. The AXIS API never signs or submits anything.

Quote Contract call Arguments from the quote
Any route swap One TradeStep per hop: asset is the hop's buying, orders its orders. Sell takes sold as the exact input and your minimum output. Buy takes bought as the exact output and your maximum input.
Direct market (direct=true), strict_send trade with Sell, kind Fill orders of the hop. Limit price = floor(10^36 / worstPrice), the minimum buying per 1 selling.
Direct market (direct=true), strict_receive trade with Buy, kind Fill orders of the hop. Limit price = worstPrice, the maximum selling per 1 buying.
Direct market with maxPrice trade with kind Limit orders of the hop and your own limit price. The contract fills the listed orders and stores the remainder as an order.

The second and third rows are market orders: they cross the listed orders at no worse than the worst quoted price and place nothing on the book. With kind FillOrKill the call fails with NotFilled (709) unless the amount fills completely. Code for both conversions is in API and stream clients, and the full swap flow with slippage and approval planning in Wallet integration.

Before you build the call:

  • The trader needs an allowance to the AXIS contract on the token they pay, covering this spend plus what their open orders still sell, see Wallet integration.
  • The trader must be able to receive the bought asset, see Wallet integration.
  • Orders that are gone by the time the transaction lands are skipped. A market order then fills less, while Fill-or-Kill and swap fail with NotFilled (709) when their bounds are not met. See Failure modes.

The JS client wraps all of this: AxisAccount.swap and the market orders of AxisAccount.sell and AxisAccount.buy quote, plan the approval and submit for you (see Axis, markets and accounts).