Querying Results
This guide explains how to query referral and affiliate data for end-user and admin experiences, including **response shapes** you can map directly to UI.
Which gateway?
| Audience | Base URL | Auth |
|---|---|---|
| Gamers / end users | Query Gateway | Gamer JWT (user_type: gamer) |
| Admin / back office | Admin Gateway | Zitadel / admin JWT (scopes wallet:read / wallet:write) |
Important: Admin-only routes (create/update/delete campaigns, affiliates, tiers, rules, hierarchy) exist only on the Admin Gateway under /v1/.... Calling them on the Query Gateway returns 404 — that gateway only exposes the gamer routes below.
Overview (gamer — Query Gateway)
Use these to drive in-app referral UI:
- list a user’s referral codes
- list referrals created by a user (as referrer)
- check inbound referral attribution (
my-attribution) - check affiliate account status
- list affiliate commissions
- list affiliate downline
All list endpoints return:
{ "total": <number>, "items": [ ... ] }total is the number of rows in this page (not a global count across the whole dataset).
Query Referral Codes
List referral codes for the authenticated user.
Endpoint (Query Gateway):
GET /v1/referral/codes?limit={limit}&offset={offset}
Authorization: Bearer <GAMER_JWT>200 Response (application/json):
{
"total": 1,
"items": [
{
"id": "417274ca-0e95-4024-a5c8-a3c3eecc6337",
"tenant_id": "phoenix_test_tenant",
"user_id": "3b435312-4359-49da-99b5-b60cc45152c4",
"campaign_id": null,
"code": "RF422C71DF",
"usage_limit": 100,
"usage_count": 0,
"expires_at": null,
"active": true,
"created_at": "2026-03-23T10:42:19.013787Z",
"updated_at": "2026-03-23T10:42:19.013787Z"
}
]
}UI ideas: show code, usage_count / usage_limit, expires_at, active.
Query Referrals Created by User
List referrals where the authenticated user is the referrer.
Endpoint (Query Gateway):
GET /v1/referral/referrals?status={status}&limit={limit}&offset={offset}
Authorization: Bearer <GAMER_JWT>200 Response:
{
"total": 1,
"items": [
{
"id": "b8b6e954-b4d7-4d67-97a1-0d46f2d2aec7",
"tenant_id": "phoenix_test_tenant",
"campaign_id": null,
"code_id": "da0b1cc8-7697-45e7-a8e1-e60aa0b43fb5",
"referrer_id": "3b435312-4359-49da-99b5-b60cc45152c4",
"referee_id": "0a36729d-e460-4e26-9ac9-fce3f1f8c944",
"status": "pending",
"qualified_at": null,
"rewarded_at": null,
"created_at": "2026-03-23T10:33:00.356349Z",
"updated_at": "2026-03-23T10:33:00.356349Z"
}
]
}Statuses: pending, qualified, rewarded, expired, cancelled (see backend validation).
UI ideas: table of referees with status; show qualified_at / rewarded_at when set.
Query My Attribution
Whether the current user was referred (referee side).
Endpoint (Query Gateway):
GET /v1/referral/my-attribution
Authorization: Bearer <GAMER_JWT>200 Response — not referred:
null200 Response — referred:
{
"id": "b8b6e954-b4d7-4d67-97a1-0d46f2d2aec7",
"tenant_id": "phoenix_test_tenant",
"campaign_id": null,
"code_id": "da0b1cc8-7697-45e7-a8e1-e60aa0b43fb5",
"referrer_id": "3b435312-4359-49da-99b5-b60cc45152c4",
"referee_id": "0a36729d-e460-4e26-9ac9-fce3f1f8c944",
"status": "pending",
"qualified_at": null,
"rewarded_at": null,
"created_at": "2026-03-23T10:33:00.356349Z",
"updated_at": "2026-03-23T10:33:00.356349Z"
}UI ideas: if null, show “Apply a code”; if object, show inviter id and progress (status).
Query Affiliate Status
Whether the authenticated user has an affiliate row (Query Gateway — gamer).
Endpoint:
GET /v1/affiliate/status
Authorization: Bearer <GAMER_JWT>200 Response — not an affiliate: typically 400 with an error body (product may treat as “no affiliate”). When the user is an affiliate:
{
"id": "719665df-2932-4f87-92a9-aa8174d139aa",
"tenant_id": "phoenix_test_tenant",
"user_id": "3b435312-4359-49da-99b5-b60cc45152c4",
"affiliate_code": "AFFFE914C5B",
"status": "active",
"tier_id": null,
"parent_affiliate_id": null,
"hierarchy_path": null,
"hierarchy_depth": 0,
"approved_at": "2026-03-23T10:42:25.572608Z",
"suspended_at": null,
"created_at": "2026-03-23T10:42:25.596880Z",
"updated_at": "2026-03-23T10:42:25.596880Z"
}UI ideas: show affiliate_code, status, tier_id, hierarchy fields if you expose MLM UI.
Query Affiliate Commissions
Endpoint:
GET /v1/affiliate/commissions?status={status}&limit={limit}&offset={offset}
Authorization: Bearer <GAMER_JWT>200 Response:
{
"total": 0,
"items": []
}Example item (when present):
{
"id": "2f2d630e-947f-4f53-a113-f8f56fc8a122",
"tenant_id": "phoenix_test_tenant",
"affiliate_id": "719665df-2932-4f87-92a9-aa8174d139aa",
"referee_id": "0a36729d-e460-4e26-9ac9-fce3f1f8c944",
"rule_id": null,
"source_event_id": "evt_12345",
"commission_type": "deposit.completed",
"base_amount": 5000,
"commission_rate": 0.05,
"commission_amount": 250,
"currency_id": "loyalty_points",
"hierarchy_level": 0,
"status": "paid",
"paid_at": "2026-03-23T12:00:00Z",
"created_at": "2026-03-23T11:59:00Z",
"updated_at": "2026-03-23T12:00:00Z"
}UI ideas: ledger table: amount, currency, status, source_event_id, date.
Query Affiliate Downline
Endpoint:
GET /v1/affiliate/downline?limit={limit}&offset={offset}
Authorization: Bearer <GAMER_JWT>200 Response:
{
"total": 0,
"items": []
}Example item:
{
"id": "f8f0d620-6585-4d12-83d5-3077187b9f04",
"tenant_id": "phoenix_test_tenant",
"user_id": "partner_child_001",
"affiliate_code": "CHILD001",
"status": "active",
"tier_id": null,
"parent_affiliate_id": "719665df-2932-4f87-92a9-aa8174d139aa",
"hierarchy_path": "/719665df-2932-4f87-92a9-aa8174d139aa/f8f0d620-6585-4d12-83d5-3077187b9f04/",
"hierarchy_depth": 1,
"approved_at": "2026-03-23T10:00:00Z",
"suspended_at": null,
"created_at": "2026-03-23T09:00:00Z",
"updated_at": "2026-03-23T09:00:00Z"
}Admin API (Admin Gateway)
Use ADMIN_URL + /v1/... + Authorization: Bearer <ADMIN_JWT>.
Super/client admins must pass tenant_id as a query parameter when the token does not carry a tenant.
Referral campaigns
| Method | Path | Notes |
|---|---|---|
| GET | /v1/referral/campaigns?tenant_id=&active=&limit=&offset= | List |
| POST | /v1/referral/campaigns?tenant_id= | Create |
| GET | /v1/referral/campaigns/{campaign_id}?tenant_id= | Detail |
| PUT | /v1/referral/campaigns/{campaign_id} | Replace (same JSON shape as POST, optional tenant_id in body) |
| DELETE | /v1/referral/campaigns/{campaign_id}?tenant_id= | Delete → 204 empty body |
Single campaign JSON (GET/POST/PUT response):
{
"id": "5d8532a6-0ec1-4a0d-9480-cc5b1cf81a2f",
"tenant_id": "phoenix_test_tenant",
"name": "JWT Test Campaign",
"qualifying_event": "deposit.completed",
"qualifying_filter": null,
"referrer_rewards": { "wallet": [{ "currency_id": "loyalty_points", "amount": 10 }] },
"referee_rewards": { "wallet": [{ "currency_id": "loyalty_points", "amount": 5 }] },
"active": true,
"starts_at": null,
"ends_at": null,
"created_at": "2026-03-23T10:42:28.340169Z",
"updated_at": "2026-03-23T10:42:28.340169Z"
}Affiliates
| Method | Path |
|---|---|
| GET | /v1/affiliates?tenant_id=&status=&limit=&offset= |
| POST | /v1/affiliates?tenant_id= |
| GET | /v1/affiliates/{affiliate_id}?tenant_id= |
| PUT | /v1/affiliates/{affiliate_id} |
| DELETE | /v1/affiliates/{affiliate_id}?tenant_id= → 204 |
PUT body: { "affiliate_code": "...", "tier_id": null, "status": "active", "tenant_id": "..." }
Affiliate tiers
| Method | Path |
|---|---|
| GET | /v1/affiliate/tiers?tenant_id=&limit=&offset= |
| POST | /v1/affiliate/tiers?tenant_id= |
| GET | /v1/affiliate/tiers/{tier_id}?tenant_id= |
| PUT | /v1/affiliate/tiers/{tier_id} |
| DELETE | /v1/affiliate/tiers/{tier_id}?tenant_id= → 204 |
Tier JSON:
{
"id": "11111111-1111-1111-1111-111111111111",
"tenant_id": "phoenix_test_tenant",
"name": "Gold",
"commission_rate": 0.05,
"min_referrals": 10,
"min_referee_revenue": 100000,
"priority": 20,
"active": true,
"created_at": "2026-03-23T10:00:00Z",
"updated_at": "2026-03-23T10:00:00Z"
}Commission rules
| Method | Path |
|---|---|
| GET | /v1/affiliate/commission-rules?tenant_id=&event_type=&limit=&offset= (lists active and inactive for admin) |
| POST | /v1/affiliate/commission-rules?tenant_id= |
| GET | /v1/affiliate/commission-rules/{rule_id}?tenant_id= |
| PUT | /v1/affiliate/commission-rules/{rule_id} |
| DELETE | /v1/affiliate/commission-rules/{rule_id}?tenant_id= → 204 |
Rule JSON:
{
"id": "22222222-2222-2222-2222-222222222222",
"tenant_id": "phoenix_test_tenant",
"name": "Deposit Commission",
"event_type": "deposit.completed",
"event_filter": null,
"commission_field": "amount",
"use_tier_rate": true,
"custom_rate": null,
"currency_id": "loyalty_points",
"active": true,
"created_at": "2026-03-23T10:00:00Z",
"updated_at": "2026-03-23T10:00:00Z"
}Affiliate hierarchy (REST)
Tenant policy (singleton) — prefer canonical paths:
| Method | Path | Notes |
|---|---|---|
| GET | /v1/affiliate/hierarchy?tenant_id= | 404 until first PUT |
| PUT | /v1/affiliate/hierarchy?tenant_id= | Idempotent upsert (first PUT creates the row) |
Deprecated alias: GET / PUT /v1/affiliate/hierarchy-config?tenant_id= — same behavior.
Response:
{
"id": "33333333-3333-3333-3333-333333333333",
"tenant_id": "phoenix_test_tenant",
"max_depth": 3,
"level_rates": [0.05, 0.02, 0.01],
"active": true,
"created_at": "2026-03-23T10:00:00Z",
"updated_at": "2026-03-23T10:00:00Z"
}Upline link (sub-resource on an affiliate):
| Method | Path | Notes |
|---|---|---|
| PUT | /v1/affiliates/{affiliate_id}/hierarchy?tenant_id= | Body: { "parent_affiliate_id": "<uuid>" | null } → 200 |
| DELETE | /v1/affiliates/{affiliate_id}/hierarchy?tenant_id= | Clear upline → 204 |
Deprecated alias: PUT /v1/affiliates/{affiliate_id}/parent?tenant_id= — same JSON body.
Downline (collection):
| Method | Path |
|---|---|
| GET | /v1/affiliates/{affiliate_id}/downline?tenant_id=&limit=&offset= |
See Creating Referrals — Affiliate hierarchy.
Other (unchanged)
GET /v1/referral/referrals?tenant_id=&status=&limit=&offset=Troubleshooting 404
- Wrong host — Admin CRUD only on Admin Gateway, not Query Gateway.
- Wrong path — Must be exactly
/v1/referral/...or/v1/affiliate/...(leading/v1required). - Missing
tenant_id— For super/client admin tokens, add?tenant_id=<id>to the URL. - Detail routes — Use the id path segments added above (
/campaigns/{id},/affiliates/{id}, etc.).
Best Practices
- Use pagination for all list screens (
limit/offset). - Apply status filters in commission and referral dashboards.
- Refresh referral attribution after code application.
- Show clear state labels (
pending,qualified,rewarded). - Cache list responses briefly for UX performance.
Next Steps
- Creating Referral Programs - Learn how to set up referral systems
- Referral Overview - Understand the referral system
Creating Referral Programs
This guide explains how to set up and create referral data from client integrations.
Guides and Tutorials
This document provides a quick start guide and best-practice reference for integrating with the Phoenix Gamification Ingestion Gateway. It outlines essential security principles, performance recommendations, and reliability patterns to help you build safe, efficient, and fault-tolerant event ingestion workflows.