Skip to main content
Ondo Global Markets brings tokenized stocks & ETFs on-chain as DeFi strategies (protocol: "Ondo", network: bsc). The market-share position always lives on BSC, but clients can fund a buy from — or receive a sell payout on — another EVM chain. Pods handles the bridge and the async order fill.

Overview

Flow summary
Settlement is asynchronous. The on-chain transaction submits the request in seconds; the order reaches SUCCESS only after Ondo fills it (minutes later). For crosschain, the bridge leg settles first, then the order. Track both the on-chain receipt and the action status via WebSocket or history polling.
Quote and bytecode come from the same call. GET /strategies/:id/bytecode returns a priced quote (for your UI) and bytecode[] (to execute on-chain).

Authentication

Every request requires:
  • The key identifies your customer. Fee configuration and strategy catalog are scoped to it.
  • Success responses are the bare JSON body (HTTP 200). Errors use { "error": { "code", "message", "details?" } }.
  • Keep the API key on your backend — never expose it in a browser app.

Integration flow


1. Market status

Gate buy/sell when the market is closed.
Key field: isOpen — block new submissions when false. The payload may also include session details (marketStatus, nextOpen, nextClose). Per-asset eligibility during off-hours can still fail at quote time with errors such as COW_ASSET_SESSION_CLOSED — see Ondo GM docs.

2. List Stocks & ETFs

GET /tokens requires the wallet product type on your API key (customer.productType must include wallet). Keys with API-only scope receive 403 Forbidden. Workaround: list Ondo strategies via GET /v2/strategies?protocol=Ondo&network=bsc — each strategy includes assetToken (market-share symbol, address, decimals).
  • category accepts comma-separated values (stock, etf).
  • Each token: { symbol, name, address, decimals, chainId, category, priceInUSD, logoURI? }.
  • Ondo symbols end in ON (e.g. AAPLON). Strip ON for display if desired.

3. Resolve strategy ID

A market-share token address alone is not enough — you need the strategy id.
Returns { data: [...], pagination }. Pick the strategy where:
  • asset matches the market-share token address
  • networkId === 56
Use actions request-lend (buy) and request-withdraw (sell) from availableActions.

4. Buy — request-lend

Same-chain (BSC): fromChainId=56, fromTokenAddress=0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d (18 decimals). The client signs on BSC. Crosschain: fromChainId= origin chain (e.g. 8453 Base). The client signs only on the origin chain; Pods bridges funds to BSC and fills the order asynchronously. Response (relevant fields):
Client execution
Atomic execution is mandatory. Cross-chain buys may return multiple legs on the funding chain (approve + bridge). Execute every leg where chainId === chainIdIn in one transaction — never as separate sends. Partial execution parks funds in escrow with PENDING status and no pipeline progress. See Executing Bytecode and EIP-7702.
  1. Filter bytecode where chainId === chainIdIn (same-chain: 56; crosschain: the origin chain).
  2. Batch all filtered legs into one signed transaction (output=bytecode + EIP-7702, or output=userOperation / output=fireblocks per your wallet stack).
  3. Wait for async completion (crosschain: bridge → BSC → CoW order fill).
  • Minimum: $10 USDC (enforced server-side, error REQUEST_LEND_AMOUNT_TOO_LOW). For crosschain the minimum is checked on the bridged USDC amount that lands on BSC.
  • Use quote for pricing UI; use quote.feeBreakdown.summary for fee display.
Crosschain: the client only signs on the origin chain. Bridge + market-share purchase are handled by Pods.

5. Sell — request-withdraw

Same-chain (BSC): toChainId=56, toTokenAddress=0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d. The client signs on BSC.
  • Use amountInShares (not amount) for Ondo sells. No minimum sell amount.
  • Response shape matches buy (id, chainIdIn, chainIdOut, crossChain, singleUseAddress, orderUid, quote, bytecode).
Crosschain: toChainId= destination chain. The client signs only on BSC (shares live there); Pods sells the market share for USDC on BSC, then bridges the proceeds to the destination chain. Client execution
Batch all BSC legs (chainId === 56) into one atomic transaction. See Executing Bytecode.
  1. Filter bytecode where chainId === 56 (always BSC — shares are on BSC).
  2. Batch and sign on BSC in a single transaction.
  3. Wait for async completion (CoW order fill → crosschain: bridge USDC to toChainId).
