> ## Documentation Index
> Fetch the complete documentation index at: https://api.vitarelay.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Rep API

> Invite clinics and reps to your network from your own software.

## What is the Rep API?

The Rep API is for **rep organizations** — a Vita Rep, or a dual Rep + Clinic account — that recruit clinics and other reps. It does what the **Refer a Tele Clinic** form in the app does, but from your own system: create an invite, get the signup link back, check whether it was accepted, and revoke it.

It is separate from the VitaClinic API. The VitaClinic API is for a clinic placing orders and managing its patients. The Rep API is for the people who **bring clinics onto the platform**.

<Info>
  Base URL: `https://vitarelay.com/api/public/rep/v1`. Authenticate with a Bearer API key, exactly as for the other VitaRelay APIs. Test keys (`vr_test_…`) run in a sandbox: nothing is created and no email is sent.
</Info>

## How it works

<Steps>
  <Step title="Get an API key">
    Ask VitaRelay for a key with **`invites:write`** (to create and revoke invites) and **`invites:read`** (to list and fetch them). See [API keys](/getting-started/api-keys). Your organization must be a rep or a dual Rep + Clinic account; any other organization gets `403 not_available`.
  </Step>

  <Step title="Create an invite">
    `POST /invites` with the prospect's details. The response includes an `invite_url`, which opens the signup page for that invite on **your own branded domain** when you have one. By default the invite is also emailed to the prospect.
  </Step>

  <Step title="The prospect signs up">
    They open the link and register as a Tele Clinic (or Rep Partner). They join your network, and you earn commission on their orders as usual.
  </Step>

  <Step title="Track it">
    `GET /invites` or `GET /invites/{id}` shows whether each invite is `pending`, `accepted` or `expired`. `POST /invites/{id}/revoke` cancels one that has not been used.
  </Step>
</Steps>

## Create an invite

```bash theme={null}
curl -X POST https://vitarelay.com/api/public/rep/v1/invites \
  -H "Authorization: Bearer $VITARELAY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "clinic",
    "email": "owner@jasonmeds.com",
    "phone": "(229) 719-4222",
    "first_name": "Jason",
    "last_name": "Tests",
    "product_types": ["503a", "rnd", "supplements"],
    "external_invite_id": "crm-lead-4471"
  }'
```

```json theme={null}
{
  "data": {
    "id": "9c7f2f1e-3b0a-4f4e-9d0b-1c2d3e4f5a6b",
    "type": "clinic",
    "status": "pending",
    "invite_code": "k3j9x2…",
    "invite_url": "https://portal.example.com/register/vita-clinic?invite=k3j9x2…",
    "email": "owner@jasonmeds.com",
    "phone": "(229) 719-4222",
    "first_name": "Jason",
    "last_name": "Tests",
    "product_types": ["503a", "rnd", "supplements"],
    "external_invite_id": "crm-lead-4471",
    "expires_at": "2026-10-07T17:00:00Z",
    "created_at": "2026-10-02T17:00:00Z"
  }
}
```

| Field | Notes |
| - | - |
| `type` | `clinic` (a Tele Clinic, the default) or `rep` (a Rep Partner). |
| `email` | Required unless `send_email` is `false`. The invite email is sent here. |
| `phone`, `first_name`, `last_name` | Optional, but provide at least one of `email`, `phone` or `first_name`. |
| `product_types` | Which product groups the invited organization can see: any of `503a`, `rnd`, `supplements`. Omit for all. 503B is never offered to clinics or reps. |
| `send_email` | `true` by default. Set `false` to get the link back **without** emailing the prospect, for example to send it yourself. |
| `external_invite_id` | Your own id for the invite. Makes the call **safe to retry** (see below). |

<Note>
  Invites created through the API use your standard commission pricing. Setting your own per-clinic pricing is done in the dashboard. An invite link is valid for **5 days**; after that its `status` is `expired` and you can create a new one.
</Note>

## Retries are safe

Send an `external_invite_id` and repeat the same request after a timeout: you get the **same invite back** (`200`), not a second one. Reusing an `external_invite_id` with a **different** body returns `409 duplicate_request`. A request that failed creates nothing, so its id can be reused.

## List, fetch and revoke

* `GET /invites` — your invites, newest first. Filter with `?status=pending|accepted|expired`, page with `?limit=` (max 100) and `?cursor=` (use `next_cursor` from the previous page).
* `GET /invites/{id}` — one invite.
* `POST /invites/{id}/revoke` — cancels a pending invite so the link stops working. Revoking an invite that is already revoked is fine and returns it unchanged. An **accepted** invite cannot be revoked (`409 invite_already_accepted`).

An invite you did not create — or that does not exist — returns `404 invite_not_found`; you can never see another organization's invites.

## Access and scopes

| Scope | Grants |
| - | - |
| `invites:read` | `GET /invites`, `GET /invites/{id}` |
| `invites:write` | `POST /invites`, `POST /invites/{id}/revoke` (also allows the reads) |

## Errors

Errors use the same shape as the rest of the platform: `{ "error": { "code": "…", "message": "…" } }`.

| Status | Code | When |
| - | - | - |
| 400 | `invalid_body` | The body is not valid JSON. |
| 401 | `unauthorized` | Missing, invalid or revoked API key. |
| 403 | `insufficient_scope` | The key lacks `invites:read` or `invites:write`. |
| 403 | `not_available` | Your organization is not a rep or dual Rep + Clinic account. |
| 404 | `invite_not_found` | No invite with that id belongs to your organization. |
| 409 | `duplicate_request` | `external_invite_id` reused with a different body, or the same request is still in flight. |
| 409 | `invite_already_accepted` | You tried to revoke an invite that has already been accepted. |
| 422 | `validation_failed` | A field is missing or invalid (the message says which). |
| 429 | `rate_limited` | Too many requests; retry after the `Retry-After` header. |
| 500 | `internal_error` | Something went wrong on our side. Nothing was created; retrying with the same `external_invite_id` is safe. |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.