# Get referral programs

List the referral programs set up in the community that owns your API key, with each stage's requirements and rewards.

- Endpoint: `GET https://api.returning.ai/v1/referral/programs`
- Section: Gamification / Referrals
- Authentication: `Authorization: Bearer <API_KEY>` (Community API key)
- Permission: `getUserData` (Shown in the dashboard as "Get User Data")
- Retries: Read-only; exact retries are safe
- Guide: hand-written
- Verified: live, 2026-09-27
- Last updated: 26 Sep 2026
- Web page: https://docs.returning.ai/api-reference/gamification-referral/get-referral-programs

## When to use this

- Show traders which referral programs exist, what each stage asks of the people they invite, and what it pays.
- Check a program's stages and rewards before you launch it.
- Find a `programId` to filter Get user's referral summary by.

**Instead:** Use [Get user's referral summary](https://docs.returning.ai/api-reference/gamification-referral/get-users-referral-summary.md) instead to see one trader's invite link, referrals and progress.

## Authentication

- Header: `Authorization: Bearer <API_KEY>`
- Permission: `getUserData`

Send a Community API key with `getUserData`, shown in the dashboard as Get User Data. The key decides the community, so never send a community ID. Keep the key on your server.

## Behaviour

This read changes nothing and returns your programs as they are set up now, not any trader's progress. It includes programs that are switched off, so check `enabled` before you show one to traders. Programs with no stages and deleted programs are left out.

Condition keys, values and rewards differ between communities and change when an admin edits a program. Render what the response returns rather than hard-coding stage counts, names or amounts.

With a `lang` other than `en`, names, descriptions and requirement text come back translated. A translation that doesn't exist yet is made on the first request, which can make that request slower.

## Request

### Query parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `lang` | `string` | No | Language code for names, descriptions and requirement text, such as `fr`. Omit it, or send `en`, for the text as it was entered. |

### Headers

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `Authorization` | `string` | Yes | Community API key with `getUserData`. (`Bearer <API_KEY>`) |

### Example request

```bash
curl --request GET \
  --url 'https://api.returning.ai/v1/referral/programs?lang=en' \
  --header 'Authorization: Bearer <API_KEY>'
```

## Response

A `200` returns the programs in `data`. An empty `data` means your community has no referral programs with stages. Branch on the HTTP status.

### Response fields

| Field | Type | Presence | Description |
| --- | --- | --- | --- |
| `meta` | `object` | always | Status of the request. |
| `meta.status` | `string` | always | Result of the request. (`success`) |
| `meta.statusCode` | `integer` | always | The HTTP status, repeated. |
| `message` | `string` | always | Human-readable summary. Do not branch on it. |
| `data` | `object[]` | always | Every program in your community that has at least one stage, in the order set in the dashboard. Includes switched-off programs. An empty array when there are none. |
| `data.programId` | `string` | always | The program's ID. Send it as `programId` to Get user's referral summary. |
| `data.name` | `string` | always | Program name. |
| `data.description` | `string` | always | Program description. Empty string when none. |
| `data.enabled` | `boolean` | always | `true` when the program is running. Switched-off programs are listed too, with `false`. |
| `data.color` | `string` | always | Display color, a hex code. Empty string when none. |
| `data.icon` | `string` | always | Icon set for the program. Empty string when none. |
| `data.totalRewards` | `object` | always | The bonus paid once an invited trader completes every stage, as `xp` and `coins`. It is paid on top of the stage rewards, not their sum. `0` when there is no bonus. |
| `data.totalRewards.xp` | `integer` | always | XP. |
| `data.totalRewards.coins` | `integer` | always | Coins. |
| `data.stages` | `object[]` | always | The program's stages, in order. |
| `data.stages.stageId` | `string` | always | The stage's ID. |
| `data.stages.stageNumber` | `integer` | always | Position in the program, starting at 1. |
| `data.stages.name` | `string` | always | Stage name. |
| `data.stages.description` | `string` | always | Stage description. Empty string when none. |
| `data.stages.displaySetting` | `string` | always | What traders are shown for the stage. (`condition`, `description` or `condition_and_description`) |
| `data.stages.rewards` | `object` | always | What the referrer earns when an invited trader completes this stage, as `xp` and `coins`. `0` when that reward is off. |
| `data.stages.rewards.xp` | `integer` | always | XP. |
| `data.stages.rewards.coins` | `integer` | always | Coins. |
| `data.stages.mainConditionOperator` | `string` | always | `and` when every condition group must be met, `or` when one is enough. (`and` or `or`) |
| `data.stages.mainConditions` | `object[]` | always | Condition groups for the stage. |
| `data.stages.mainConditions.groupId` | `string` | always | The group's ID. |
| `data.stages.mainConditions.operator` | `string` | always | `and` when every condition in the group must be met, `or` when one is enough. (`and` or `or`) |
| `data.stages.mainConditions.enableUserFacingCondition` | `boolean` | always | `true` when the group's own text is shown to traders. |
| `data.stages.mainConditions.userFacingCondition` | `string` | - | Text shown to traders for the group, when set. |
| `data.stages.mainConditions.nestedConditions` | `object[]` | always | The conditions in the group. |
| `data.stages.mainConditions.nestedConditions.conditionId` | `string` | always | The condition's ID. |
| `data.stages.mainConditions.nestedConditions.key` | `string` | always | What is checked about the invited trader, such as `total_xp`, `messages_sent`, `role` or one of your user fields. |
| `data.stages.mainConditions.nestedConditions.type` | `string` | always | The kind of value, such as `number`, `date`, `role` or `tag`. |
| `data.stages.mainConditions.nestedConditions.condition` | `string` | always | The comparison, such as `is`, `is_not`, `more_than`, `less_than`, `before` or `after`. |
| `data.stages.mainConditions.nestedConditions.value` | `number, string or object` | always | The value compared against. A number, text, or an object for ranges, depending on `type`. |
| `data.stages.mainConditions.nestedConditions.valueLabel` | `string` | always | `value` in readable form, such as a role or tier name, or a formatted date. |
| `data.stages.mainConditions.nestedConditions.isDeletedValue` | `boolean` | always | `true` when `value` points to a role, tag, trader, tier or badge that no longer exists. `valueLabel` then reads `Deleted Role`, `Deleted Tag` and so on. |
| `data.stages.mainConditions.nestedConditions.reference` | `object` | - | Extra detail for conditions that compare against another field. Its shape depends on the condition; don't rely on it. |
| `data.stages.mainConditions.nestedConditions.enableUserFacingCondition` | `boolean` | always | `true` when the condition's own text is shown to traders. |
| `data.stages.mainConditions.nestedConditions.userFacingCondition` | `string` | - | Text shown to traders for the condition, when set. |

### Example response (200)

```json
{
  "meta": {
    "status": "success",
    "statusCode": 200
  },
  "message": "Get referral programs success.",
  "data": [
    {
      "enabled": true,
      "programId": "66f000000000000000000710",
      "name": "Invite a trader",
      "description": "Earn rewards as the traders you invite get started.",
      "color": "#4F46E5",
      "icon": "",
      "totalRewards": {
        "xp": 0,
        "coins": 100
      },
      "stages": [
        {
          "stageId": "66f000000000000000000711",
          "stageNumber": 1,
          "name": "Get active",
          "description": "Your friend earns more than 500 XP.",
          "displaySetting": "condition",
          "mainConditionOperator": "and",
          "mainConditions": [
            {
              "groupId": "66f000000000000000000712",
              "operator": "and",
              "enableUserFacingCondition": false,
              "nestedConditions": [
                {
                  "conditionId": "66f000000000000000000713",
                  "key": "total_xp",
                  "type": "number",
                  "condition": "more_than",
                  "value": 500,
                  "enableUserFacingCondition": true,
                  "userFacingCondition": "Earn more than 500 XP",
                  "valueLabel": "500",
                  "isDeletedValue": false
                }
              ]
            }
          ],
          "rewards": {
            "xp": 250,
            "coins": 25
          }
        }
      ]
    }
  ]
}
```

## Errors

`401`, `403` and `502` errors carry a code in `meta.code`. A `500` carries `INTERNAL_ERROR`, or no code at all with `message` `Get referral programs error.`; treat both the same. Branch on the HTTP status.

### Fix the request

| Status | Code | What to do |
| --- | --- | --- |
| 401 | `AUTH_API_KEY_REQUIRED` | No key was sent. Send `Authorization: Bearer <API_KEY>`. |
| 401 | `AUTH_API_KEY_INVALID` | The key is unknown, expired or malformed. Use a current Community API key. |
| 403 | `AUTH_PERMISSION_REQUIRED` | The key lacks `getUserData`. Add Get User Data in Settings > Integration > API Keys. |

### Retry with backoff

| Status | Code | What to do |
| --- | --- | --- |
| 502 | `STORE_DEPENDENCY_UNAVAILABLE` | Referral programs are briefly unavailable. Retry the same request with exponential backoff. |
| 500 | `INTERNAL_ERROR` | The read failed unexpectedly. Retry the same request with exponential backoff. |
| 401 | `AUTH_API_KEY_VALIDATION_FAILED` | The key could not be checked just now. Retry with backoff; the key itself may be fine. |

**Retries:** This endpoint is read-only, so retrying the exact same request is safe after a network error, a `500` or a `502`. Use bounded exponential backoff. Over the [rate limit](https://docs.returning.ai/how-it-works.md#rate-limits), requests return `429`; wait for the window to reset, then retry.

## Next step

- [Get user's referral summary](https://docs.returning.ai/api-reference/gamification-referral/get-users-referral-summary.md): `POST /v1/referral/summary`. Read one trader's invite link and their invited traders' progress, optionally for one `programId`.
- [Find the trader to look up with Get User Data](https://docs.returning.ai/api-reference/users/get-user-data.md): `POST /v1/users/info`.
