Base URL, app IDs & API keys
The API base URL, where your app ID and server API key come from, and which headers go on each call
Base URL
| URL | |
|---|---|
| REST API | https://api.t.sufwankhalid.com |
| WebSocket | wss://ws.t.sufwankhalid.com/ws?appId=YOUR_APP_ID |
| Orderbook socket | wss://ob.agg.market/ws?appId=YOUR_APP_ID |
| Admin dashboard | https://admin.agg.market |
The orderbook socket is optional. It serves the orderbook channel, with an opt-in realtime tier, and the orderbook firehose. Everything else stays on the WebSocket URL. See Orderbook streams.
There is one environment. Orders route to the real venues, so a live fill spends real funds. Use paper trading to test without them.
Your app ID
Every request that uses an app id carries it in the x-app-id header. Find it in the admin
dashboard: pick your app, then open API under Develop. The same page lists your API keys.
Allowed origins
Your app's allowed origins are the sites your browser code runs on. Manage them in the admin
dashboard under Domains. Enter bare origins such as https://app.example.com, with no path,
query, or wildcard.
They are used in three places:
- A request that sends an
Originheader must match one of them, or it gets403 Origin not allowed for this app. Server requests usually send noOriginand skip this check. - A browser WebSocket connection must send a matching
Origin. Servers connect withx-app-api-keyon the handshake instead. See Server connections. - A SIWE or SIWS sign-in message names a domain. It must match an allowed origin, or sign-in
fails with
401andcode: "unregistered_domain". - OAuth and magic-link
redirectUrlvalues must be on an allowed origin.
An app with no allowed origins cannot complete wallet sign-in.
Headers
The public API uses the credentials below. Your app ID identifies the integration and is safe to include in browser or mobile code. A user access token authorizes actions for that user. Server API keys are secrets and must stay on your backend.
| Set | Headers | Calls |
|---|---|---|
| 1 | x-app-id | Markets, market data, news, correlated markets, and most of auth. Also the smart-route quote GET /orderbook/{venueMarketOutcomeId}/route, geo policy GET /app/venue-geo-policy, the leaderboard GET /leaderboard, and both ramp calls POST /ramp/quotes and POST /ramp/session. |
| 2 | x-app-id and Authorization: Bearer <accessToken> | Users, hosted venue accounts, funding except the two ramp calls, trading except the quote, and portfolio except the leaderboard. Sign-out (POST /auth/sign-out) is the auth call in this set. |
| 3 | x-app-api-key; x-app-id is not required. | Partner-admin reads, paper-trading admin calls, and webhook rotate and replay (POST /apps/{appId}/webhooks/{webhookId}/rotate-secret and POST /apps/{appId}/webhooks/{webhookId}/replay). |
Exception: POST /bot-protection/verify requires both x-app-id and x-app-api-key. See
Bot protection.
A user JWT on the smart-route quote turns a preview into an executable quote. A sell still requires a signed-in user. referrer is rejected without x-app-api-key. skipQuote and skipBalance are rejected without an x-app-api-key that can write (read_write); a read-only key is refused. That key does not replace x-app-id.
Users sign in on the client. Your backend sends that user's access token on set 2 calls. See Authentication & sessions.
App config
GET /app/config is UI config for the app: disabled venues, disabled categories, early access,
auth providers, trading mode, and the paper starting balance. Send x-app-id only. A user
session and an API key are not required, including when the app requires a key on other routes.
An unknown or inactive app returns 404. The response has no secrets. A successful response is
cached at the edge until the app changes.
import { createAggClient } from "@agg-build/sdk";
const client = createAggClient({
baseUrl: "https://api.t.sufwankhalid.com",
appId: "your-app-id",
});
const config = await client.getAppConfig();Full shape on Get the per-app UI config (disabled venues + categories).
Server API keys
Send x-app-api-key from your backend on API-key routes, on POST /bot-protection/verify, and
when using per-trade fee overrides, referrals, skipQuote, or skipBalance. You can also send
a key with server-side market-data requests to use its rate-limit budget. Keep x-app-id on
app and user routes, and keep the user token where required; the key does not replace them.
An API key is a secret. Never put it in browser bundles, source maps, public repositories, or logs.
Create a key
In the admin dashboard, pick your app, open API, and create a key. The key is shown once. Store it in your secret manager right away. sufwan-local-test keeps only a hash and cannot show it again.
Keys look like agg_<appId>_<64 hex characters>. Keep that prefix unchanged when reusing a key.
A key that is missing, malformed, unknown, revoked, or expired is rejected with 401.
On app and user routes, a read or read_write key can be sent with any active x-app-id; app
membership is not required for reuse. The target app's settings and allowed origins apply, and a
user token must be issued for that target app. The key retains its scope and rate-limit budget.
Keep shared keys secure and revoke them if compromised. Admin routes continue to require a key
issued for their target app. A trade key is the exception: it works only with the app id in
the key.
Use a read key for reporting and a read_write key for operations that change state.
skipQuote and skipBalance require read_write. A trade key lets a market maker sign in
with their own wallets and trade on this app. It does not create users, it cannot read other
users, and it cannot set app fees or referrals. A wallet is the same user on your app whichever
of these keys it used to sign in, and a token from one key works when the caller sends the
other. Send the trader key on every call. A user token without
the key uses the lower per-user limits and counts toward that user's budget. Calls that
include the trader key use the key's own copy of the app's server limits and do not draw down
the app's user budgets. See Market maker trading. Manage app members
and settings in the admin dashboard.
For app-wide reporting, follow Partner admin to read users, balances, orders, and analytics from your backend with this key.
Rotate a key
- Create a new key.
- Deploy your backend with it.
- Check traffic moved to it (
lastUsedAtin the dashboard). - Revoke the old key. Revoked and expired keys fail at once with
401.
Rate limits
A validated key gets its own per-key budget, by default 18,000 requests per minute, and skips per-IP limits. Endpoint limits still apply. See Rate limits, which also explains how to request a higher limit.
Testing mode
New apps start in testing mode, with two caps:
| Limit | Cap | Counts |
|---|---|---|
| Users | 20 | Unique users who sign in to your app |
| Trades | 100 | Orders placed, not counting failed orders |
Existing users can always sign in. Past the user cap, POST /auth/verify returns 403 for new
users. Past the trade cap, trading calls return 403. Both carry a readable message:
{
"statusCode": 403,
"message": "This app has reached its testing limit of 100 trades. Sign the partner agreement to enable live mode and continue placing trades."
}OAuth and magic-link sign-in report the user cap on the redirect URL as a message query
parameter with error=testing_user_limit_reached.
To lift the caps, sign the partner agreement in the admin dashboard (Go Live). It takes effect at once and cannot be undone from the dashboard. Existing users and trades are kept.