---
title: API keys, scopes, rotation and sandbox | HelpRange developers
url: https://www.helprange.com/developers/keys
---

Developers

# API keys, scopes, rotation and the sandbox

How to authenticate to the HelpRange REST API with least-privilege keys, rotate them without downtime and test safely in test mode.

## API keys

Every request to the HelpRange REST API (`/api/v2/…` and the older `/public-api/…`) carries an API key. Administrators create keys in **Settings → API keys**. Give every integration its own key, with only the scopes it needs, so you can roll or revoke one without touching the others.

- **Format:** `hr_live_` or `hr_test_` followed by 40 letters and digits.
- **Shown once.** HelpRange stores only a SHA-256 hash of the key and its first characters (e.g. `hr_live_Ab3x9K…`) to recognise it in the list. Copy the key when you create it; if you lose it, roll it.
- **Who it acts as:** the administrator who created (or last rolled) the key, with their permissions. If that person leaves the team the key stops working (`401 key_owner_removed`) until another administrator rolls it.
- **Plans:** the same as before – the REST API is available on the Max and Unlimited plans, the Deal Room Pass and the trial (`402` otherwise), for live and test keys alike.

### Sending the key

```
curl https://www.helprange.com/api/v2/documents \
  -H "Authorization: Bearer hr_live_…"
```

`X-API-Key: hr_live_…` and `Authorization: Api-Key hr_live_…` work too; the v1 API also takes the bare key in `Authorization`.

### Errors

| `401 invalid_key` | Unknown key. |
|---|---|
| `401 key_revoked` | The key was revoked (or its roll overlap ended). |
| `401 key_expired` | The key's expiry date has passed. |
| `401 key_owner_removed` | The key's creator is no longer in the team – roll it. |
| `403 insufficient_scope` | The key lacks the endpoint's scope; `required_scope` names it. |
| `400 sandbox_email_domain` | Test mode only accepts e-mail addresses at reserved test domains. |

```
{"error": "This API key does not have the \"rooms:write\" scope needed for POST /api/v2/data-rooms/12/guests. …",
 "code": "insufficient_scope", "required_scope": "rooms:write", "key_scopes": ["documents:read", "rooms:read"]}
```

## Scopes

A key can call an endpoint only when it has the endpoint's scope – least privilege. Reading needs `…:read`; creating, changing and deleting need `…:write`. Presets: **Read-only** (every `:read` scope) and **Full access** (all scopes).

| `documents:read` | List folders, documents, subfolders, e-signature requests and files uploaded by clients. |
|---|---|
| `documents:write` | Upload documents, create and change folders and subfolders, send and manage e-signature requests. |
| `links:read` | Read share links of documents, offers and lead-form templates. |
| `links:write` | Create share links, give or remove buyer access, create and change offers. |
| `rooms:read` | Read data rooms: details, index, guests' access requests, Q&A, request lists, folders, documents. |
| `rooms:write` | Change data rooms: invite guests, answer Q&A, request lists, room folders and documents. |
| `analytics:read` | Read views, statistics, activity, offer responses and store sales. |
| `webhooks:manage` | Reserved for managing webhook endpoints through the API (no endpoint uses it yet – webhooks are set up in Settings → Integrations). |
| `team:read` | Read the team: who the key belongs to, the plan and its limits. |

Main endpoints per scope: `documents:*` – folders, documents, uploads, subfolders, e-signature requests; `links:*` – share links, buyer access, offers, lead-form templates; `rooms:*` – data rooms, guests, Q&A, request lists, room folders and documents; `analytics:read` – views, statistics, activity, offer responses, store sales; `team:read` – `/api/v2/me` and `/api/v2/plan`; `webhooks:manage` – reserved (webhooks are set up in Settings → Integrations; no API endpoint needs it yet).

## Rotation and revocation

- **Roll key** creates a new secret with the same name, scopes, mode and expiry. Choose how long the old key keeps working: **not at all**, **24 hours** or **7 days** – long enough to deploy the new key everywhere. After the overlap the old key is revoked automatically.
- **Revoke** stops a key immediately (also an old key that is still in its overlap).
- **Expiry date** (optional): the key stops working at the end of that day (UTC).
- Every create, roll and revoke is recorded in **Activity → Team** with who did it. The list shows when each key was last used.
- **Legacy keys**: the single per-member key from before (shown as “Legacy key (full access, live)”) keeps working with full access. Migrate by creating a scoped key and switching your integration to it.

## Sandbox (test mode)

Keys starting with `hr_test_` work on a separate **sandbox** of your team – never on your live data, and live keys never see the sandbox. The first test request creates it with sample data: two documents with share links and sample views, and a data room with two guests at example.com / example.org.

- Every response says `"livemode": false` (and the header `X-HelpRange-Livemode: false`); live keys answer `"livemode": true`.
- **No e-mails are sent.** Invitations, signature requests and notifications are logged instead – see “E-mails the sandbox did not send” in Settings → API keys. To make sure nobody real is ever e-mailed, test mode accepts only addresses at reserved test domains such as `jane@example.com`, `guest@example.org` or `anyone@acme.test`.
- **No payments:** nothing in the sandbox talks to Stripe.
- **Webhooks:** sandbox activity does not trigger your webhook. To test your receiver, use **Send test event** in Settings → Integrations → Delivery log (the event carries `"test": true`).
- The sandbox does not count towards your plan's limits, statistics or billing. API rate limits and daily caps are counted separately for it.
- **Reset sandbox** (Settings → API keys) deletes all sandbox data; the next test request starts a fresh one. Sandbox data is deleted automatically 30 days after the sandbox was created or reset.

```
curl https://www.helprange.com/api/v2/documents -H "Authorization: Bearer hr_test_…"
{"documents": [{"id": 9182, "name": "Sample – Investor Deck.pdf", …}], "livemode": false}
```
