Skip to main content

Boros API Best Practices

This guide provides recommendations and common patterns for integrating with the Boros API efficiently.


Bulk Order Placement

When placing multiple orders simultaneously, always use the bulk order endpoint instead of making multiple single order requests.

Why Use Bulk Orders?

ApproachGas CostAtomicityNetwork Overhead
Multiple single ordersHigh (N transactions)None (partial failures possible)High
Bulk ordersLow (1 transaction)Atomic (all or nothing)Low

Benefits

  1. Lower Gas Fees — Multiple operations batched into a single transaction
  2. Atomic Execution — All operations execute together, eliminating partial execution risks
  3. Better Performance — Reduces network overhead and speeds up execution
  4. Complex Strategies — Combine cancellations and new orders in one operation
caution

Unlike single order placement (placeSingleOrder), bulk orders do NOT match with the AMM. They are placed directly into the order book. If you need to take liquidity from both the order book and the AMM, use single order placement with IOC or FOK time-in-force.

Examples


Transaction Submission

direct-call vs bulk-direct-call

The Send Txs Bot provides two submission endpoints:

EndpointUse case
POST /v2/agent/direct-callSubmit a single calldata
POST /v3/agent/bulk-direct-callSubmit one or more calldatas with sequential execution

When to use bulk-direct-call: The calldata generation endpoints (e.g., POST /calldata/place-orders) may return multiple calldatas in the calldatas array — for example, [exit-market, place-order] when autoExitMarket=true. You must submit all calldatas together using bulk-direct-call to ensure correct execution order.

Common pitfall

If you use direct-call with only the first element of a multi-calldata response, only the exit-market transaction executes — your order will not be placed. Always check the length of the calldatas array and use bulk-direct-call when there are multiple entries.

autoExitMarket Parameter

When calling POST /calldata/place-orders, the autoExitMarket parameter (default: true) controls whether the API automatically generates an exit-market calldata for expired/unused markets:

  • autoExitMarket=true → API may return 1 or 2 calldatas: [exit-market (optional), place-order]. The last element is always the place-order calldata.
  • autoExitMarket=false → API always returns exactly 1 calldata (place-order only). Use this if you manage market entry/exit yourself.

skipReceipt Parameter

Controls whether the Send Txs Bot waits for block confirmation:

  • skipReceipt=false (default): Waits for the transaction to be included in a block, then returns status and error fields. Higher latency but gives immediate confirmation.
  • skipReceipt=true: Returns the txHash immediately after broadcasting. Lower latency but you must track the transaction status yourself.

Market Management

Exit Unused Markets

If you have entered markets that are no longer in use, exit them to reduce gas costs on future operations.

When you enter a market, the system tracks your participation for margin calculations. Each entered market adds overhead to the margin tracker, making it more expensive in gas for every subsequent transaction.

Important limitations:

  • Maximum 10 entered markets per marketAcc (market account). This limit is per combination of (address, accountId, tokenId) — i.e., per collateral type.
  • Maximum active limit orders per marketAcc per market (configurable per market via maxOpenOrders, typically 100)
  • Entering more markets = heavier margin calculations = higher gas costs
tip

If you trade many markets over time (e.g., weekly expiry markets), you will hit the 10-market limit. You must exit expired/matured markets to free up slots for new ones. The autoExitMarket parameter in the place-orders API can handle this automatically.

Exiting unused markets helps:

  • Reduce gas consumption on all subsequent transactions
  • Free up slots for new markets (10 market limit)
  • Improve transaction performance

When to Exit Markets

  • After closing all positions in a market
  • When you no longer plan to trade a specific market
  • During account cleanup/maintenance
  • Before market expiry (for dated markets)

To exit a market, you must first:

  1. Close all positions (zero position size)
  2. Cancel all open orders
  3. Have no pending settlements

Isolated-Only Markets

Some markets are isolated-only, meaning they cannot be traded from a cross-margin account. For these markets:

  1. Deposit to the isolated account — You must transfer collateral specifically to the isolated market account, not the cross-margin account
  2. Use the correct marketAcc — Pack the marketAcc with the specific marketId instead of CROSS_MARKET_ID
import { MarketAccLib } from "@pendle/sdk-boros";

// For isolated-only markets, use the specific marketId
const isolatedMarketAcc = MarketAccLib.pack(
walletAddress,
accountId,
tokenId,
marketId // Use the specific market ID, NOT CROSS_MARKET_ID
);

To fund an isolated account, either:

  • Direct deposit: Deposit directly to the isolated market using the marketId in the deposit calldata
  • Cash transfer: Transfer from cross-margin to isolated using the /calldata/cash-transfer endpoint with isDeposit: true

Example: Top Up Isolated Account


Gas Usage and Estimation

Monitor Gas Balance

Boros uses a gas account system for executing agent-signed transactions. Always monitor your gas balance to avoid failed transactions.

Key endpoints:

  • GET /accounts/gas-balance — Check current balance
  • GET /accounts/gas-consumption-history — Review usage patterns
  • GET /calldata/vault-pay-treasury — Top up gas balance (sensitive, root-signed)

Arbitrum Gas Spikes

Arbitrum gas prices can spike significantly during high network activity. Consider:

  1. Monitor gas prices before submitting transactions
  2. Maintain buffer in your gas account for unexpected spikes
  3. Check gas consumption history to understand your usage patterns

Example: Top Up Gas Account


