# Referral

> Share a link, earn credits when the accounts you refer pay. Generated from the API contract.

## GET `/r/{code}`

A referral link.

Added by MEG-237. No key. A 302, never an error body: a bad code
redirects without a ref_token. A 404 with no body when this server
has no landing page configured. Counts one click and redirects to the
landing page with ?ref_token=<signed token> and ?campaign= when
campaign is valid. to=/buy redirects to the dashboard's /buy page
instead, which sends the token with the checkout once you are signed
in. The token is good for 60 days. Only the account's first paid
purchase binds it. We store no IP, user agent, Referer,
URL or cookie; a click is a counter. An ad-click id (gclid, gbraid,
wbraid, dclid, msclkid, fbclid, ttclid, twclid, li_fat_id) marks the
click as paid, and a paid click never earns. Only its presence is
read, never its value.

### Parameters

| name | in | required | type or values | what it is |
| -- | -- | -- | -- | -- |
| `code` | path | yes | string | 8 characters of a-z and 0-9. |
| `to` | query | no | string; default `/` | A page of ours to land on. Allowed are /, /pricing, /docs/*, /guides/scrape-* and /board. Anything else lands on /. |
| `campaign` | query | no | string | 1 to 64 of a-z, 0-9 and -. Passed on to the landing page. A wrong value is dropped. |


### Answers

| status | what it means |
| -- | -- |
| `302` | To the landing page. Cache-Control: no-store, Referrer-Policy: no-referrer. |
| `404` | Referral links are off on this server (no landing page configured). No body. |


## GET `/v1/account/affiliate`

Your referral status, codes, terms and earnings.

Added by MEG-237. Owner only.

### Answers

| status | what it means |
| -- | -- |
| `200` | Your affiliate record. |
| `401` | bad_token. The key is missing, not valid, expired, revoked, of an unknown prefix or wrong length, or sent as the api_key query parameter, which no route accepts. |
| `403` | wrong_scope (a scrape key on a route that needs an account key, or an account key on a scraping or batches route) or owner_only (your role is member). |
| `404` | not_enrolled. This account has not joined the referral program. Join with POST /v1/account/affiliate. |
| `429` | rate_limited. Too many requests to this endpoint right now. Wait Retry-After seconds, then send the same request again. |
| `500` | internal. Our bug. Try again in a minute; if it stays, report the X-Request-Id. |
| `503` | busy. A store we need did not answer, or is not configured on this server. Send the same request again after the Retry-After seconds. |


## POST `/v1/account/affiliate`

Join the referral program.

Added by MEG-237. Owner only, for an account with at least one paid
purchase that was not refunded or disputed. Makes your first code.
Sending it again changes nothing and answers 200 with what you have.
The body is {}.

### Body



### Answers

| status | what it means |
| -- | -- |
| `200` | Already joined. The same body as GET. |
| `201` | Joined. |
| `400` | bad_parameter: a field is missing, wrong, or not one this request takes; error.field names it. bad_request: the body is not one JSON object. |
| `401` | bad_token. The key is missing, not valid, expired, revoked, of an unknown prefix or wrong length, or sent as the api_key query parameter, which no route accepts. |
| `403` | wrong_scope, owner_only, or not_eligible (no paid purchase yet that was not refunded or disputed). |
| `413` | body_too_large. The body was larger than 4 KiB. |
| `415` | unsupported_media_type. Send Content-Type: application/json, even for an empty {} body. |
| `429` | rate_limited. Too many requests to this endpoint right now. Wait Retry-After seconds, then send the same request again. |
| `500` | internal. Our bug. Try again in a minute; if it stays, report the X-Request-Id. |
| `503` | busy. A store we need did not answer, or is not configured on this server. Send the same request again after the Retry-After seconds. |


## POST `/v1/account/affiliate/codes`

Make another referral code.

Added by MEG-237. Owner only. At most 5 codes. A code is never
deleted and never reused. The body is {}.

### Body



### Answers

| status | what it means |
| -- | -- |
| `201` | The new code. |
| `400` | bad_parameter: a field is missing, wrong, or not one this request takes; error.field names it. bad_request: the body is not one JSON object. |
| `401` | bad_token. The key is missing, not valid, expired, revoked, of an unknown prefix or wrong length, or sent as the api_key query parameter, which no route accepts. |
| `402` | over_plan. You already have 5 codes. |
| `403` | wrong_scope (a scrape key on a route that needs an account key, or an account key on a scraping or batches route) or owner_only (your role is member). |
| `404` | not_enrolled. This account has not joined the referral program. Join with POST /v1/account/affiliate. |
| `413` | body_too_large. The body was larger than 4 KiB. |
| `415` | unsupported_media_type. Send Content-Type: application/json, even for an empty {} body. |
| `429` | rate_limited. Too many requests to this endpoint right now. Wait Retry-After seconds, then send the same request again. |
| `500` | internal. Our bug. Try again in a minute; if it stays, report the X-Request-Id. |
| `503` | busy. A store we need did not answer, or is not configured on this server. Send the same request again after the Retry-After seconds. |


## GET `/v1/account/affiliate/stats`

Clicks, referrals and earnings per month.

Added by MEG-237. Owner only. Newest month first. Never names or ids of the accounts you referred.

### Parameters

| name | in | required | type or values | what it is |
| -- | -- | -- | -- | -- |
| `months` | query | no | integer, 1 to 12; default `6` | How many calendar months back, 1 to 12, the current one included. |


### Answers

| status | what it means |
| -- | -- |
| `200` | The months. |
| `400` | bad_parameter. error.field names the parameter; the message says which values work. An unknown query key is this 400 too. |
| `401` | bad_token. The key is missing, not valid, expired, revoked, of an unknown prefix or wrong length, or sent as the api_key query parameter, which no route accepts. |
| `403` | wrong_scope (a scrape key on a route that needs an account key, or an account key on a scraping or batches route) or owner_only (your role is member). |
| `404` | not_enrolled. This account has not joined the referral program. Join with POST /v1/account/affiliate. |
| `429` | rate_limited. Too many requests to this endpoint right now. Wait Retry-After seconds, then send the same request again. |
| `500` | internal. Our bug. Try again in a minute; if it stays, report the X-Request-Id. |
| `503` | busy. A store we need did not answer, or is not configured on this server. Send the same request again after the Retry-After seconds. |
