Authentication & API keys

How Orion authenticates requests — API keys for data, bearer tokens for account management, and the key lifecycle.

Orion uses two credential types:

  • API keys authenticate every data request, sent in the x-orion-api-key header. This is what you use to read positions, activities, and protocol data.
  • Bearer tokens (JWT) authenticate organization-management requests — reading your org, listing keys, revoking keys. You get them by logging in.

Data endpoints never accept a bearer token, and management endpoints never accept an API key.

API keys

Send your key on every data request:

curl https://query.orionhq.run/v1/users/GABC7XYZ.../positions \
  -H "x-orion-api-key: sk-orion-...your-key..."

A key value is shown exactly once, at creation. Orion stores only a hash — listing keys returns their metadata and prefix, never the full secret. If you lose a key, revoke it and mint a new one.

Create a key

POST /v1/org/api-keys creates an organization and its first key. It is authorized by an x-orion-admin-token header rather than a bearer token.

curl -X POST https://query.orionhq.run/v1/org/api-keys \
  -H "x-orion-admin-token: ...admin-token..." \
  -H "content-type: application/json" \
  -d '{
    "organization_name": "Acme Analytics",
    "organization_slug": "acme",
    "key_name": "production",
    "scopes": ["data:read"]
  }'

201 Created:

{
  "organization_id": "org_a1b2c3",
  "organization_slug": "acme",
  "organization_reused": false,
  "api_key_id": "key_9f8e7d",
  "key_prefix": "sk-orion-9f8e",
  "scopes": ["data:read"],
  "key": "sk-orion-...full-secret-shown-once...",
  "expires_at": null
}

Store key immediately — it is the only time the full value appears.

FieldTypeNotes
organization_namestringRequired. Display name for the organization.
organization_slugstringRequired. URL-safe identifier; reused if the org already exists.
key_namestringRequired. Label for the key, shown in listings.
scopesstring[]Optional. Defaults to ["data:read"].
expires_atstring | nullOptional RFC 3339 expiry. Omit or null for no expiry.

List keys

GET /v1/org/api-keys returns every key on the organization — prefixes and metadata only, never raw values.

curl https://query.orionhq.run/v1/org/api-keys \
  -H "authorization: Bearer <access_token>"
[
  {
    "id": "key_9f8e7d",
    "name": "production",
    "prefix": "sk-orion-9f8e",
    "scopes": ["data:read"],
    "revoked": false,
    "created_at": "2026-07-20T14:03:00Z",
    "last_used_at": "2026-07-23T09:12:44Z",
    "expires_at": null
  }
]

Revoke a key

DELETE /v1/org/api-keys/{id} revokes a key by its id. A revoked key is refused on every subsequent request.

curl -X DELETE https://query.orionhq.run/v1/org/api-keys/key_9f8e7d \
  -H "authorization: Bearer <access_token>"

Returns 204 No Content on success, or 404 if the id is unknown or belongs to another organization.

Bearer tokens

Management endpoints (GET /v1/org, listing and revoking keys) authenticate with a JWT access token in the authorization header.

Log in

POST /v1/auth/login exchanges credentials for a token pair:

curl -X POST https://query.orionhq.run/v1/auth/login \
  -H "content-type: application/json" \
  -d '{ "email": "you@acme.com", "password": "..." }'
{
  "access_token": "eyJhbGciOi...",
  "refresh_token": "eyJhbGciOi...",
  "expires_in": 3600
}

expires_in is the access token lifetime in seconds. Send the access token as authorization: Bearer <access_token> on management requests.

Refresh

When the access token expires, exchange the refresh token for a fresh one with POST /v1/auth/refresh — no need to log in again:

curl -X POST https://query.orionhq.run/v1/auth/refresh \
  -H "content-type: application/json" \
  -d '{ "refresh_token": "eyJhbGciOi..." }'
{
  "access_token": "eyJhbGciOi...",
  "expires_in": 3600
}

Errors

Authentication failures return the standard error envelope:

{
  "error": {
    "code": "unauthorized",
    "message": "Missing or invalid API key"
  },
  "meta": { "...": "response metadata" }
}
StatusWhen
401Missing, invalid, revoked, or expired credential.
404Revoking a key id that doesn’t belong to your organization.
429Rate limit for your organization exceeded.