curl --request GET \
--url https://api.goyappr.com/affiliates/stats \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.goyappr.com/affiliates/stats"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.goyappr.com/affiliates/stats', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.goyappr.com/affiliates/stats",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.goyappr.com/affiliates/stats"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.goyappr.com/affiliates/stats")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.goyappr.com/affiliates/stats")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"ref_code": "AB12CD34",
"commission_rate_pct": 10,
"override_rate_pct": 2.5,
"hold_days": 30,
"months_window_months": 12,
"summary": {
"clients_invited": 123,
"sub_affiliates": 123,
"referred_revenue_cents": 123,
"override_revenue_cents": 123,
"earned_cents": 123,
"direct_earned_cents": 123,
"override_earned_cents": 123,
"payable_cents": 123,
"paid_cents": 123,
"outstanding_cents": 123,
"earned_before_window_cents": 123
},
"months": [
{
"month": "2026-07",
"clients_invited": 123,
"referred_revenue_cents": 123,
"commission_cents": 123,
"direct_commission_cents": 123,
"override_commission_cents": 123,
"payable_commission_cents": 123,
"payout_sent_cents": 123
}
]
}{
"error": "<string>",
"code": "<string>"
}{
"error": "<string>",
"code": "<string>"
}{
"error": "<string>",
"code": "<string>"
}Affiliate stats
Your referral code, your commission rates, lifetime totals, and a trailing
month-by-month breakdown. Always scoped to the API key’s own workspace —
there is no path, query or body parameter for a company id, and supplying
company_id returns 400. Required scope affiliates:read.
Money is integer US cents. Every *_cents field, including
payout_sent_cents, is denominated in US cents no matter which currency a
payout was actually wired in. Divide by 100 for dollars.
Earned vs payable. earned_cents is everything you have accrued.
payable_cents is the part that has aged past hold_days and is claimable
now; it is the number payouts are drawn from. outstanding_cents is
payable_cents - paid_cents and may be negative when you have been paid
ahead of the hold window — that is a real state, not an error.
Reconciliation. earned_before_window_cents plus the sum of
months[].commission_cents equals summary.earned_cents exactly, so the
table on screen can always be made to add up to the lifetime total.
curl --request GET \
--url https://api.goyappr.com/affiliates/stats \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.goyappr.com/affiliates/stats"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.goyappr.com/affiliates/stats', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.goyappr.com/affiliates/stats",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.goyappr.com/affiliates/stats"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.goyappr.com/affiliates/stats")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.goyappr.com/affiliates/stats")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"ref_code": "AB12CD34",
"commission_rate_pct": 10,
"override_rate_pct": 2.5,
"hold_days": 30,
"months_window_months": 12,
"summary": {
"clients_invited": 123,
"sub_affiliates": 123,
"referred_revenue_cents": 123,
"override_revenue_cents": 123,
"earned_cents": 123,
"direct_earned_cents": 123,
"override_earned_cents": 123,
"payable_cents": 123,
"paid_cents": 123,
"outstanding_cents": 123,
"earned_before_window_cents": 123
},
"months": [
{
"month": "2026-07",
"clients_invited": 123,
"referred_revenue_cents": 123,
"commission_cents": 123,
"direct_commission_cents": 123,
"override_commission_cents": 123,
"payable_commission_cents": 123,
"payout_sent_cents": 123
}
]
}{
"error": "<string>",
"code": "<string>"
}{
"error": "<string>",
"code": "<string>"
}{
"error": "<string>",
"code": "<string>"
}affiliates:read.
Scoping
This endpoint always reports on the workspace that issued the API key. There is no path, query or body parameter for a company id, and passingcompany_id returns 400 rather than silently reporting your own numbers back to you. To read a different workspace’s affiliate stats, use a key issued by that workspace.
Query parameters
| Parameter | Type | Default | Notes |
|---|---|---|---|
months | integer | 12 | How many trailing months months[] covers, 1–60. Does not affect summary, which is always lifetime. |
Money is integer US cents
Every field ending in_cents is a whole number of US cents. Divide by 100 for dollars; never parse it as a decimal. That includes payout_sent_cents and paid_cents — a payout wired in another currency is converted at the rate recorded on that payout and stored in US cents, so the whole payload is one currency.
Earned vs payable — the distinction that matters
| Field | What it is |
|---|---|
earned_cents | Everything you have accrued, from the moment the customer paid. |
payable_cents | The part of earned_cents that has aged past hold_days and is claimable now. |
paid_cents | What has actually been sent to you. |
outstanding_cents | payable_cents - paid_cents. The number you are owed today. |
hold_days have elapsed — that window covers card disputes and refunds, so money that could still be reversed never appears as owed. A recent month therefore reads commission_cents higher than payable_commission_cents; the gap closes on its own as the hold elapses. Nothing is lost.
outstanding_cents can be negative. That means a payout ran ahead of the hold window — you have been paid for commission that has not cleared yet. It is a real state, not an error, and it is deliberately not clamped to zero so an overpayment stays visible. It works itself off as more commission becomes payable. Render it as an “overpaid” state rather than as a negative currency amount.Response fields
| Field | Type | Meaning |
|---|---|---|
ref_code | string | Your referral code. Your link is https://app.goyappr.com/signup?ref=<ref_code>. |
commission_rate_pct | number | Your direct (tier-1) rate today, as a percentage. See Rates are not retroactive. |
override_rate_pct | number | Your override (tier-2) rate on revenue from your sub-affiliates’ customers, today. 0 when you have no tier-2 terms — which is the normal case. |
hold_days | integer | Days a commission ages before becoming payable. 0 means immediately payable. |
months_window_months | integer | Echo of the months parameter. |
summary.clients_invited | integer | Companies that signed up through your link, including ones that have never paid. |
summary.sub_affiliates | integer | Enrolled partners you earn an override through. 0 for most workspaces. Itemised by GET /affiliates/downline. |
summary.referred_revenue_cents | integer | Lifetime tier-1 billed revenue — what your direct referrals paid us. |
summary.override_revenue_cents | integer | Lifetime tier-2 billed revenue — what your sub-affiliates’ customers paid us. |
summary.earned_cents | integer | Lifetime commission, both tiers. Equals direct_earned_cents + override_earned_cents. |
summary.direct_earned_cents | integer | Tier-1 share of earned_cents. |
summary.override_earned_cents | integer | Tier-2 share of earned_cents. |
summary.payable_cents | integer | The part of earned_cents past the hold window. |
summary.paid_cents | integer | Lifetime payouts in US cents. Voided payouts are excluded. |
summary.outstanding_cents | integer | payable_cents - paid_cents. May be negative. |
summary.earned_before_window_cents | integer | Commission earned before the first month in months[]. |
months[] | array | Newest first, months_window_months entries, zero-filled. |
Month rows
| Field | Type | Meaning |
|---|---|---|
month | string | YYYY-MM. |
clients_invited | integer | Signups through your link that month. |
referred_revenue_cents | integer | Tier-1 billed revenue that month. |
commission_cents | integer | Commission earned that month, both tiers. |
direct_commission_cents | integer | Tier-1 share. |
override_commission_cents | integer | Tier-2 share. |
payable_commission_cents | integer | The part past the hold window. Lower than commission_cents for recent months. |
payout_sent_cents | integer | Payouts recorded against that month, in US cents. |
*_cents field in a month row can be negative. A refund or chargeback is booked in the month it happens, and it reverses the commission at the rate that applied when the customer originally paid — so a month with more refunds than sales reads negative. The summary totals already account for it. Do not clamp these to zero; a table that hides a reversal will not add up to earned_cents.Rates are not retroactive
commission_rate_pct and override_rate_pct are the rates in force today. Each commission was priced at the rate in force on the day that customer paid, and a later rate change never re-prices what you already earned — up or down.
So this does not hold, and you should not present it as if it did:
referred_revenue_cents * commission_rate_pct / 100 ≠ direct_earned_cents
direct_earned_cents and override_earned_cents are the authoritative figures; the rate fields tell you what the next dollar earns.
For the same reason, the per-line rounding is done at the (customer, month) grain, so sum(months[].commission_cents) can differ by a cent or two from a rate applied to a lifetime revenue total. The reconciliation identity below is the one that always holds.
Reconciling the table to the lifetime total
summary is lifetime and unbounded; months[] is a trailing window. They differ, and the payload tells you by exactly how much:
earned_before_window_cents + sum(months[].commission_cents) == summary.earned_cents
earned_before_window_cents as an “Earlier” row and your table always adds up. Widen the window with months if you want the older months itemised.
Example request
curl "https://api.goyappr.com/affiliates/stats?months=2" \
-H "Authorization: Bearer $YAPPR_API_KEY"
Example response
Read on 2026-09-15, for an affiliate on 10% direct, 2.5% override, 30-day hold, whose rates have never changed — which is why revenue times rate happens to reproduce the earned figures here. Do not rely on that in general; see Rates are not retroactive.{
"ref_code": "AB12CD34",
"commission_rate_pct": 10,
"override_rate_pct": 2.5,
"hold_days": 30,
"months_window_months": 2,
"summary": {
"clients_invited": 3,
"sub_affiliates": 1,
"referred_revenue_cents": 26500,
"override_revenue_cents": 40000,
"earned_cents": 3650,
"direct_earned_cents": 2650,
"override_earned_cents": 1000,
"payable_cents": 1450,
"paid_cents": 700,
"outstanding_cents": 750,
"earned_before_window_cents": 1450
},
"months": [
{
"month": "2026-09",
"clients_invited": 0,
"referred_revenue_cents": 12000,
"commission_cents": 2200,
"direct_commission_cents": 1200,
"override_commission_cents": 1000,
"payable_commission_cents": 0,
"payout_sent_cents": 0
},
{
"month": "2026-08",
"clients_invited": 1,
"referred_revenue_cents": 0,
"commission_cents": 0,
"direct_commission_cents": 0,
"override_commission_cents": 0,
"payable_commission_cents": 0,
"payout_sent_cents": 700
}
]
}
earned_cents is 3,650¢, but all 2,200¢ of it earned in September — a 1,200¢ direct commission and a 1,000¢ override — is younger than the 30-day hold, so payable_commission_cents is 0 for that month and payable_cents is only the 1,450¢ accrued before the window. 700¢ of that has been paid, so the amount actually owed today is outstanding_cents = 750¢. Come 2026-10-05 the September lines age past the hold and payable_cents jumps to 3,650¢ with no new revenue at all.
The reconciliation also holds: earned_before_window_cents (1,450) + 2200 + 0 = earned_cents (3,650).
Errors
| HTTP | Code | When |
|---|---|---|
| 400 | — | months is not an integer 1–60, or a company_id parameter was supplied. |
| 401 | INSUFFICIENT_SCOPE | API key lacks affiliates:read. |
| 401 | INVALID_KEY | Key not found, revoked, or expired. |
| 403 | AFFILIATE_FORBIDDEN | Affiliate data is not readable for this workspace. |
| 429 | RATE_LIMIT | 60 requests/minute exceeded. |
| 500 | — | The figures could not be computed. Safe to retry. |
Authorizations
Your Yappr API key (e.g. ypr_live_...). Generate one in the dashboard under Settings → API Keys.
Query Parameters
How many trailing months months[] should cover. Does not affect summary, which is lifetime.
1 <= x <= 60Response
Affiliate stats
Affiliate commission summary for the API key's own workspace. All money is integer US cents — divide by 100 for dollars, never parse as a float.
Your referral code. Your link is https://app.goyappr.com/signup?ref=<ref_code>.
"AB12CD34"
Your direct (tier-1) commission rate as a percentage, as it stands today. Every past commission was priced at the rate in force on the day that customer paid, so after a rate change referred_revenue_cents * commission_rate_pct will NOT reproduce direct_earned_cents. Use it to say what new revenue will earn — never to re-derive history.
10
Your override (tier-2) rate on revenue from your sub-affiliates' customers, as it stands today. 0 when you have no tier-2 terms. Same caveat as commission_rate_pct: it does not re-derive override_earned_cents.
2.5
Days a commission must age before it becomes payable. Covers the card-dispute window. 0 means commission is payable as soon as it is earned.
30
How many trailing months months[] covers — echoes the months query parameter.
12
Lifetime totals. Unbounded — not limited to months_window_months.
Show child attributes
Show child attributes
Newest month first, months_window_months entries, zero-filled for months with no activity.
Show child attributes
Show child attributes