# Referrals API

The Referrals API exposes the same self-scoped behavior used by the Bkper Referrals application. Scripts and agents can read the authenticated user's recommendation link and relationships, inspect aggregate economics, update public recommendation copy, or remove a relationship.

## Endpoints and discovery

| Resource                          | URL                                                                |
| --------------------------------- | ------------------------------------------------------------------ |
| Production API                    | `https://referrals.bkper.app`                                      |
| Development API                   | `https://referrals-dev.bkper.app`                                  |
| OpenAPI 3.1 contract              | `https://referrals.bkper.app/openapi.json`                         |
| OAuth protected-resource metadata | `https://referrals.bkper.app/.well-known/oauth-protected-resource` |
| Agent index                       | `https://referrals.bkper.app/llms.txt`                             |

Use production for real user automation. Development uses the Bkper development environment and does not provide a public sandbox for production accounts.

## Supported operations

| Operation                                 | Method and path                             | Effect                      |
| ----------------------------------------- | ------------------------------------------- | --------------------------- |
| Get recommendation link and relationships | `GET /api/v1/referrals`                     | Read-only                   |
| Get aggregate referred subscription value | `GET /api/v1/economics?scope=user\|billing` | Read-only                   |
| Get public recommendation presentation    | `GET /public/v1/recommendations/{username}` | Public and read-only        |
| Publish or reset recommendation copy      | `PUT /api/v1/recommendation`                | Changes public presentation |
| Remove the caller's current referrer      | `DELETE /api/v1/referrer`                   | Removes a relationship      |
| Remove one direct referral                | `DELETE /api/v1/referrals/{referredUserId}` | Removes a relationship      |

The API does not:

- send a recommendation link through email, messaging, or social services;
- create or claim a referral relationship from arbitrary user IDs;
- replace an established referrer;
- configure custom URLs, campaign parameters, rewards, or payouts.

A relationship is established only after someone follows an ordinary recommendation or Book invitation link and completes verified Bkper sign-in. The first established referrer wins. Self-referrals and circular relationships are rejected.

## Authentication

Every `/api/v1/*` request requires a Bkper OAuth access token:

```http
Authorization: Bearer BKPER_ACCESS_TOKEN
```

The public recommendation endpoint and discovery resources do not require authentication.

For local scripts, authenticate the official CLI and place its short-lived token in an environment variable:

```bash
bkper auth login
export BKPER_TOKEN="$(bkper auth token)"
```

Do not put access tokens in source files, prompts, logs, URLs, or recommendation text.

Authenticated routes do not provide broad cross-origin browser access. Call them from server-side scripts or use the Referrals application on its own origin.

## Get the recommendation link

```bash
curl --fail-with-body --silent \
  --header "Authorization: Bearer ${BKPER_TOKEN}" \
  "https://referrals.bkper.app/api/v1/referrals"
```

The `recommendationUrl` field contains the exact public URL to share. It is `null` when the authenticated profile has no Bkper username.

A sharing automation should:

1. Read `recommendationUrl` from this response.
2. Ask the user to confirm the recipient and delivery channel.
3. Pass the exact URL to the separately authorized email, messaging, or social tool.

The Referrals API itself does not contact recipients.

## Read relationships

The same response returns:

- `profile`: the authenticated user's current public profile;
- `referrer`: the user's current referrer or `null`;
- `referrals`: direct referrals only;
- `recommendationUrl`: the canonical recommendation link.

Each relationship contains an immutable `userId`, current public profile when available, attribution `source`, and `createdAt` timestamp. A null related profile does not prevent relationship removal.

Only these attribution sources are returned:

- `RECOMMENDATION_LINK`
- `BOOK_INVITATION`

## Read aggregate economics

Request the user's direct-referral scope:

```bash
curl --fail-with-body --silent \
  --header "Authorization: Bearer ${BKPER_TOKEN}" \
  "https://referrals.bkper.app/api/v1/economics?scope=user"
```

Use `scope=billing` when the result should follow the caller's current shared subscription billing owner. This gives members of the same billing scope one stable aggregate without exposing the billing owner's relationship rows.

Important response semantics:

