All webhook events share the same envelope format:
{
"id": "evt_accounts.created:usr_abc123",
"type": "accounts.created",
"createdAt": "2026-04-09T18:15:03.000Z",
"data": { ... }
}
| Field | Type | Description |
|---|
id | string | Unique event ID (use for deduplication) |
type | string | Event type (dot notation) |
createdAt | string | ISO 8601 timestamp |
data | object | Event-specific payload |
accounts.created
Fired when a new user is created in your app (first authentication).
{
"id": "evt_accounts.created:usr_abc123",
"type": "accounts.created",
"createdAt": "2026-04-09T18:15:03.000Z",
"data": {
"userId": "usr_abc123",
"appId": "app_xyz",
"createdAt": "2026-04-09T18:15:03.000Z"
}
}
| Field | Type | Description |
|---|
userId | string | The new user’s ID |
appId | string | Your app’s ID |
createdAt | string | When the user was created |
accounts.linked
Fired when a user is linked to a partner external ID via the identity assertion flow.
{
"id": "evt_accounts.linked:usr_abc123:partner_42",
"type": "accounts.linked",
"createdAt": "2026-04-09T18:15:03.000Z",
"data": {
"userId": "usr_abc123",
"externalId": "partner_42",
"linkedAt": "2026-04-09T18:15:03.000Z"
}
}
| Field | Type | Description |
|---|
userId | string | The user’s AGG ID |
externalId | string | Your internal user ID |
linkedAt | string | When the link was created |
wallets.ready
Fired when a server-managed wallet is provisioned for a user (both EVM and Solana addresses
are available).
{
"id": "evt_wallets.ready:usr_abc123",
"type": "wallets.ready",
"createdAt": "2026-04-09T18:15:03.000Z",
"data": {
"userId": "usr_abc123",
"evmAddress": "0x1234...abcd",
"svmAddress": "ABC123...xyz",
"createdAt": "2026-04-09T18:15:03.000Z"
}
}
| Field | Type | Description |
|---|
userId | string | The user’s ID |
evmAddress | string | EVM (Ethereum/Polygon) wallet address |
svmAddress | string | Solana wallet address |
createdAt | string | When the wallet was provisioned |
trades.placed
Fired when a user submits a trade order. The payload contains the order ID — query the API for
the full breakdown (venue splits, amounts, prices).
{
"id": "evt_trades.placed:quote_abc123",
"type": "trades.placed",
"createdAt": "2026-04-09T18:15:03.000Z",
"data": {
"orderId": "quote_abc123",
"userId": "usr_abc123",
"side": "yes",
"timestamp": "2026-04-09T18:15:03.000Z"
}
}
| Field | Type | Description |
|---|
orderId | string | The order/quote ID (query API for details) |
userId | string | The user who placed the trade |
side | string | Outcome side: "yes" or "no" |
timestamp | string | When the order was placed |
trades.filled
Fired when a trade order reaches a terminal fill state. One event per venue-level order fill.
{
"id": "evt_trades.filled:ord_abc123",
"type": "trades.filled",
"createdAt": "2026-04-09T18:15:03.000Z",
"data": {
"orderId": "ord_abc123",
"userId": "usr_abc123",
"status": "filled",
"timestamp": "2026-04-09T18:15:03.000Z"
}
}
| Field | Type | Description |
|---|
orderId | string | The individual order ID (query API for fill details) |
userId | string | The user who placed the trade |
status | string | "filled" or "partial_fill" |
timestamp | string | When the fill was recorded |
markets.resolved
Fired once per app when a prediction market resolves. Contains a summary — use the pull endpoint
for the full list of affected users.
{
"id": "evt_markets.resolved:vm_123:app_xyz",
"type": "markets.resolved",
"createdAt": "2026-04-09T18:15:03.000Z",
"data": {
"venueMarketId": "vm_123",
"externalIdentifier": "KXBTC-26APR09",
"status": "resolved",
"outcomes": [
{ "label": "Yes", "winner": true },
{ "label": "No", "winner": false }
],
"affectedUsersCount": 1842,
"detailsPath": "/apps/app_xyz/market-resolutions/vm_123/users"
}
}
| Field | Type | Description |
|---|
venueMarketId | string | The resolved market ID |
externalIdentifier | string | Venue-specific market identifier |
status | string | "resolved" or "closed" |
outcomes | array | Resolution outcome for each option |
affectedUsersCount | number | Users in your app with open positions |
detailsPath | string | API path to paginate affected user IDs |
Querying affected users
Use the SDK to paginate through affected users. Pass includeEmails: true to get email addresses
where available.
import { AggAdminClient } from "@agg-market/sdk/server";
const admin = new AggAdminClient({
baseUrl: "https://api.agg.market",
apiKey: process.env.AGG_API_KEY!,
});
// Paginate through all affected users
let cursor: string | undefined;
do {
const page = await admin.listMarketResolutionUsers(
appId,
event.data.venueMarketId,
{ limit: 100, cursor, includeEmails: true },
);
for (const user of page.data) {
console.log(user.userId, user.email);
}
cursor = page.nextCursor ?? undefined;
} while (cursor);
See the List users affected by market resolution
API reference for full details.
This endpoint returns the current set of users with non-zero positions, not an immutable
snapshot at resolution time. If positions are modified after resolution, the results may differ
from the affectedUsersCount in the webhook.