You’ll need: a
trade API key for your app, your app id, fee recipients configured, and a
non-zero app fee with self-custody fee collection enabled.
Result: orders, webhooks, and the app fee attributed to your app. The market maker signs
with their own wallet. You do not create their user first.read or read_write key, or with no key, is the same user when they
sign in with the trader key. Someone who first signed in with the trader key is the same user
when they sign in with another of your keys. The token from either sign-in works with the other
key. The key does not replace the user token and cannot act as a user who has not signed in.
The key is trading access for your app only. It cannot list or read your other users, manage
keys, members, settings, webhooks, or security, or set a per-trade fee or referral. It works
only with your app id. skipQuote and skipBalance stay on read_write keys. Direct orders
(POST /execution/orders) reject signingAddress, so this flow uses quote, then fill.
Venue trader points stay on the market maker’s own venue account. Agg does not move those
points to you. What you receive is the Agg order on your app, the order webhook, your app fee
collected to feeRecipientEvm or feeRecipientHypercore, and your builder code
when one is configured.
Fee collection on this path works for a buy funded from one EVM wallet, with approveMode
omitted or sponsored. Other shapes can skip the fee. See
Self-custody trading.
Create the key
In the admin dashboard, open API and create a key with the Trader permission. The secret is shown once. You can have three active trader keys. They do not count toward the five read and read/write keys. Revoking a key stops it on the next call and does not delete users it already created. To freeze one wallet, suspend that user.Rate limits
Send the trader key on every call, including sign-in, quotes, and fills. The key has its own copy of your app’s server limits: 18,000 requests per minute onagg:rl:apikey:<keyId>, plus
the per-endpoint API-key ceiling (quotes 1,500 per minute, trading 6,000 per minute) on
agg:rl:route:v1:<group>:hash(key:<keyId>). Those calls do not count toward your app’s user
buckets.
A user token sent without the key is a normal user call. It uses the lower per-user ceilings
and counts toward agg:rl:app:<appId>:user:<userId>. There is no single shared
agg:rl:app:<appId> bucket.
Trade
The market maker keeps custody of the key. Agg never holds it. The signing wallet is the one that signed in, so there is no separate step to link it.1
Sign in
POST /auth/start with provider: "siwe", x-app-id, and x-app-api-key. A valid trader
key skips the per-IP sign-in limit and Turnstile. The key’s own rate limit still applies.
Sign the nonce with the market maker’s EOA and POST /auth/verify. Keep the user access
token.2
Quote
GET /orderbook/{venueMarketOutcomeId}/route with the user token, the trader key, and
signingAddress set to that EOA. Omit appFeeBips and referral fields. The app’s configured
fee applies. A different address is refused.3
Fill and sign
POST /execution/fill with the same signingAddress, then poll
GET /execution/status?quoteId= and submit signatures. The sequence is the same as
self-custody signing.cancelSignature. Kalshi still
needs the user’s own venue key from Venue keys. The secret is never
returned.
GET /apps/{appId}/users and GET /apps/{appId}/orders return 403 for this key. A read key
still has partner admin. Using the trader key with another app’s x-app-id returns 403.