Overview
When an AI agent discovers your listing through Hub and the interaction results in a completed transaction, ezForge records a referral linking the discovery event to the transaction. Listing owners can view their referral history, track commission amounts, and dispute any attributed commission through these endpoints.
Referral commission tracking requires a transaction-capable MCP server (bookings, orders, or purchases). All listing tiers (Basic, Featured, Premium) generate commissions. Ready servers receive referral token integration automatically.
Commission rates
| Transaction type | Rate | Cap |
|---|
| Booking | 1% of transaction amount | $50 |
| Order | 1.5% of transaction amount | $50 |
| Quote | $2.00 flat | — |
| Custom | 0.5% of transaction amount | $50 |
Basic listing owners receive a commission-free ramp on the first $500/month of transaction volume. Featured and Premium listings do not receive this ramp.
Referral lifecycle
| Status | Meaning |
|---|
pending | Token generated; awaiting transaction attribution (24-hour window) |
attributed | Transaction matched; commission calculated but not yet collected |
paid | Commission collected via Stripe Connect |
expired | No transaction attributed within 24 hours |
disputed | Listing owner has disputed the attributed commission |
Authentication: All referral endpoints require session authentication (dashboard login). Hub API key auth is not supported.
Rate limits:
| Operation | Tier | Limit |
|---|
GET /api/v1/hub/referrals | free | Standard per-IP rate limit |
POST /api/v1/hub/referrals/:id/dispute | free | Standard per-IP rate limit |
List referral history
GET /api/v1/hub/referrals
Returns a cursor-paginated list of referrals for all Hub listings owned by the authenticated user, ordered by referral ID ascending (chronological). All listing tiers generate commissions; Basic listings receive a commission-free ramp on the first $500/month of facilitated volume (see commission rates above).
Authentication: Session cookie (dashboard login).
Query parameters:
| Parameter | Type | Default | Description |
|---|
limit | integer | 20 | Max items to return (1–100) |
cursor | string | — | Opaque cursor from a previous response meta.cursor |
Response 200:
{
"data": [
{
"id": "01J9Z3K2M4N5P6Q7R8S9T0U1V2",
"referralToken": "hub_ref_01J9Z3K2M4N5P6Q7R8S9T0U1V2",
"listingId": "01J9Z3K2M4N5P6Q7R8S9T0U1V3",
"apiKeyId": "01J9Z3K2M4N5P6Q7R8S9T0U1V4",
"querySnapshot": { "q": "plumber detroit", "vertical": "plumbing" },
"discoveredAt": "2026-04-20T14:00:00Z",
"expiresAt": "2026-04-21T14:00:00Z",
"transactionId": "pi_3OxyzABC123",
"transactionAmount": 15000,
"commissionAmount": 150,
"commissionRate": "1%",
"status": "attributed",
"attributedAt": "2026-04-20T16:30:00Z"
}
],
"meta": {
"hasMore": true,
"cursor": "MDFKOVozSzJNNE41UDZRN1I4UzlUMFUxVjI"
}
}
Response fields:
| Field | Type | Description |
|---|
id | string | Referral record ID (ULID) |
referralToken | string | Token embedded in search results (hub_ref_{ulid}) |
listingId | string | Hub listing ID that generated this referral |
apiKeyId | string | Hub API key used by the discovering agent |
querySnapshot | object | Search query context that produced this referral |
discoveredAt | string (ISO 8601) | When the agent discovered the listing |
expiresAt | string (ISO 8601) | Attribution window expiry (24 hours after discovery) |
transactionId | string | null | Stripe PaymentIntent ID, once attributed |
transactionAmount | integer | null | Transaction amount in cents |
commissionAmount | integer | null | Commission owed in cents |
commissionRate | string | null | Human-readable rate label (e.g. "1%", "flat $2") |
status | string | Referral status: pending, attributed, paid, expired, or disputed |
attributedAt | string | null | When the transaction was attributed to this referral |
Errors:
| Code | Description |
|---|
401 | Not authenticated |
429 | Rate limit exceeded |
Dispute a commission
POST /api/v1/hub/referrals/:id/dispute
Flags an attributed referral for manual review by the ezForge team. Only the listing owner may dispute, and only referrals in attributed status can be disputed — referrals that are already paid, expired, or disputed will return an error.
Authentication: Session cookie (dashboard login).
Path parameters:
| Parameter | Description |
|---|
id | Referral ID (ULID) from GET /api/v1/hub/referrals |
Request body: None required.
Response 200:
{
"data": {
"id": "01J9Z3K2M4N5P6Q7R8S9T0U1V2",
"referralToken": "hub_ref_01J9Z3K2M4N5P6Q7R8S9T0U1V2",
"listingId": "01J9Z3K2M4N5P6Q7R8S9T0U1V3",
"apiKeyId": "01J9Z3K2M4N5P6Q7R8S9T0U1V4",
"querySnapshot": { "q": "plumber detroit", "vertical": "plumbing" },
"discoveredAt": "2026-04-20T14:00:00Z",
"expiresAt": "2026-04-21T14:00:00Z",
"transactionId": "pi_3OxyzABC123",
"transactionAmount": 15000,
"commissionAmount": 150,
"commissionRate": "1%",
"status": "disputed",
"attributedAt": "2026-04-20T16:30:00Z"
}
}
Errors:
| Code | Description |
|---|
401 | Not authenticated |
404 | Referral not found or not owned by the authenticated user |
409 | Referral is not in attributed status (e.g. already paid, expired, or disputed) |
429 | Rate limit exceeded |
Using referral tokens
Referral tokens (hub_ref_{ulid}) are automatically included in Hub search results and listing detail responses when accessed via a Hub API key. Pass the token from your agent’s transaction context to the Stripe PaymentIntent metadata field hub_referral_id to trigger attribution.
{
"metadata": {
"hub_referral_id": "hub_ref_01J9Z3K2M4N5P6Q7R8S9T0U1V2"
}
}
ezForge listens for payment_intent.succeeded webhooks and automatically matches the token, computes the commission, and updates the referral status. No additional integration is required for Ready servers — referral token injection is handled automatically.
See Analytics for commission tracking within the Hub dashboard.