API reference
A region-scoped REST API and a matching gRPC service. Authenticate with a secret key, send and receive JSON, and page through everything the SDKs expose.
Every OrthID capability is reachable over HTTP. The REST API is the primary surface and is what the typed SDKs wrap; the gRPC service mirrors it for low-latency, server-to-server callers. Both speak the same resources, scopes and error model, so what you learn here applies to the SDKs too.
Base URL
There is no global endpoint. Each region is addressed directly, which is how OrthID keeps requests inside their sovereign boundary:
https://api.<region>.orthid.com # for example https://api.au-syd-1.orthid.com https://api.eu-fra-1.orthid.com
A key issued in one region is only valid against that region’s host. Sending it elsewhere returns region_mismatch. See Regions for the full list.
Authentication
Authenticate server-to-server with your secret key as a Bearer token. Keep ORTHID_SECRET_KEY on the server only - it must never reach the browser, where you use the publishable key instead.
curl https://api.au-syd-1.orthid.com/v1/users/user_5f3a \ -H "Authorization: Bearer $ORTHID_SECRET_KEY"
The typed SDK reads the same key and region from the environment:
import { orthid } from "@orthid/sdk";
// Reads ORTHID_SECRET_KEY and ORTHID_REGION from the environment.
const user = await orthid.users.get("user_5f3a");
console.log(user.id, user.email);Core endpoints
Resources are organised around the three actors - users, organisations and agents - plus sessions and audit. These are the most-used routes; the SDKs cover the full set.
| Method | Path | Description |
|---|---|---|
GET | /v1/users | List users in the tenant. |
GET | /v1/users/:id | Retrieve a single user. |
POST | /v1/organizations | Create an organisation. |
POST | /v1/organizations/:id/members | Add a member to an organisation. |
POST | /v1/sessions/verify | Verify a session token and return its actor. |
POST | /v1/agents | Issue a scoped, expiring agent credential. |
GET | /v1/audit | Page through the immutable audit log. |
Pagination
List endpoints are cursor-paginated. Pass limit (default 25, max 100) and follow next_cursor until it is null. Cursors are opaque and stable; do not construct them yourself.
{
"data": [ { "id": "user_5f3a", "email": "ada@example.org" } ],
"has_more": true,
"next_cursor": "eyJpZCI6InVzZXJfNWYzYSJ9"
}Errors
Errors use standard HTTP status codes with a typed JSON body. The code field is stable and safe to branch on; the message is for humans and may change.
HTTP/1.1 403 Forbidden
{
"error": {
"code": "insufficient_scope",
"message": "Token is missing the required 'users:read' scope.",
"request_id": "req_8b21d0"
}
}Common codes:
401 invalid_key- the secret key is missing, malformed or revoked.403 insufficient_scope- the actor lacks a required scope.404 not_found- no such resource in this tenant.409 region_mismatch- the key does not belong to this region.429 rate_limited- too many requests; back off.
Always log request_id - quoting it lets support trace a single call through the audit log.
Rate limits
Limits are applied per secret key. Each response carries your current budget so you can throttle yourself before you are throttled:
X-RateLimit-Limit: 600 X-RateLimit-Remaining: 597 X-RateLimit-Reset: 1750550400
429, read Retry-After and retry with exponential backoff and jitter. The SDKs do this for you; if you call the REST API directly, build it in from the start.Next steps
- SDK reference - typed clients that wrap every endpoint here.
- Tokens & token exchange - what
sessions.verifyreturns and how delegation works. - Regions - choose the base URL for your deployment.