Authentication
Partner API Calls
Make Rhombus API calls as a partner — authenticate with a partner API key, manage your client organizations with partner endpoints, and scope client-level calls to a managed org using the x-auth-org header.
On this page
- Overview
- Before you begin
- Two kinds of calls
- Authenticating as a partner
- Scoping a call to a client organization
- Calls without x-auth-org
- Examples
- Step 1 — List your client organizations
- Step 2 — Call a client-level endpoint as a managed client
- The CLI does this for you
- WebSocket connections
- Partner endpoint reference
- Partner API keys
- Troubleshooting
- Next steps
Overview
If you're a Rhombus partner — a managed service provider (MSP) or reseller that operates many customer organizations under one partner account — your API key works differently from a standard organization key. A single partner key lets you:
- Manage your fleet of client organizations with partner endpoints (
/api/partner/...) — list clients, register hardware, check licenses, and issue API tokens. - Reach into any one of those clients and call client-level endpoints (cameras, access control, sensors, users — the rest of the API) as that client, by naming the target org in a single request header.
This guide explains the two kinds of calls, how partner credentials authenticate, and the x-auth-org header that ties them together so one set of credentials can operate across every organization you manage.
What this guide isn't. This covers making REST API calls with an existing partner API key. If you need to obtain partner credentials — the OAuth browser-login flow, detecting partner accounts, or minting long-lived partner keys — see Sign in with Rhombus, which documents the partner OAuth path and key minting. This guide picks up once you have a partner key in hand.
Before you begin
To follow this guide you need:
- A partner API key (
x-auth-apikey) issued for your partner account. See Sign in with Rhombus → Working with partner accounts for how partner keys are minted. A partner user's OAuth access token works the same way, sent asAuthorization: Bearer <token>. - The client organization UUID of any client you want to act on. You don't have to know it up front — the first call below returns it.
- Familiarity with the standard authentication headers (
x-auth-scheme+x-auth-apikey) used everywhere else in the API.
The base URLs are the same as for any other Rhombus API call — there is no separate partner host. Use your region's base URLs (US shown here; EU organizations use the .eu. variants):
| Base URL | Purpose |
|---|---|
https://api2.rhombussystems.com | All API endpoints, partner and client-level |
https://media.rhombussystems.com | Media and streaming (clips, live streams, thumbnails) |
Partner keys are region-bound like any other API key, and a partner account and its client organizations live in the same region.
Two kinds of calls
Every request you make as a partner is one of two kinds. The difference is the endpoint path — and whether you scope the call to a specific client.
| Partner endpoints | Client-level endpoints | |
|---|---|---|
| Path prefix | /api/ | Everything else (/api/, /api/, /api/, …) |
| What they do | Manage your portfolio of clients: list orgs, register devices, check licenses, issue tokens | Operate inside one org: cameras, doors, sensors, users, events |
| Who can call them | Partner accounts only | Any account; a partner targets a specific client |
| Auth scheme | api-token (partner-api-token also accepted) | api-token (partner-api-token also accepted) |
x-auth-org header | Don't send it — it moves the call into that client org | Required — names the client org to act as |
The key idea: partner endpoints operate at the partner level, client-level endpoints operate inside one organization. A partner reaches into a client by adding the x-auth-org header — covered below. There are no "partner versions" of client endpoints; you call the same /api/camera/... endpoint a customer would, just with partner credentials and the x-auth-org header.
Authenticating as a partner
Partner credentials use the same schemes and headers as any other credential. api-token, api and api-oauth-token accept partner credentials, and partner-api-token, partner-api and partner-api-oauth-token are accepted as aliases for them. With a partner API key:
| Header | Value |
|---|---|
x-auth-scheme | api-token (or its alias partner-api-token) |
x-auth-apikey | Your partner API key |
Content-Type | application/ |
-H "x-auth-scheme: api-token" \
-H "x-auth-apikey: YOUR_PARTNER_API_KEY" \
-H "Content-Type: application/json"Create a partner API key in the Rhombus Console under Settings → API Management → Add API Key.
Other partner credentials. Partners using mutual-TLS (certificate-based) keys use x-auth-scheme: api (or partner-api) with their client certificate; certificate keys aren't accepted on the event WebSocket. A partner user's OAuth access token goes in Authorization: Bearer <token>. The token-based key shown throughout this guide is the simplest option and is recommended for most integrations.
Treat a partner API key like a master key. It can reach every organization you manage. Store it encrypted at rest, never commit it to source control, and rotate or revoke unused keys. A leaked partner key exposes all of your clients, not just one.
Scoping a call to a client organization
To make a client-level call on behalf of a managed client, add the x-auth-org header set to that client's organization UUID:
| Header | Value |
|---|---|
x-auth-org | The target client organization's UUID (base64 url-safe, ~22 chars, e.g. AAAAAAAAAAAAAAAAAAAAAA) |
With this header present, Rhombus treats the request as though it came from inside that client organization. The server checks that the client has granted your partner account access (login access, or management by your MSP) and that the grant hasn't expired; if not, the request is rejected with 403 PARTNER_CLIENT_ACCESS_DENIED. A value that isn't a valid organization UUID is rejected with 400 INVALID_AUTH_ORG. Inside the client org, the call can do what the role the client granted your partner account allows.
x-auth-orgis a header only. It's never read from a query parameter.- It means the same for every partner credential: partner API keys, partner certificate keys and partner OAuth access tokens.
- A blank value counts as absent.
- The API Reference lists it on every operation, and the Rhombus CLI sets it for its
--partner-orgflag.
Omit x-auth-org on /api/partner/... endpoints. Partner endpoints operate at the partner level; sending x-auth-org there moves the call into the client org, so it fails or acts on the wrong org.
Calls without x-auth-org
A partner credential that calls a client-level endpoint without x-auth-org still works, and acts in your partner organization, but the response carries two headers:
Deprecation: true
Sunset: Tue, 05 Jan 2027 00:00:00 GMTAfter January 5, 2027, those calls return an error. Send x-auth-org on every client-level call; the /api/partner/... endpoints don't need it. The event WebSocket already refuses a partner handshake without x-auth-org, with 403 PERMISSION_REQUIRED.
Examples
Step 1 — List your client organizations
Start with a partner endpoint to discover the orgs you manage and their UUIDs. POST /api/partner/getClientsV2 returns lightweight client records (name + UUID + device counts), ideal for quickly resolving a client UUID before acting on it.
curl -X POST https://api2.rhombussystems.com/api/partner/getClientsV2 \
-H "x-auth-scheme: api-token" \
-H "x-auth-apikey: YOUR_PARTNER_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'import requests
BASE_URL = "https://api2.rhombussystems.com"
headers = {
"x-auth-scheme": "api-token",
"x-auth-apikey": "YOUR_PARTNER_API_KEY",
"Content-Type": "application/json",
}
resp = requests.post(f"{BASE_URL}/api/partner/getClientsV2", headers=headers, json={})
resp.raise_for_status()
for client in resp.json().get("clients", []):
print(client["clientOrgName"], "->", client["clientOrgUuid"])const BASE_URL = "https://api2.rhombussystems.com";
const headers = {
"x-auth-scheme": "api-token",
"x-auth-apikey": "YOUR_PARTNER_API_KEY",
"Content-Type": "application/json",
};
const resp = await fetch(`${BASE_URL}/api/partner/getClientsV2`, {
method: "POST",
headers,
body: JSON.stringify({}),
});
const data = await resp.json();
for (const client of data.clients ?? []) {
console.log(`${client.clientOrgName} -> ${client.clientOrgUuid}`);
}package main
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
)
func main() {
req, _ := http.NewRequest("POST",
"https://api2.rhombussystems.com/api/partner/getClientsV2",
bytes.NewBufferString("{}"))
req.Header.Set("x-auth-scheme", "api-token")
req.Header.Set("x-auth-apikey", "YOUR_PARTNER_API_KEY")
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
var out struct {
Clients []struct {
ClientOrgName string `json:"clientOrgName"`
ClientOrgUUID string `json:"clientOrgUuid"`
} `json:"clients"`
}
json.NewDecoder(resp.Body).Decode(&out)
for _, c := range out.Clients {
fmt.Printf("%s -> %s\n", c.ClientOrgName, c.ClientOrgUUID)
}
}A response lists each managed client, including the clientOrgUuid you'll pass as x-auth-org:
{
"clients": [
{
"clientOrgName": "Acme Corporation",
"clientOrgUuid": "aB_cD1eF2gH3iJ4kL5mN6o",
"totalCameras": 25,
"totalLocations": 3
},
{
"clientOrgName": "Beta Industries",
"clientOrgUuid": "nO_pQ6rS7tU8vW9xY0zZ",
"totalCameras": 12,
"totalLocations": 1
}
]
}Step 2 — Call a client-level endpoint as a managed client
Now use a client UUID from Step 1 in the x-auth-org header to call a regular client-level endpoint — here, listing a client's cameras with POST /api/camera/getMinimalCameraStateList. Note this is not a partner endpoint; it's the same camera endpoint any organization uses, scoped to your client by the header.
curl -X POST https://api2.rhombussystems.com/api/camera/getMinimalCameraStateList \
-H "x-auth-scheme: api-token" \
-H "x-auth-apikey: YOUR_PARTNER_API_KEY" \
-H "x-auth-org: aB_cD1eF2gH3iJ4kL5mN6o" \
-H "Content-Type: application/json" \
-d '{}'import requests
BASE_URL = "https://api2.rhombussystems.com"
CLIENT_ORG_UUID = "aB_cD1eF2gH3iJ4kL5mN6o"
headers = {
"x-auth-scheme": "api-token",
"x-auth-apikey": "YOUR_PARTNER_API_KEY",
"x-auth-org": CLIENT_ORG_UUID, # act as this managed client
"Content-Type": "application/json",
}
resp = requests.post(
f"{BASE_URL}/api/camera/getMinimalCameraStateList",
headers=headers,
json={},
)
resp.raise_for_status()
print(resp.json().get("cameraStates", []))const BASE_URL = "https://api2.rhombussystems.com";
const CLIENT_ORG_UUID = "aB_cD1eF2gH3iJ4kL5mN6o";
const headers = {
"x-auth-scheme": "api-token",
"x-auth-apikey": "YOUR_PARTNER_API_KEY",
"x-auth-org": CLIENT_ORG_UUID, // act as this managed client
"Content-Type": "application/json",
};
const resp = await fetch(`${BASE_URL}/api/camera/getMinimalCameraStateList`, {
method: "POST",
headers,
body: JSON.stringify({}),
});
console.log((await resp.json()).cameraStates);package main
import (
"bytes"
"net/http"
)
func main() {
clientOrgUUID := "aB_cD1eF2gH3iJ4kL5mN6o"
req, _ := http.NewRequest("POST",
"https://api2.rhombussystems.com/api/camera/getMinimalCameraStateList",
bytes.NewBufferString("{}"))
req.Header.Set("x-auth-scheme", "api-token")
req.Header.Set("x-auth-apikey", "YOUR_PARTNER_API_KEY")
req.Header.Set("x-auth-org", clientOrgUUID) // act as this managed client
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
// decode resp.Body...
}Drop the x-auth-org header and the same call would target your partner organization instead of the client — which usually has no cameras of its own — and the response would carry the Deprecation and Sunset headers described in Calls without x-auth-org. The header is what redirects the call into the managed client.
The CLI does this for you
The Rhombus CLI wraps the same mechanism behind a --partner-org flag, accepting either a client UUID or name and setting x-auth-org for you:
# By UUID
rhombus --partner-org aB_cD1eF2gH3iJ4kL5mN6o camera get-minimal-camera-state-list
# By client name (the CLI resolves it to a UUID via getClientsV2)
rhombus --partner-org "Acme Corporation" camera get-minimal-camera-state-listWebSocket connections
Real-time partner connections use the same credentials. On the WebSocket handshake, send x-auth-apikey and x-auth-org as HTTP headers. x-auth-scheme can go in the query string or a header. x-auth-org is not read from the query string, and it's required: a partner handshake without it is refused with 403 PERMISSION_REQUIRED. Browsers can't set custom headers on a WebSocket handshake, so connect from a server-side client. See WebSocket Authentication for the full pattern.
URL: wss://ws.rhombussystems.com:8443/websocket?x-auth-scheme=api-token
Headers: x-auth-apikey: YOUR_PARTNER_API_KEY
x-auth-org: aB_cD1eF2gH3iJ4kL5mN6oPartner endpoint reference
These /api/partner/... endpoints operate at the partner level and require a partner credential. All are POST. Browse full request/response schemas in the API Reference.
| Purpose | Endpoint | What it does |
|---|---|---|
| Clients | getClients | List all client organizations (full info) |
getClientsV2 | List clients with basic info — fastest way to resolve client UUIDs | |
getClientSummaryInfo | Summary for a single client | |
getClientStatusMap | Aggregated device and location status across clients | |
createPartnerClient | Create a new client organization | |
customizeClient | Customize a client account | |
deleteClient | Delete a client organization | |
| Devices | getClientDevices | Devices for a specific client |
getListOfAllClientDevices | Devices across every managed client | |
getListOfAvailableHardware | Hardware available for registration | |
getClaimKeysForPartnerOrg | Claim keys for the partner org | |
registerCameraToClient | Register a camera to a client org | |
reassignDeviceOrg | Move a device from one client org to another | |
customizeClientDevice | Customize a client device | |
| Licensing | getLicensesForOrg | Licenses available to a client org |
getDeviceLicensesForOrg | Device-specific licenses for a client org | |
updateSendLicenseExpirationEmail | Toggle license-expiration email alerts | |
| API tokens | getApiTokens | List the partner's active API tokens |
getApiTokenApplications | List pending token applications | |
revokeApiToken | Revoke a partner API token | |
| Sales | registerDeal | Register a deal/opportunity |
getShipments | Shipments for a specific client |
Partner API keys
Create partner keys in the console under Settings → API Management, or with the API. These endpoints run at the partner level, so call them without x-auth-org. All are POST:
| Action | Endpoint | Body | Response |
|---|---|---|---|
| Create | /api/ | displayName, permissionGroupUuid (a partner role), authType (API_TOKEN or CERT with a csr), expiresAtMs | apiKey, tokenUuid, expiresAtMs; for certificate keys, cert and certNotAfterMs |
| Rotate | /api/ | tokenUuid, optional overlapSec (default 86400, at most 2592000), csr (required for certificate keys), expiresAtMs | The create fields plus previousKeyExpiresAtMs |
| Renew a certificate | /api/ | csr, and tokenUuid unless a certificate key renews its own certificate | cert, certNotAfterMs |
- Who can call them: a partner console or mobile app session, a partner user's OAuth access token (with all three scopes), or a partner API key, whose partner role includes API administration. Federated tokens can't.
- When the caller is a partner API key,
expiresAtMsis required: at most 365 days from now, and no later than the calling key's own expiry. The new key is deleted when the calling key is deleted. A key creates and rotates keys only in its own organization, so a partner key that sendsx-auth-orgto these endpoints gets 403. - Rotation issues a key with the same role and keeps the old key working for
overlapSecseconds;previousKeyExpiresAtMssays when it stops. - Renewal keeps the same key and issues a new certificate, with no overlap. Partner certificates last 365 days, and a CSR whose signature doesn't verify is rejected.
- Expired keys get 401
CREDENTIAL_EXPIREDand still appear ingetApiTokensuntil you revoke them.
# Rotate a partner key; the old key keeps working for one day.
EXPIRES_AT_MS=$(( ($(date +%s) + 90 * 86400) * 1000 ))
curl -X POST "https://api2.rhombussystems.com/api/partner/rotateApiToken" \
-H "x-auth-scheme: api-token" \
-H "x-auth-apikey: YOUR_PARTNER_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"tokenUuid\": \"OLD_TOKEN_UUID\", \"overlapSec\": 86400, \"expiresAtMs\": $EXPIRES_AT_MS}"Manage keys with the API documents the same fields for organization keys. To mint a partner key from a partner user's sign-in, see Sign in with Rhombus → Working with partner accounts.
Troubleshooting
401 Unauthorized
A 401 means the credential is missing, malformed, unknown, expired or revoked. The body's errorCode says which: UNAUTHENTICATED (no credential sent), INVALID_CREDENTIAL (a malformed value, or a key that was deleted or belongs to the other region), CREDENTIAL_EXPIRED, CREDENTIAL_REVOKED, or CERTIFICATE_MISMATCH (a certificate issued for a different key). Check x-auth-scheme and that the key is in x-auth-apikey.
400 INVALID_AUTH_ORG
The x-auth-org value isn't a valid organization UUID. Copy the exact clientOrgUuid from getClientsV2: these are base64 url-safe UUIDs (~22 chars), so a truncated or re-encoded value is rejected.
403 Forbidden, or the call targets the wrong org
PARTNER_CLIENT_ACCESS_DENIED means your partner account doesn't have access to the x-auth-org organization: it isn't a client you manage, or its grant to you has expired. Re-fetch the list with getClientsV2 and copy the exact clientOrgUuid. PERMISSION_REQUIRED means the credential is valid but the role (or, for an OAuth token, its scopes) doesn't allow the call. A standard organization key can't reach other organizations, whatever x-auth-org you send.
An empty or unexpected response on a client endpoint
If you forgot x-auth-org, the call ran against your partner organization (which typically owns no cameras, doors, or sensors) and returned an empty list; the response also carries Deprecation and Sunset headers. Add the header to scope the call into the client.
A /api/partner/ endpoint fails or acts on the wrong org
Don't send x-auth-org to partner endpoints: it moves the call into the client org. Use the endpoint's own request body (for example, the orgUuid field on registerCameraToClient) to say which client an action applies to.
Partner auth fails over WebSocket
The event WebSocket doesn't accept certificate keys. Generate a token-based key and use api-token. On the handshake, x-auth-scheme may be a query parameter, but x-auth-apikey and x-auth-org must be HTTP headers. A partner handshake without x-auth-org is refused with 403 PERMISSION_REQUIRED. See WebSocket Authentication.
Next steps
Obtain partner credentials and mint long-lived partner keys
Open real-time partner connections scoped to a client org
Use --partner-org to run any command against a managed client
Browse every partner and client-level endpoint