Skip to main content

Decide in 30 seconds

Which call needs which header: Base URL, app IDs & API keys. A bot is one user. It signs a SIWE message with its own private key, gets a user access token, and trades from that user’s managed balance. No browser, no API key.
You’ll need:
  • An app ID from the admin dashboard (https://admin.agg.market), under API.
  • One allowed origin on that app (Domains), for example https://bot.example.com. It never has to serve a page. Wallet sign-in names it, and an app with none cannot complete sign-in.
  • Node 18 or later, @agg-build/sdk, and viem.
  • A private key for the bot. Keep it out of source control.
Result: a filled order, polled until terminal is true, then the bot’s positions.
The steps below run top to bottom as one file. The same code as a single script is in Full script. It trades in paper mode unless you set AGG_LIVE=1.

0. Set up

1. Sign in with the bot’s key

Get a nonce, build the SIWE message, sign it locally, and verify it. verify() keeps the access and refresh tokens in the client and sends them from then on.
Start authentication · Verify sign-in

Keeping the session alive

  • The SDK keeps tokens in memory only. A restarted process must call signIn() again. Each sign-in uses a fresh nonce.
  • The access token lasts 15 minutes and the refresh token 7 days. When a call returns 401, the SDK refreshes once with the refresh token, stores the new pair, and retries the call. You write no refresh code.
  • If that refresh fails (the refresh token expired or was revoked), the SDK clears the session and throws the 401. Call signIn() again.
  • With cURL, refresh yourself: POST /auth/token/refresh with { "refreshToken": "..." } and x-app-id, then use the new pair. See Refresh access token.
  • In Node, a client holds the process open. Call client.destroy() when the bot is done.

2. Fund the bot

Live mode only. In paper mode, skip to the balance check: the paper account starts with a simulated PAPER_USD balance.
Get deposit addresses · Get balances · Funding availableRaw is an integer string in the token’s decimals: "5000000" with 6 decimals is 5 USDC.

3. Find an outcome

You trade an outcome, not a market. Take a venueMarketOutcomes[].id.
List venue markets · Markets, outcomes & matching

4. Quote

The bot’s token makes the quote executable. Fill only when status is "ok".
Get a quote (smart route) · Quotes & smart routing A quote expires about 45 seconds after it is created. Fill right away.

5. Fill

Execute quote The response means accepted, not done. If the call times out, do not re-quote: resend the same quoteId or poll status. Resending a quoteId never trades twice. See Errors, retries & idempotency.

6. Poll to a final state

Get execution status · Order lifecycle & statuses overallState ends as filled, partially_filled, failed, cancelled, or expired.

7. Read positions

Get user positions. When a market settles, claim winnings with Claim winnings.

Paper mode

mode: "paper" on the quote, the fill, the status call, and the balance and position reads. Paper fills price against live books but never reach a venue, so no deposit is needed. A paper quote must be filled in paper mode. See Paper trading. To trade live, set AGG_LIVE=1, fund the deposit address from step 2, and drop mode=paper from the cURL calls.

Failures a bot hits

The SDK throws AggApiError with status, code, and retryAfterMs; check it with isAggApiError(err). Every code: Errors, retries & idempotency.

Full script

Save as bot.ts and run with AGG_APP_ID=... BOT_PRIVATE_KEY=0x... npx tsx bot.ts.
SDK

Next

Direct orders

One call per trade with your own idempotent externalId. Live only.

Limit orders

Rest an order at your price on one venue.

Order book stream

Live books over WebSocket instead of polling.

Self-custody

Keep funds in the bot’s own wallet; the bot signs each step.