- `monthlyValueNanoUsd` is an integer amount in USD nano-units.
- `contributingCount` counts deduplicated eligible subscriptions.
- `referralPlans` contains current plan labels for the caller's direct referrals, without individual values.
- `availability=unavailable` means the valuation is unknown. Never interpret null amounts or counts as zero.
- The API returns current subscription valuation, not AI allowance, cash, commission, or an earned balance.

Bkper AI separately applies the current Referral Program benefit policy.

## Publish recommendation copy

Recommendation copy appears publicly on the user's Bkper recommendation page. Obtain explicit approval of the final text before publishing it.

```bash
curl --fail-with-body --silent \
  --request PUT \
  --header "Authorization: Bearer ${BKPER_TOKEN}" \
  --header "Content-Type: application/json" \
  --data '{
    "header": "Books that stay clear.",
    "subheader": "Automate repetitive work while keeping every balance reviewable."
  }' \
  "https://referrals.bkper.app/api/v1/recommendation"
```

Both fields are written together and both must be non-empty after normalization.

| Field       |         Maximum length |
| ----------- | ---------------------: |
| `header`    |  64 Unicode characters |
| `subheader` | 140 Unicode characters |

The service trims surrounding whitespace, collapses repeated spaces and tabs, and rejects:

- line breaks;
- URLs and email addresses;
- angle brackets or markup-like text;
- control and bidirectional control characters;
- abusive, unsafe, impersonating, misleading, or unrelated promotional content.

A rejected or unavailable validation leaves the previously published message unchanged.

## Reset recommendation copy

Obtain confirmation before resetting. Send both fields as `null` to restore the default Marketing presentation:

```bash
curl --fail-with-body --silent \
  --request PUT \
  --header "Authorization: Bearer ${BKPER_TOKEN}" \
  --header "Content-Type: application/json" \
  --data '{"header":null,"subheader":null}' \
  "https://referrals.bkper.app/api/v1/recommendation"
```

## Remove relationships

Relationship removal does not assign a replacement or retain history. A future relationship requires a fresh recommendation or Book invitation. Always show the related public profile and obtain explicit confirmation immediately before either request.

Remove the authenticated user's current referrer:

```bash
curl --fail-with-body --silent \
  --request DELETE \
  --header "Authorization: Bearer ${BKPER_TOKEN}" \
  "https://referrals.bkper.app/api/v1/referrer"
```

Remove one of the authenticated user's direct referrals:

```bash
curl --fail-with-body --silent \
  --request DELETE \
  --header "Authorization: Bearer ${BKPER_TOKEN}" \
  "https://referrals.bkper.app/api/v1/referrals/REFERRED_USER_ID"
```

Both endpoints return `204` when the relationship is removed, absent, or unrelated. This idempotent behavior prevents relationship-existence disclosure. A client must not report that a relationship existed based only on the `204` response.

## Errors

| Status | Meaning                                                                   |
| -----: | ------------------------------------------------------------------------- |
|  `400` | Invalid parameters or recommendation format                               |
|  `401` | Missing, expired, or invalid Bkper bearer token                           |
|  `404` | Unknown username on the public recommendation endpoint                    |
|  `422` | Recommendation copy rejected by safety validation                         |
|  `503` | Identity, profile, validation, valuation, or referral storage unavailable |

Error responses use this shape:

```json
{
    "error": {
        "code": "INVALID_REQUEST",
        "message": "Invalid request parameters."
    }
}
```

Preserve the service's safe error message for the user. Do not log access tokens or raw upstream authentication errors.

## Automation safety

Before mutating Referrals data, an agent should:

1. Read the current state.
2. Explain the exact proposed change.
3. Show the final recommendation text or related profile.
4. Obtain explicit user confirmation.
5. Perform only the confirmed request.
6. Report the API response without inferring undisclosed relationship state.

Reading relationships, recommendation links, public presentation, and economics does not require mutation confirmation.

## Next steps

- [Review the Referral Program rules](https://bkper.com/referrals.md)
- [Inspect the machine-readable OpenAPI contract](https://referrals.bkper.app/openapi.json)
- [Review direct REST authentication](https://bkper.com/docs/platform/scripts/rest-api.md)
- [Review the official CLI](https://bkper.com/docs/platform/tools/cli.md)
