# Rhombus API Authentication

> How automated clients — scripts, integrations, and AI agents — authenticate to the Rhombus public API.

## Hosts

| Host | Role |
| --- | --- |
| `api2.rhombussystems.com` | Resource server — all API calls (`https://api2.rhombussystems.com/api/...`) |
| `console.rhombus.com` | Interactive sign-in and OAuth authorization |
| `auth.rhombussystems.com` | OAuth token, refresh, revocation, and client registration endpoints |

## Discover

Machine-readable discovery documents (RFC 8414 two-hop flow: fetch the protected-resource metadata on the resource server, then the authorization-server metadata at the issuer it names):

1. **Protected resource metadata (RFC 9728)**: <https://api2.rhombussystems.com/.well-known/oauth-protected-resource> — names the resource (`https://api2.rhombussystems.com`) and its authorization server.
2. **Authorization server metadata (RFC 8414)**: <https://auth-web.rhombussystems.com/.well-known/oauth-authorization-server> (also at <https://auth.rhombussystems.com/oauth/.well-known/oauth-authorization-server>) — lists the authorization, token, revocation, and registration endpoints, supported grants, and PKCE methods.
3. Unauthenticated API requests return `401` with `WWW-Authenticate: Bearer resource_metadata="https://api2.rhombussystems.com/.well-known/oauth-protected-resource"`, so a single probe discovers this entire chain.

Other references: [OpenAPI 3.0 spec](https://api2.rhombussystems.com/api/openapi/public.json) · [developer docs](https://api-docs.rhombus.community/) ([llms.txt index](https://api-docs.rhombus.community/llms.txt)) · [API catalog (RFC 9727)](https://www.rhombus.com/.well-known/api-catalog)

## Pick a method

| Your situation | Use | Why |
| --- | --- | --- |
| Agent, script, or server-to-server integration acting as one Rhombus account | **API key** (Option 1) | Single header pair, no browser, available on every plan |
| Third-party app where Rhombus customers sign in to *your* product | **OAuth 2.0 + PKCE** (Option 2) | Per-user consent, refresh tokens, revocation |
| You only have a browser session (no key yet) | Create an API key first | Keys are self-serve in the [Console](https://console.rhombus.com/settings/api-management) |

There is no anonymous access: every API call requires one of the two credentials above.

## Option 1: API key (recommended for agents and server-to-server)

### Register (get a credential)

1. Sign in to the [Rhombus Console](https://console.rhombus.com/) and create a key under **Settings → API Management** (<https://console.rhombus.com/settings/api-management>).
2. The key is shown once at creation — store it securely.
3. A key inherits the permissions of the user who created it; scope access by creating the key from a least-privilege user or role.

### Use the credential

Send two headers on every request:

```http
POST /api/camera/getMinimalCameraStateList HTTP/1.1
Host: api2.rhombussystems.com
Content-Type: application/json
x-auth-scheme: api-token
x-auth-apikey: YOUR_API_KEY

{}
```

Notes for agents:

- All endpoints are `POST` with JSON request bodies (use `{}` when no parameters are needed).
- Responses are JSON; errors are JSON (see [Errors](#errors)).

## Option 2: OAuth 2.0 — authorization code with PKCE (acting on behalf of a user)

Rhombus supports "Sign in with Rhombus" via OAuth 2.0 authorization code flow with PKCE (S256). Full guide: <https://api-docs.rhombus.community/oauth-authentication>.

### Register (get a client)

`POST https://api2.rhombussystems.com/api/oauth/submitApplication` (authenticated with an API key) returns a `clientId` and `clientSecret`:

```json
{
  "name": "Acme Console",
  "description": "Acme dashboard for Rhombus operators",
  "contactEmail": "engineering@acme.example",
  "redirectUri": "https://acme.example/oauth/callback"
}
```

Response:

```json
{
  "clientId": "abc123...",
  "clientSecret": "shh-shown-once..."
}
```

Store the `clientSecret` securely — it is not retrievable later. Production apps distributed to other organizations require Rhombus review (start in the [developer community](https://rhombus.community/)).

### Authorize and claim the credential

1. Redirect the user to `https://console.rhombus.com/oauth/authorize` with `client_id`, `redirect_uri`, `response_type=code`, `state`, `code_challenge`, and `code_challenge_method=S256`.
2. After approval the user returns to your `redirect_uri` with `?code=...&state=...`; verify `state`.
3. **Claim**: exchange the code at `POST https://auth.rhombussystems.com/oauth/token` (header `x-auth-scheme: web2`) with the authorization code and PKCE `code_verifier`. Response:

```json
{
  "accessToken": "eyJ...",
  "refreshToken": "def50200...",
  "accessTokenExpirationSec": 3600
}
```

### Use the credential

```http
POST /api/camera/getMinimalCameraStateList HTTP/1.1
Host: api2.rhombussystems.com
Content-Type: application/json
x-auth-scheme: api-oauth-token
x-auth-access-token: ACCESS_TOKEN

{}
```

### Refresh and revoke

- **Refresh**: `POST https://auth.rhombussystems.com/oauth/token` with `grant_type=refresh_token` and your `refreshToken` returns a fresh `accessToken`.
- **Revoke**: `POST https://auth.rhombussystems.com/oauth/token/revoke` invalidates a token (RFC 7009 style; see the RFC 8414 metadata for the canonical `revocation_endpoint`).

Supported, per the [RFC 8414 metadata](https://auth-web.rhombussystems.com/.well-known/oauth-authorization-server): `authorization_code` and `refresh_token` grants, `code` response type, PKCE `S256`, `client_secret_basic` and `client_secret_post` client authentication, and dynamic client registration.

## Errors

All API errors are JSON. Canonical shapes and remediation:

| HTTP | Body shape | Meaning | What an agent should do |
| --- | --- | --- | --- |
| `401` | `{"authenticationFailed": true}` + `WWW-Authenticate: Bearer resource_metadata="..."` | No credential, or the request matched no auth scheme | Read the RFC 9728 document from the challenge header, obtain a credential per this guide, retry |
| `403` | `{"status": 403, "error": "Forbidden", "timestamp": ..., "msg": "Access Denied"}` | Credential present but invalid, expired, or lacking permission | Re-check the key/token; if expired OAuth, refresh at the token endpoint; if permissions, the key's owning user needs a broader role |
| `429` | JSON error body | Rate limited | Back off and retry with exponential delay; see [rate limits](https://api-docs.rhombus.community/rate-limits) |
| `4xx` | `{"error": ..., "msg": ...}` | Malformed request (bad JSON, missing fields) | Validate the request body against the [OpenAPI spec](https://api2.rhombussystems.com/api/openapi/public.json) |

Expired OAuth access tokens: claim a new one with `grant_type=refresh_token` (see [Refresh and revoke](#refresh-and-revoke)). Revoked or deleted API keys cannot be recovered — create a new key in the Console.

## Rate limits and support

- Rate limits: <https://api-docs.rhombus.community/rate-limits>
- Developer community: <https://rhombus.community/>
- Security contact: `security@rhombussystems.com` (see `/.well-known/security.txt`)