Crosschain: the client only signs on BSC. Market share → USDC redemption and the bridge payout are async.

6. Positions & pending requests

The wallet is always normalized to BSC (same EVM address regardless of funding/payout chain).

Wallet snapshot (all positions)

Stocks & ETFs appear under earn.positions where strategy.protocol === "Ondo".

Single strategy position

or
Use fromActions=1 for correct accounting (principal, profit, in-flight operations).

Position shape

requestedTo* fields

These arrays represent pending async orders not yet settled (same on same-chain and crosschain): Empty arrays mean nothing is pending. Expected states
  • Buy submitted, shares not yet credited → requestedToLend / requestedToLendInShares populated.
  • Sell submitted, USDC not yet paid out → requestedToWithdraw / requestedToWithdrawInShares populated.
  • Settled → all pending arrays empty; currentPositionInShares / underlyingBalanceUSD reflect the real balance.
Suggested polling: every 5–15 s until the pending arrays clear (or use WebSocket/webhook below).

Available balance for sell

Do not subtract pending buys from available shares. Use availableShares as amountInShares when selling the full position.

7. Track order status

After submitting bytecode[] on-chain, the action is not complete until status is SUCCESS.

HTTP — pending actions for one strategy

Poll when you want a strategy-scoped snapshot without loading the full wallet or strategy position. The handler refreshes in-flight operations before responding.

What appears in actions[]

Root response (always)

Ondo Global Markets strategies only — root also includes orderBook:
Present even when actions is empty.

Each item in actions[]

Base fields (every pending action)
Cross-chain pending actions include only the base block (no suw). suw block (Ondo Global Markets request-lend / request-withdraw only)

suw.phase lifecycle

suw.order shapes

Not posted yet (posted: false):
Posted / live (posted: true): adds validTo, creationDate, executionDate, executedSellAmount, executedBuyAmount, txHash. Typical status values: open, fulfilled, unknown (with providerError when lookup fails).

Empty pending example

Suggested polling: every 5–15 s while hasPending is true, or until suw.phase reaches a terminal value. Example
Non-Ondo strategies return the same root envelope without orderBook or suw.
Listen for action_update events where action.id matches the bytecode response id: Re-subscribe on reconnect. Alternatively, use your customer webhook (ACTION_UPDATE events).

History

Embedded in GET /v2/wallets/:address?include=all&fromActions=1 or:
Market-share buys appear as SAMECHAIN_INVESTMENT_DEPOSIT; sells as SAMECHAIN_INVESTMENT_WITHDRAW. Ignore INITIAL status (quote artifact).

Refresh positions

Refetch wallet/strategy endpoints after on-chain confirmation and after WebSocket SUCCESS.

8. Supported chains & USDC addresses

Stocks & ETFs settle on BSC; funding (buy) and payout (sell) can use any supported USDC chain. When fromChainId / toChainId are set, fromTokenAddress / toTokenAddress are required — the API does not default to USDC. Omission returns 422 VALIDATION_ERROR. A non-USDC funding or payout token may add an extra same-chain swap leg.

9. Errors

Preserve error.code in your UI for user-friendly messages.

10. Integration notes

  1. Use the correct actions: request-lend (buy) and request-withdraw (sell). Do not use the generic lend/withdraw.
  2. Sign on the right chain: buy = funding chain (chainIdIn); sell = always BSC; position = BSC wallet.
  3. Atomic bytecode: never send bytecode[] legs as separate transactions — see Executing Bytecode.
  4. Async completion: after the origin tx, Pods completes bridge (if crosschain) + order fill; monitor via the action status, position, or history.
  5. Sells use shares: pass amountInShares (18 decimals), not amount. Gate sells on wallet position (currentPositionInShares) and suw.phase !== 'awaiting_forward'.
  6. Wallet output: EOA → output=bytecode + EIP-7702; smart account → output=userOperation; Fireblocks → output=fireblocks + accountId.
  7. Same EVM wallet works across funding/payout chains; the market-share position always lives on BSC.

Minimal example

Buy $10 of AAPL from Base (crosschain):
Sign response.bytecode (legs where chainId === 8453) on Base, then poll:
Sell shares, receive USDC on Arbitrum (crosschain):
Sign response.bytecode (legs where chainId === 56) on BSC, then poll the position until the pending arrays clear.

Endpoint reference

All HTTP endpoints require x-api-key.