Reference
REST API
Every v1 endpoint, its parameters and its scope.
Base URL https://referralmeter.com. Authenticate with a secret key: Authorization: Bearer sk_…. Create keys on Install & verify or in Settings; a key is read-only unless it has the write scope. The machine-readable description is openapi.json.
- Amounts are integer cents with an ISO currency.
- Lists are newest first with cursor pagination:
limit(1–100, default 50) andcursor(the previous page'snext_cursor). - Errors look like
{"error":{"code":"…","message":"…"}}: 400 invalid input, 401 bad key, 403 read-only key, 404 not in your program, 429 over 600 requests a minute. - Every write is recorded in your program's audit log with the key that made it.
- No endpoint moves money or marks a payout as paid.
Get the program
GET /api/v1/program · read scope
Name, public key, portal URL and the commission rules in force.
curl https://referralmeter.com/api/v1/program \
-H "Authorization: Bearer $REFERRALMETER_SECRET_KEY"Response:
{
"id": "…",
"name": "Acme AI",
"slug": "acme",
"public_key": "pk_…",
"currency": "usd",
"commission": {
"type": "percent",
"value": 30,
"duration": "months",
"months": 12,
"hold_days": 30
}
}Update commission rules and portal text
PATCH /api/v1/program · write scope
Send only the fields you change. Changes apply to commissions earned from now on; existing commissions keep their amount.
| Field | In | Type |
|---|---|---|
commission_type | body | percent, flat |
commission_value | body | number, 0–100000 |
commission_duration | body | once, months, lifetime |
commission_months | body | integer, 1–120 |
pay_on_one_time | body | boolean |
pay_on_usage | body | boolean |
attribution_days | body | integer, 1–365 |
attribution_model | body | first, last |
hold_days | body | integer, 0–120 |
min_payout_cents | body | integer, 0–100000000 |
approval_threshold_cents | body | integer, 0–100000000 or null |
auto_approve_affiliates | body | boolean |
portal_headline | body | string or null |
portal_body | body | string or null |
terms_url | body | string (uri) or null |
curl -X PATCH https://referralmeter.com/api/v1/program \
-H "Authorization: Bearer $REFERRALMETER_SECRET_KEY" \
-H "Content-Type: application/json" -d '{"commission_value":25,"commission_duration":"months","commission_months":12,"portal_headline":"Earn 25% for a year"}'List affiliates
GET /api/v1/affiliates · read scope
Newest first. Verification test affiliates are hidden unless include_test=true.
| Field | In | Type |
|---|---|---|
limit | query | integer, 1–100, default 50 |
cursor | query | string |
status | query | pending, approved, rejected, banned |
q | query | string |
include_test | query | boolean or 0, 1, true, false |
curl https://referralmeter.com/api/v1/affiliates \
-H "Authorization: Bearer $REFERRALMETER_SECRET_KEY"Response:
{
"data": [
{
"id": "8d0f7c1e-2a7b-4c55-9d1e-3b4a5c6d7e8f",
"email": "maya@example.com",
"name": "Maya Chen",
"code": "maya",
"status": "approved",
"referral_link": "https://referralmeter.com/go/acme/maya",
"commission_override": null,
"clicks": 412,
"customers": 9,
"earned_cents": 13230,
"currency": "usd"
}
],
"next_cursor": null
}Add an affiliate
POST /api/v1/affiliates · write scope
Creates an affiliate directly (no application). Omit code and one is derived from the name.
| Field | In | Type |
|---|---|---|
email * | body | string (email) |
name | body | string, default `` |
code | body | string |
status | body | approved, pending, default approved |
notes | body | string |
commission_type | body | percent, flat or null |
commission_value | body | number, 0–100000 or null |
curl -X POST https://referralmeter.com/api/v1/affiliates \
-H "Authorization: Bearer $REFERRALMETER_SECRET_KEY" \
-H "Content-Type: application/json" -d '{"email":"maya@example.com","name":"Maya Chen","code":"maya"}'Response:
{
"id": "8d0f7c1e-2a7b-4c55-9d1e-3b4a5c6d7e8f",
"email": "maya@example.com",
"name": "Maya Chen",
"code": "maya",
"status": "approved",
"referral_link": "https://referralmeter.com/go/acme/maya",
"commission_override": null,
"clicks": 412,
"customers": 9,
"earned_cents": 13230,
"currency": "usd"
}Get an affiliate
GET /api/v1/affiliates/{id} · read scope
One affiliate with clicks, paying customers and commission earned.
| Field | In | Type |
|---|---|---|
id | path | Affiliate id |
curl https://referralmeter.com/api/v1/affiliates/<id> \
-H "Authorization: Bearer $REFERRALMETER_SECRET_KEY"Response:
{
"id": "8d0f7c1e-2a7b-4c55-9d1e-3b4a5c6d7e8f",
"email": "maya@example.com",
"name": "Maya Chen",
"code": "maya",
"status": "approved",
"referral_link": "https://referralmeter.com/go/acme/maya",
"commission_override": null,
"clicks": 412,
"customers": 9,
"earned_cents": 13230,
"currency": "usd"
}Approve, reject or ban; set a commission override; edit notes
PATCH /api/v1/affiliates/{id} · write scope
status: approved | pending | rejected | banned. Set commission_type and commission_value together, or both to null to fall back to the program rule.
| Field | In | Type |
|---|---|---|
id | path | Affiliate id |
status | body | approved, pending, rejected, banned |
notes | body | string or null |
commission_type | body | percent, flat or null |
commission_value | body | number, 0–100000 or null |
curl -X PATCH https://referralmeter.com/api/v1/affiliates/<id> \
-H "Authorization: Bearer $REFERRALMETER_SECRET_KEY" \
-H "Content-Type: application/json" -d '{"status":"approved","commission_type":"percent","commission_value":40}'List commissions
GET /api/v1/commissions · read scope
Newest first. Reversals (refunds, disputes) are rows with a negative amount and reversal_of set. Test commissions are hidden unless include_test=true.
| Field | In | Type |
|---|---|---|
limit | query | integer, 1–100, default 50 |
cursor | query | string |
status | query | pending, needs_approval, approved, paid, reversed, rejected |
affiliate_id | query | string (uuid) |
since | query | string (date-time) or string (date) |
include_test | query | boolean or 0, 1, true, false |
curl https://referralmeter.com/api/v1/commissions \
-H "Authorization: Bearer $REFERRALMETER_SECRET_KEY"Response:
{
"data": [
{
"id": "…",
"affiliate_code": "maya",
"amount_cents": 1470,
"base_amount_cents": 4900,
"currency": "usd",
"rate_label": "30% · month 1 of 12",
"status": "pending",
"hold_until": "2026-12-03T14:01:31Z"
}
],
"next_cursor": null
}List referred customers
GET /api/v1/customers · read scope
Every referral: leads (signed up) and customers (paid), with the affiliate who brought them and revenue so far.
| Field | In | Type |
|---|---|---|
limit | query | integer, 1–100, default 50 |
cursor | query | string |
status | query | lead, customer, refunded, canceled |
affiliate_id | query | string (uuid) |
include_test | query | boolean or 0, 1, true, false |
curl https://referralmeter.com/api/v1/customers \
-H "Authorization: Bearer $REFERRALMETER_SECRET_KEY"Program stats
GET /api/v1/stats · read scope
Live traffic only (test payments and verification runs are excluded). Revenue and commissions are in the program currency.
| Field | In | Type |
|---|---|---|
days | query | integer, 1–365, default 30 |
curl https://referralmeter.com/api/v1/stats \
-H "Authorization: Bearer $REFERRALMETER_SECRET_KEY"Response:
{
"days": 30,
"currency": "usd",
"revenue_cents": 418000,
"commissions_owed_cents": 125400,
"clicks": 3120,
"leads": 211,
"customers": 38,
"active_affiliates": 7,
"ai_customers": 5
}Start an install verification
POST /api/v1/verifications · write scope
Creates a test affiliate and returns a test link. Open it, sign up, pay in test mode; poll GET /api/v1/verifications/{id} until status is passed. A running run is reused; runs expire after 24 hours.
curl -X POST https://referralmeter.com/api/v1/verifications \
-H "Authorization: Bearer $REFERRALMETER_SECRET_KEY"Response:
{
"id": "…",
"publicId": "Qm3x…",
"status": "running",
"testLink": "https://acme.ai/?via=verify-k3m9tq",
"next": "Waiting for: affiliate click recorded. …",
"certificate_url": "https://referralmeter.com/verify/Qm3x…"
}Get a verification run
GET /api/v1/verifications/{id} · read scope
Each step with its timestamp, a plain-English hint for the step it is waiting on, and diagnostics from your data (e.g. a payment that arrived without a referral). Use latest as the id for the newest run.
| Field | In | Type |
|---|---|---|
id | path | Run id, or latest |
curl https://referralmeter.com/api/v1/verifications/<id> \
-H "Authorization: Bearer $REFERRALMETER_SECRET_KEY"What you owe, per affiliate
GET /api/v1/payouts/due · read scope
Approved, unpaid live commissions grouped by affiliate and currency. Read-only: no API creates a payout batch or marks money as sent.
curl https://referralmeter.com/api/v1/payouts/due \
-H "Authorization: Bearer $REFERRALMETER_SECRET_KEY"Response:
{
"data": [
{
"affiliate_id": "…",
"email": "maya@example.com",
"currency": "usd",
"amount_cents": 13230,
"commissions": 9,
"meets_minimum": true
}
],
"min_payout_cents": 5000
}Record a sale (server-side)
POST /api/v1/track/sale · write scope
For billing we don't connect to natively. Idempotent on event_id. Returns 201 with the outcome and commission_cents, or 200 for a duplicate.
| Field | In | Type |
|---|---|---|
event_id * | body | string — Your unique id for this payment. Re-sending the same id is a no-op. |
payment_id | body | string — The id a later refund will name. Defaults to event_id. |
amount * | body | integer — Amount in minor units (cents). |
currency * | body | string — ISO 4217 code, e.g. usd. |
customer_id | body | string — Your billing customer id. Later sales for the same customer attribute to the same affiliate. |
customer_email | body | string (email) |
customer_external_id | body | string — Your own user id (the uid you passed to referralmeter.signup). |
referral | body | string — The value of referralmeter.ref() (click id) or an affiliate code. |
coupon | body | string — Coupon code used, if it belongs to an affiliate. |
kind | body | subscription, one_time, credits, usage, default subscription |
livemode | body | boolean, default true — false for test payments: recorded, never paid out. |
occurred_at | body | string (date-time) |
curl -X POST https://referralmeter.com/api/v1/track/sale \
-H "Authorization: Bearer $REFERRALMETER_SECRET_KEY" \
-H "Content-Type: application/json" -d '{"event_id":"pay_123","amount":4900,"currency":"usd","customer_external_id":"user_42","referral":"<referralmeter.ref()>","kind":"subscription"}'Record a refund
POST /api/v1/track/refund · write scope
Claws the commission back in proportion to the refunded amount.
| Field | In | Type |
|---|---|---|
event_id * | body | string — Your unique id for this refund. |
payment_id * | body | string — The payment_id (or event_id) of the sale being refunded. |
amount * | body | integer — Refunded amount in cents. Partial refunds claw back proportionally. |
currency | body | string — Defaults to the program currency. |
livemode | body | boolean, default true |
curl -X POST https://referralmeter.com/api/v1/track/refund \
-H "Authorization: Bearer $REFERRALMETER_SECRET_KEY" \
-H "Content-Type: application/json" -d '{"event_id":"ref_9","payment_id":"pay_123","amount":4900}'Record a signup (server-side)
POST /api/v1/referrals · write scope
The server-side twin of referralmeter.signup(): attributes a new user to the click or affiliate code in referral.
| Field | In | Type |
|---|---|---|
email * | body | string (email) — The new user's email. |
external_id | body | string — Your own user id. |
referral * | body | string — referralmeter.ref() from the browser (click id) or an affiliate code. |
ip | body | string — The visitor's IP, so self-referral checks still work server-side. |
curl -X POST https://referralmeter.com/api/v1/referrals \
-H "Authorization: Bearer $REFERRALMETER_SECRET_KEY" \
-H "Content-Type: application/json" -d '{"email":"new.user@example.com","external_id":"user_42","referral":"<referralmeter.ref()>"}'