> ## Documentation index
> Fetch the complete documentation index at: https://developer.rhombus.com/llms.txt
> Use it to discover all available pages before exploring further.

# API Keys and Certificates

> Create a Rhombus API key, choose its role, call the API with it, and use a certificate (mTLS) key: expiry, creating, rotating and renewing keys with the API, the CSR, and revocation.

An API key is the credential for code you run on your own servers. It belongs to one organization, acts with the **role** you give it, and works until you delete it or until its expiry (`expiresAtMs`), if it has one. A key can be a plain **API token**, sent in a header, or a **certificate** key that also needs a TLS client certificate (mTLS).

## Create an API key

1. In the [Rhombus Console](https://console.rhombussystems.com/settings/integrations/api-tokens/), go to **Settings → Integrations & Developer Resources → API Tokens** and click **Add API Key**. EU organizations use [console.eu.rhombussystems.com](https://console.eu.rhombussystems.com/settings/integrations/api-tokens/).
2. Enter a **Name** that says what uses the key (`warehouse-door-sync`). It shows in the audit log.
3. Choose an **Auth Type**: **Api Token**, or **Certificate** for mTLS (see [Certificate keys](https://developer.rhombus.com/authentication/api-keys#certificate-keys-mtls)).
4. Choose a **Role**. The key can do exactly what the role allows, so pick the narrowest role that covers the job. See [Permissions and key rotation](https://developer.rhombus.com/authentication/permissions).
5. Copy the key. It's shown once.

Creating keys needs a role with API administration, and you can only give a key a role you're allowed to assign. To create keys from code, see [Manage keys with the API](https://developer.rhombus.com/authentication/api-keys#manage-keys-with-the-api).

## Call the API with a key

Send the scheme and the key as headers on every request:

```bash cURL
curl -X POST "https://api2.rhombussystems.com/api/camera/getMinimalCameraStateList" \
  -H "x-auth-scheme: api-token" \
  -H "x-auth-apikey: $RHOMBUS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'
```

```python Python
import os
import requests

session = requests.Session()
session.headers.update({
    "x-auth-scheme": "api-token",
    "x-auth-apikey": os.environ["RHOMBUS_API_KEY"],
    "Content-Type": "application/json",
})

cameras = session.post(
    "https://api2.rhombussystems.com/api/camera/getMinimalCameraStateList", json={}
).json()
```

```javascript JavaScript
const res = await fetch(
  "https://api2.rhombussystems.com/api/camera/getMinimalCameraStateList",
  {
    method: "POST",
    headers: {
      "x-auth-scheme": "api-token",
      "x-auth-apikey": process.env.RHOMBUS_API_KEY,
      "Content-Type": "application/json",
    },
    body: "{}",
  },
);
const cameras = await res.json();
```

The same headers work on the media hosts and the event WebSocket handshake. Partner keys use them too, plus `x-auth-org` to act in a client organization (see [Partner API](https://developer.rhombus.com/partner-api-calls)). The key is never accepted as a query parameter, so it can't authenticate an `<img>`, a `<video>` or a browser WebSocket; use a [federated token](https://developer.rhombus.com/authentication/federated-tokens) there. Cameras on your local network accept only federated tokens.

## Lifetime and revocation

- **Expiry.** A key can have an expiry time, `expiresAtMs` (Unix epoch milliseconds). A key created by another API key always has one. After it passes, requests with the key get 401 `CREDENTIAL_EXPIRED`; the key still appears in key lists ([`getApiTokens`](https://developer.rhombus.com/api-reference/org-integrations-webservice/get-api-tokens)) until you delete it. A key without `expiresAtMs` works until you delete it.
- **Revocation takes effect within 60 seconds on every host.** That applies to deleting a key (in the console or with [`revokeApiToken`](https://developer.rhombus.com/api-reference/org-integrations-webservice/revoke-api-token)) and to changing its role. Open event WebSocket connections that used the key get a STOMP `ERROR` frame and close with code `1008`; open media sockets (live video, talk, robot, PTZ) close with `1008` within the same 60 seconds.
- **Deleting a key ends what it created:** keys it created are deleted with it, and federated tokens it minted stop working.
- **Keys are region-bound.** A key from a US organization returns 401 `INVALID_CREDENTIAL` on EU hosts, and the reverse.
- **No per-key network or rate settings.** Keys have no IP allow-list and no rate limit of their own; every key draws on your organization's [rate limit](https://developer.rhombus.com/rate-limits).

To replace a key without downtime, see [Rotate an API key](https://developer.rhombus.com/authentication/permissions#rotate-an-api-key).

## Manage keys with the API

Keys can be created, rotated and, for certificate keys, renewed with the API. All are `POST`:

| Action              | Organization keys                                                                                                                                         | Partner keys                                                                                                                            |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| Create              | [`/api/integrations/org/submitApiTokenApplication`](https://developer.rhombus.com/api-reference/org-integrations-webservice/submit-api-token-application) | [`/api/partner/submitApiTokenApplication`](https://developer.rhombus.com/api-reference/partner-webservice/submit-api-token-application) |
| Rotate              | [`/api/integrations/org/rotateApiToken`](https://developer.rhombus.com/api-reference/org-integrations-webservice/rotate-api-token)                        | [`/api/partner/rotateApiToken`](https://developer.rhombus.com/api-reference/partner-webservice/rotate-api-token)                        |
| Renew a certificate | [`/api/integrations/org/renewApiTokenCert`](https://developer.rhombus.com/api-reference/org-integrations-webservice/renew-api-token-certificate)          | [`/api/partner/renewApiTokenCert`](https://developer.rhombus.com/api-reference/partner-webservice/renew-api-token-certificate)          |
| Who can call        | A console or mobile app session, an OAuth access token, or an API key, whose role includes API administration                                             | A partner console or mobile app session, a partner OAuth access token, or a partner key, whose partner role includes API administration |

When the caller is an **API key**:

- `expiresAtMs` is required: at most 365 days from now, and no later than the calling key's own expiry.
- A key creates and rotates keys only in its own organization. A partner key that sends `x-auth-org` gets 403.
- A key it creates is deleted when the calling key is deleted.
- Federated tokens can't call these endpoints, and neither can the keys Rhombus's own devices and apps use (TV, keypad, kiosk, door station, executable and chatbot keys): they get 403.

An OAuth access token needs all three scopes (`read`, `write` and `physical`) to create, rotate or renew keys ([OAuth scopes](https://developer.rhombus.com/authentication/permissions#oauth-scopes)). The deprecated `submitApiTokenApplication` that predates the `/org/` path doesn't accept API credentials; use the endpoints above.

### Create a key

- **`displayName` (body, string, required)**: The key's name, shown in the console and the audit log.
- **`permissionGroupUuid` (body, string, required)**: The role the key acts with: one you're allowed to assign. List roles with [`getPermissionGroups`](https://developer.rhombus.com/api-reference/permission-webservice/get-permission-groups).
- **`authType` (body, string, required)**: `API_TOKEN` for a plain key, or `CERT` for a [certificate key](https://developer.rhombus.com/authentication/api-keys#certificate-keys-mtls).
- **`csr` (body, string)**: Required with `CERT`: the PEM certificate signing request for the key's client certificate.
- **`expiresAtMs` (body, integer)**: When the key stops working, in Unix epoch milliseconds. Required when the caller is an API key.

```bash cURL
EXPIRES_AT_MS=$(( ($(date +%s) + 90 * 86400) * 1000 ))  # 90 days from now

curl -X POST "https://api2.rhombussystems.com/api/integrations/org/submitApiTokenApplication" \
  -H "x-auth-scheme: api-token" \
  -H "x-auth-apikey: $RHOMBUS_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"displayName\": \"warehouse-door-sync\", \"permissionGroupUuid\": \"$ROLE_UUID\", \"authType\": \"API_TOKEN\", \"expiresAtMs\": $EXPIRES_AT_MS}"
```

```python Python
import os
import time
import requests

res = requests.post(
    "https://api2.rhombussystems.com/api/integrations/org/submitApiTokenApplication",
    headers={
        "x-auth-scheme": "api-token",
        "x-auth-apikey": os.environ["RHOMBUS_API_KEY"],
        "Content-Type": "application/json",
    },
    json={
        "displayName": "warehouse-door-sync",
        "permissionGroupUuid": os.environ["ROLE_UUID"],
        "authType": "API_TOKEN",
        "expiresAtMs": int((time.time() + 90 * 86400) * 1000),  # 90 days from now
    },
)
res.raise_for_status()
data = res.json()
if data.get("error"):
    raise RuntimeError(data.get("errorMsg"))
api_key = data["apiKey"]  # shown once: store it like a password
```

The response holds the new key:

- **`apiKey` (string)**: The key. It's returned once; store it securely.
- **`tokenUuid` (string)**: The key's ID, used to rotate, renew or delete it.
- **`expiresAtMs` (integer)**: When the key expires, if it has an expiry.
- **`cert` (string)**: Certificate keys only: the signed client certificate (PEM).
- **`certNotAfterMs` (integer)**: Certificate keys only: when the certificate expires.

A refused request can return HTTP 200 with `"error": true` and an `errorMsg`, so check the body as well as the status.

### Rotate a key

`rotateApiToken` issues a replacement key with the **same role** and keeps the old key working for an overlap, so you can deploy the new key without downtime.

- **`tokenUuid` (body, string, required)**: The key to replace.
- **`overlapSec` (body, integer, default: 86400)**: How long the old key keeps working, in seconds: one day by default, at most 2592000 (30 days).
- **`csr` (body, string)**: Required when rotating a certificate key: a CSR for the new key's certificate.
- **`expiresAtMs` (body, integer)**: The new key's expiry, in Unix epoch milliseconds. Required when the caller is an API key, with the same limits as creating a key.

```bash cURL
curl -X POST "https://api2.rhombussystems.com/api/integrations/org/rotateApiToken" \
  -H "x-auth-scheme: api-token" \
  -H "x-auth-apikey: $RHOMBUS_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"tokenUuid\": \"$OLD_TOKEN_UUID\", \"overlapSec\": 172800, \"expiresAtMs\": $(( ($(date +%s) + 90 * 86400) * 1000 ))}"
```

The response has the new key's `apiKey`, `tokenUuid`, `expiresAtMs` and, for certificate keys, `cert` and `certNotAfterMs`, plus **`previousKeyExpiresAtMs`**: when the old key stops working. Deploy the new key before then. The full procedure is in [Rotate an API key](https://developer.rhombus.com/authentication/permissions#rotate-an-api-key).

## Certificate keys (mTLS)

A certificate key adds a TLS client certificate to the API key. Requests are refused unless they present both the key and the certificate issued for it, so a leaked key alone isn't enough. Use it when your security policy requires mutual TLS for service credentials.

**Where it works:** only the REST API hosts **`api2.rhombussystems.com`** and **`api2.eu.rhombussystems.com`**, which pass TLS through to Rhombus so the client certificate can be checked. Media hosts, the event WebSocket and cameras on your LAN don't accept certificate keys; use a separate API key or a [federated token](https://developer.rhombus.com/authentication/federated-tokens) for those.

### 1. Make a private key and a CSR

Generate the key on the machine that will use it, and keep it there:

```bash
openssl req -new -newkey rsa:2048 -nodes \
  -keyout rhombus-client.key \
  -out rhombus-client.csr \
  -subj "/CN=warehouse-door-sync"
```

RSA 2048-bit or ECDSA P-256 keys both work. Rhombus sets the certificate's subject itself, so the `CN` you choose doesn't matter. Rhombus verifies the CSR's signature, which proves you hold its private key; a CSR whose signature doesn't verify is rejected. `openssl req` signs it for you.

### 2. Create the key

In **Add API Key**, choose **Auth Type: Certificate**, choose a role, and paste the contents of `rhombus-client.csr`. With the API, send `"authType": "CERT"` and the CSR in `csr` ([Create a key](https://developer.rhombus.com/authentication/api-keys#create-a-key)). Rhombus returns the API key and a signed client certificate. Save the certificate as `rhombus-client.crt`.

### 3. Call the API

Use the scheme `api`, send the key in `x-auth-apikey` as usual, and present the certificate in the TLS handshake:

```bash cURL
curl -X POST "https://api2.rhombussystems.com/api/camera/getMinimalCameraStateList" \
  --cert rhombus-client.crt --key rhombus-client.key \
  -H "x-auth-scheme: api" \
  -H "x-auth-apikey: $RHOMBUS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'
```

```python Python
import os
import requests

res = requests.post(
    "https://api2.rhombussystems.com/api/camera/getMinimalCameraStateList",
    cert=("rhombus-client.crt", "rhombus-client.key"),
    headers={
        "x-auth-scheme": "api",
        "x-auth-apikey": os.environ["RHOMBUS_API_KEY"],
        "Content-Type": "application/json",
    },
    json={},
)
```

```javascript JavaScript (Node.js)
import { readFileSync } from "node:fs";
import https from "node:https";

const agent = new https.Agent({
  cert: readFileSync("rhombus-client.crt"),
  key: readFileSync("rhombus-client.key"),
});

const req = https.request(
  "https://api2.rhombussystems.com/api/camera/getMinimalCameraStateList",
  {
    method: "POST",
    agent,
    headers: {
      "x-auth-scheme": "api",
      "x-auth-apikey": process.env.RHOMBUS_API_KEY,
      "Content-Type": "application/json",
    },
  },
  (res) => res.pipe(process.stdout),
);
req.end("{}");
```

Partner certificate keys work the same way, with the scheme `api` (or its alias `partner-api`). See [Partner API](https://developer.rhombus.com/partner-api-calls).

### Renew a certificate

Certificates last 365 days. Before `certNotAfterMs`, get a new certificate for the same key with `renewApiTokenCert` (partner keys: `/api/partner/renewApiTokenCert`):

- **`tokenUuid` (body, string)**: The certificate key to renew. Leave it out when a certificate key renews its own certificate.
- **`csr` (body, string, required)**: A CSR for the new certificate, made as in [step 1](https://developer.rhombus.com/authentication/api-keys#1-make-a-private-key-and-a-csr).

```bash cURL
openssl req -new -newkey rsa:2048 -nodes \
  -keyout rhombus-client-new.key -out rhombus-client-new.csr -subj "/CN=warehouse-door-sync"

curl -X POST "https://api2.rhombussystems.com/api/integrations/org/renewApiTokenCert" \
  --cert rhombus-client.crt --key rhombus-client.key \
  -H "x-auth-scheme: api" \
  -H "x-auth-apikey: $RHOMBUS_API_KEY" \
  -H "Content-Type: application/json" \
  -d "$(jq -n --rawfile csr rhombus-client-new.csr '{csr: $csr}')" \
  | jq -r .cert > rhombus-client-new.crt
```

The response has `cert` and `certNotAfterMs`. The API key stays the same and there's no overlap, so switch the client to the new certificate and private key as soon as you receive them. To change the key as well, [rotate](https://developer.rhombus.com/authentication/api-keys#rotate-a-key) it with a new CSR instead.

### Certificate facts

- **Validity:** developer and partner certificates last 365 days (`certNotAfterMs`). Renew them in place, or rotate the key.
- **TLS:** TLS 1.2. If your network inspects TLS, exempt the `api2` hosts, or the proxy strips the client certificate.
- **Revocation:** deleting the key revokes its certificate within 60 seconds.
- **Failures:** a certificate Rhombus didn't issue fails the TLS handshake itself (no HTTP status). A certificate key sent without its certificate (for example with `x-auth-scheme: api-token`), or with a certificate issued for a different key, returns 401 `CERTIFICATE_MISMATCH` (`Client certificate does not match the api key`).

## Keys for other kinds of access

- **Customers authorize your app:** use [Sign in with Rhombus](https://developer.rhombus.com/oauth-authentication). An OAuth app can also create an API key for background work; the key is deleted when the user revokes the app's access.
- **MSPs and resellers:** a [partner API key](https://developer.rhombus.com/partner-api-calls) reaches every client organization you manage.
- **Browsers, mobile apps and cameras on your LAN:** mint a short-lived [federated token](https://developer.rhombus.com/authentication/federated-tokens) from your backend.