Error Handling

Error Response Formats

The Open API uses a structured error format:

{
"errorCode": "INVALID_MARKET_ID",
"message": "Market with ID 999 not found",
"data": {}
}

The Send Txs Bot and Stop Order services use a legacy format:

{
"statusCode": 400,
"message": "Invalid signature"
}

Handling Common Errors

ErrorCauseSolution
Insufficient marginNot enough collateral for the positionDeposit more, reduce size, or close other positions
Agent expiredAgent approval has expiredRe-approve agent via GET /calldata/approve-agent
Invalid signatureSignature doesn't match the expected signerVerify you're signing with the correct agent key
Market not enteredTrying to trade on a market you haven't enteredUse GET /calldata/enter-exit-markets to enter first
Order limit reachedExceeded maxOpenOrders for the marketCancel some existing orders before placing new ones
Market limit reachedOver 10 entered marketsExit unused markets to free up slots

Retry Strategy

  • Don't retry immediately on validation errors (bad parameters, insufficient margin) — fix the root cause
  • Retry with backoff on transient errors (network timeouts, 503s)
  • Check transaction status before retrying submissions to the Send Txs Bot — the original may have succeeded

Simulation Before Execution

Always use the simulation endpoints before executing trades, especially for:

  • Large orders — preview margin impact and fees
  • Close positions — verify the counter-order parameters
  • Deposits/withdrawals — check that the operation won't cause under-margining

Simulations are free (no gas) and return the projected account state. The key simulation endpoints:

EndpointUse case
GET /simulations/place-orderPreview order placement
GET /simulations/close-active-positionPreview closing a position
GET /simulations/depositPreview deposit effect
GET /simulations/withdrawPreview withdrawal effect
GET /simulations/cash-transferPreview cross ↔ isolated transfer

Real-Time Data

Market Data Latency

Not all REST endpoints have the same latency characteristics. For latency-sensitive indicators, use the correct endpoint:

DataBest endpointLatency
midApr, bestBid, bestAsk, ammImpliedApr, markAprGET /open-api/v1/markets/{marketId}Real-time
Order book depthGET /core/orderbooks/{marketId}< 1 second
AMM stateGET /core/amm/{ammId}< 1 second
Market list / overviewGET /open-api/v1/marketsMay have several seconds of delay
tip

For market making or any use case requiring live mid/mark rates, always use the single market endpoint (GET /v1/markets/{marketId}) rather than the bulk markets list. The bulk endpoint may have a delay of several seconds on sensitive indicators.

Combined Order Book (AMM + Order Book)

The order book displayed in the Boros UI and returned by GET /v2/markets/order-books (with AMM enabled) is a combined order book that merges:

  • Order book liquidity: Discrete maker orders at specific tick levels
  • AMM liquidity: Continuous liquidity from the AMM, discretized into tick levels for display

Important: The AMM has a minimum and maximum APR range. When the market rate moves outside this range, the AMM stops providing liquidity. In this case, the combined order book may show a wider spread since only order book liquidity remains.

Note: Some markets may have no AMM at all. In these markets, all liquidity comes from the order book only, and placeSingleOrder behaves the same as bulkOrders (no AMM to route through). Check the market's ammId — if absent or null, there is no AMM.

The AMM implied rate should normally be within the range (bestBid - ε, bestAsk + ε) where ε is a small amount to prevent arbitrage between the AMM and the order book.

Use WebSocket for Streaming

Don't poll REST endpoints for real-time data. Use WebSocket for:

  • Order book updates: orderbook:MARKET_ID:TICK_SIZE
  • Trade events: market-trade:MARKET_ID
  • Market statistics: statistics:MARKET_ID
  • Account changes: account:ADDRESS:ACCOUNT_ID

Caching Strategy

DataCache durationRefresh trigger
Assets listLong (hours)Rarely changes
Market listMedium (minutes)New markets added infrequently
Market state / order bookDon't cacheUse WebSocket
Account positionsDon't cacheUse WebSocket account channel
Gas balanceShort (seconds)After each transaction

Security

Key Management

  • Never expose your root private key in client-side code or logs
  • Use the agent system — the agent key has limited permissions and cannot withdraw funds
  • Rotate agent keys periodically by revoking the old agent and approving a new one
  • Set reasonable expiry times on agent approvals

Transaction Verification

  • Always simulate before executing to verify expected outcomes
  • Check the to address in calldata responses matches the expected Router contract
  • Verify transaction status after submission — don't assume success

Summary

Best PracticeWhy
Use bulk orders for multiple operationsLower gas, atomic execution
Use bulk-direct-call for multi-calldata responsesEnsures all calldatas (exit-market + place-order) are submitted
Set autoExitMarket=false if managing markets yourselfAvoids unexpected multi-calldata responses
Exit unused/expired markets (max 10 per account)Reduce gas overhead, free up slots
Use GET /v1/markets/{marketId} for real-time ratesGuaranteed real-time midApr, markApr, bestBid, bestAsk
Use correct marketAcc for isolated-only marketsRequired for trading isolated-only markets
Monitor gas balanceAvoid failed transactions
Simulate before executingPreview margin impact and catch errors
Use WebSocket for real-time dataLower latency, less overhead than polling
Handle errors by format (Open API vs legacy)Different services use different formats
Never expose root key; use agentsSecurity best practice

For complete working examples, visit: https://github.com/pendle-finance/boros-api-examples