API reference · v1.0.0

Olympus Platform API

Download OpenAPI (platform.yaml) · Base URL https://api.olympus.new-odyssey.com

Accounts, organizations, API keys and usage for Olympus, government data infrastructure by New Odyssey.

Console endpoints (/v1/auth/*, /v1/me, /v1/organizations/*) are used by the developer console. They authenticate with an HttpOnly session cookie set by POST /v1/auth/login. Every state-changing console request (POST, PATCH, DELETE), signed in or not, must send the X-Olympus-CSRF header (any non-empty value); browsers must also send an Origin (or Referer) that is an allowed console origin.

Customer endpoints (/v1/usage and every product under /v1/<product>/...) authenticate with an API key in X-API-Key or Authorization: Bearer. Product requests also require the organization's plan to include the product, and count against its monthly quota.

Every response carries X-Request-Id. Errors share the Error body. Responses never reveal whether an email address is registered.

Health

Liveness

GET/health

Authentication: None

Responses

200

The process is serving.

Health

Liveness

GET/health/live

Authentication: None

Responses

200

The process is serving.

Health

Readiness (database and Redis)

GET/health/ready

Authentication: None

Responses

200

Dependencies are healthy.

Health
503

A dependency is unhealthy.

Health

Auth

Create an account

POST/v1/auth/signup

Creates a user, a personal organization owned by the user and a Free plan subscription, then emails a verification link. Always answers 202 for a well-formed request; if the address is already registered, its owner is emailed a notice instead. Sign in with POST /v1/auth/login afterwards.

Authentication: X-Olympus-CSRF header

Request body

application/json — SignupRequest

Responses

202

Accepted.

400

Invalid fields (VALIDATION_ERROR, details.fields maps field to reason) or malformed body (BAD_REQUEST).

Error
403

Missing CSRF header or disallowed origin (CSRF_FAILED).

Error
429

Too many attempts (TOO_MANY_ATTEMPTS); see Retry-After.

Error

Verify an email address

POST/v1/auth/verify-email

Consumes a single-use verification token from the emailed link.

Authentication: X-Olympus-CSRF header

Request body

application/json — TokenRequest

Responses

200

The email address is verified.

400

Invalid, used or expired token (INVALID_TOKEN).

Error
403

Missing CSRF header or disallowed origin (CSRF_FAILED).

Error
429

Too many attempts (TOO_MANY_ATTEMPTS); see Retry-After.

Error

Resend the verification email

POST/v1/auth/resend-verification

Authentication: Console session cookie + X-Olympus-CSRF header

Responses

202

Accepted.

401

No valid session (UNAUTHENTICATED).

Error
403

Missing CSRF header or disallowed origin (CSRF_FAILED).

Error
409

The email address is already verified (EMAIL_ALREADY_VERIFIED).

Error
429

Too many attempts (TOO_MANY_ATTEMPTS); see Retry-After.

Error

Sign in

POST/v1/auth/login

Sets the session cookie. Unknown addresses and wrong passwords both answer 401 INVALID_CREDENTIALS. Attempts are throttled per address and per client IP.

Authentication: X-Olympus-CSRF header

Request body

application/json — LoginRequest

Responses

200

Signed in.

LoginResponse
400

Malformed request (BAD_REQUEST).

Error
401

Invalid email or password (INVALID_CREDENTIALS).

Error
403

CSRF check failed (CSRF_FAILED) or the account is disabled (ACCOUNT_DISABLED).

Error
429

Too many attempts (TOO_MANY_ATTEMPTS); see Retry-After.

Error

Sign out

POST/v1/auth/logout

Revokes the current session and clears the cookie.

Authentication: Console session cookie + X-Olympus-CSRF header

Responses

204

Signed out.

401

No valid session (UNAUTHENTICATED).

Error
403

Missing CSRF header or disallowed origin (CSRF_FAILED).

Error

Request a password reset email

POST/v1/auth/forgot-password

Always answers 202 for a valid address, whether or not an account exists.

Authentication: X-Olympus-CSRF header

Request body

application/json — object

Responses

202

Accepted.

400

Invalid fields (VALIDATION_ERROR, details.fields maps field to reason) or malformed body (BAD_REQUEST).

Error
403

Missing CSRF header or disallowed origin (CSRF_FAILED).

Error
429

Too many attempts (TOO_MANY_ATTEMPTS); see Retry-After.

Error

Set a new password with a reset token

POST/v1/auth/reset-password

Consumes the single-use token, sets the password, verifies the email address and revokes every session of the user.

Authentication: X-Olympus-CSRF header

Request body

application/json — object

Responses

204

Password changed. Sign in again.

400

Invalid password (VALIDATION_ERROR) or invalid or expired token (INVALID_TOKEN).

Error
403

Missing CSRF header or disallowed origin (CSRF_FAILED).

Error
429

Too many attempts (TOO_MANY_ATTEMPTS); see Retry-After.

Error

The signed-in user and their organizations

GET/v1/me

Authentication: Console session cookie

Responses

200

The signed-in user.

Me
401

No valid session (UNAUTHENTICATED).

Error

Organizations

List my organizations

GET/v1/organizations

Authentication: Console session cookie

Responses

200

Organizations the user belongs to.

401

No valid session (UNAUTHENTICATED).

Error

Get an organization with its plan and entitlements

GET/v1/organizations/{org_id}

Authentication: Console session cookie

Parameters

NameInTypeDescription
org_idrequiredpathstring (uuid)

Organization ID. Organizations the caller does not belong to answer 404.

Responses

200

The organization.

OrganizationDetail
401

No valid session (UNAUTHENTICATED).

Error
404

Not found, or not visible to the caller (NOT_FOUND).

Error

Members

List members

GET/v1/organizations/{org_id}/members

Authentication: Console session cookie

Parameters

NameInTypeDescription
org_idrequiredpathstring (uuid)

Organization ID. Organizations the caller does not belong to answer 404.

Responses

200

Members of the organization.

401

No valid session (UNAUTHENTICATED).

Error
404

Not found, or not visible to the caller (NOT_FOUND).

Error

Change a member's role

PATCH/v1/organizations/{org_id}/members/{user_id}

Owners and admins may change roles; only owners may grant the owner role or change an owner. The last owner cannot be demoted.

Authentication: Console session cookie + X-Olympus-CSRF header

Parameters

NameInTypeDescription
org_idrequiredpathstring (uuid)

Organization ID. Organizations the caller does not belong to answer 404.

user_idrequiredpathstring (uuid)

Request body

application/json — object

Responses

200

The updated member.

Member
400

Invalid fields (VALIDATION_ERROR, details.fields maps field to reason) or malformed body (BAD_REQUEST).

Error
401

No valid session (UNAUTHENTICATED).

Error
403

Insufficient role (INSUFFICIENT_ROLE), unverified email (EMAIL_NOT_VERIFIED) or CSRF failure (CSRF_FAILED).

Error
404

Not found, or not visible to the caller (NOT_FOUND).

Error
409

The organization must keep at least one owner (LAST_OWNER).

Error

Remove a member

DELETE/v1/organizations/{org_id}/members/{user_id}

Any member may remove themselves. Owners and admins may remove others; only owners may remove an owner. The last owner cannot be removed.

Authentication: Console session cookie + X-Olympus-CSRF header

Parameters

NameInTypeDescription
org_idrequiredpathstring (uuid)

Organization ID. Organizations the caller does not belong to answer 404.

user_idrequiredpathstring (uuid)

Responses

204

Removed.

401

No valid session (UNAUTHENTICATED).

Error
403

Insufficient role (INSUFFICIENT_ROLE), unverified email (EMAIL_NOT_VERIFIED) or CSRF failure (CSRF_FAILED).

Error
404

Not found, or not visible to the caller (NOT_FOUND).

Error
409

The organization must keep at least one owner (LAST_OWNER).

Error

API keys

List API keys (secrets are never returned)

GET/v1/organizations/{org_id}/api-keys

Authentication: Console session cookie

Parameters

NameInTypeDescription
org_idrequiredpathstring (uuid)

Organization ID. Organizations the caller does not belong to answer 404.

Responses

200

API keys, newest first, including revoked ones.

401

No valid session (UNAUTHENTICATED).

Error
404

Not found, or not visible to the caller (NOT_FOUND).

Error

Create an API key

POST/v1/organizations/{org_id}/api-keys

Owners and admins with a verified email address only. The response contains the secret; it is shown once and cannot be retrieved again. At most 50 unrevoked keys per organization.

Authentication: Console session cookie + X-Olympus-CSRF header

Parameters

NameInTypeDescription
org_idrequiredpathstring (uuid)

Organization ID. Organizations the caller does not belong to answer 404.

Request body

application/json — object

Responses

201

The new key, with its secret.

CreatedAPIKey
400

Invalid fields (VALIDATION_ERROR, details.fields maps field to reason) or malformed body (BAD_REQUEST).

Error
401

No valid session (UNAUTHENTICATED).

Error
403

Insufficient role (INSUFFICIENT_ROLE), unverified email (EMAIL_NOT_VERIFIED) or CSRF failure (CSRF_FAILED).

Error
404

Not found, or not visible to the caller (NOT_FOUND).

Error
409

Too many keys (API_KEY_LIMIT_REACHED).

Error

Revoke an API key

DELETE/v1/organizations/{org_id}/api-keys/{key_id}

The key stops working immediately. Its record is kept for usage history and the audit log.

Authentication: Console session cookie + X-Olympus-CSRF header

Parameters

NameInTypeDescription
org_idrequiredpathstring (uuid)

Organization ID. Organizations the caller does not belong to answer 404.

key_idrequiredpathinteger (int64)

Responses

204

Revoked.

401

No valid session (UNAUTHENTICATED).

Error
403

Insufficient role (INSUFFICIENT_ROLE), unverified email (EMAIL_NOT_VERIFIED) or CSRF failure (CSRF_FAILED).

Error
404

Not found, or not visible to the caller (NOT_FOUND).

Error
409

The API key is already revoked (API_KEY_REVOKED).

Error

Rotate an API key

POST/v1/organizations/{org_id}/api-keys/{key_id}/rotate

Creates a key with the same name and environment and revokes the old one, atomically. The new secret is shown once.

Authentication: Console session cookie + X-Olympus-CSRF header

Parameters

NameInTypeDescription
org_idrequiredpathstring (uuid)

Organization ID. Organizations the caller does not belong to answer 404.

key_idrequiredpathinteger (int64)

Responses

201

The replacement key, with its secret.

CreatedAPIKey
401

No valid session (UNAUTHENTICATED).

Error
403

Insufficient role (INSUFFICIENT_ROLE), unverified email (EMAIL_NOT_VERIFIED) or CSRF failure (CSRF_FAILED).

Error
404

Not found, or not visible to the caller (NOT_FOUND).

Error
409

The API key is already revoked (API_KEY_REVOKED).

Error

Usage

Organization usage (console)

GET/v1/organizations/{org_id}/usage

Authentication: Console session cookie

Parameters

NameInTypeDescription
org_idrequiredpathstring (uuid)

Organization ID. Organizations the caller does not belong to answer 404.

fromquerystring (date)

First UTC day (inclusive). Defaults to 29 days before to.

toquerystring (date)

Last UTC day (inclusive). Defaults to today. The range may cover at most 90 days.

productquerystring

Only this product (e.g. geo-demographics, sec, platform).

api_key_idqueryinteger (int64)

Only this API key of the organization.

Responses

200

Usage summary.

UsageSummary
400

Invalid fields (VALIDATION_ERROR, details.fields maps field to reason) or malformed body (BAD_REQUEST).

Error
401

No valid session (UNAUTHENTICATED).

Error
404

Not found, or not visible to the caller (NOT_FOUND).

Error

Usage for the API key's organization

GET/v1/usage

Metered requests across every product and key of the caller's organization. Requests to this endpoint are themselves metered as product platform.

Authentication: API key (X-API-Key or Bearer)

Parameters

NameInTypeDescription
fromquerystring (date)

First UTC day (inclusive). Defaults to 29 days before to.

toquerystring (date)

Last UTC day (inclusive). Defaults to today. The range may cover at most 90 days.

productquerystring

Only this product (e.g. geo-demographics, sec, platform).

api_key_idqueryinteger (int64)

Only this API key of the organization.

Responses

200

Usage summary.

UsageSummary
400

Invalid fields (VALIDATION_ERROR, details.fields maps field to reason) or malformed body (BAD_REQUEST).

Error
401

Missing or invalid API key (UNAUTHORIZED), or a disabled, expired or revoked one (API_KEY_DISABLED, API_KEY_EXPIRED, API_KEY_REVOKED).

Error
403

Organization suspended (ORGANIZATION_SUSPENDED), no live subscription (NO_ACTIVE_SUBSCRIPTION) or, on product endpoints, product not on the plan (PRODUCT_NOT_ENABLED) or a key scoped to another product (API_KEY_PRODUCT_SCOPE).

Error
429

Per-minute rate limit exceeded (RATE_LIMIT_EXCEEDED) or, on product endpoints, monthly quota exhausted (QUOTA_EXCEEDED, with X-Quota-* headers).

Error
curl
curl -s "https://api.olympus.new-odyssey.com/v1/usage" \
  -H "X-API-Key: $OLYMPUS_API_KEY"

Audit

List audit events (owners and admins)

GET/v1/organizations/{org_id}/audit-log

Authentication: Console session cookie

Parameters

NameInTypeDescription
org_idrequiredpathstring (uuid)

Organization ID. Organizations the caller does not belong to answer 404.

beforequeryinteger (int64)

Return events older than this event ID (the previous page's next_before).

limitqueryinteger

Responses

200

Events, newest first.

400

Invalid fields (VALIDATION_ERROR, details.fields maps field to reason) or malformed body (BAD_REQUEST).

Error
401

No valid session (UNAUTHENTICATED).

Error
403

Insufficient role (INSUFFICIENT_ROLE), unverified email (EMAIL_NOT_VERIFIED) or CSRF failure (CSRF_FAILED).

Error
404

Not found, or not visible to the caller (NOT_FOUND).

Error

Schemas

Error object

The error body shared by every Olympus service.

FieldTypeDescription
error *string

Human-readable message.

code *string

Stable machine-readable code.

productstring

Product that produced the error, when applicable.

detailsobject

Health object

FieldTypeDescription
status *enum: ok | degraded
product *string
version *string
timestamp *string (date-time)
checksobject

SignupRequest object

FieldTypeDescription
email *string (email)
password *string

Common passwords, simple sequences and passwords containing the email name are rejected.

namestring
organization_namestring

Name of the personal organization. Defaults to "<name>'s workspace".

TokenRequest object

FieldTypeDescription
token *string

LoginRequest object

FieldTypeDescription
email *string (email)
password *string

LoginResponse object

FieldTypeDescription
user *User
session_expires_at *string (date-time)

User object

FieldTypeDescription
id *string (uuid)
email *string (email)
name *string
email_verified *boolean
email_verified_at *string (date-time) | null
created_at *string (date-time)
last_login_at *string (date-time) | null

Me object

FieldTypeDescription
user *User
organizations *array of object

Role enum: owner | admin | member

owneradminmember

Organization object

FieldTypeDescription
id *string (uuid)
name *string
is_personal *boolean
status *enum: active | suspended
created_at *string (date-time)
role *Role

The caller's role.

OrganizationDetail object

FieldTypeDescription
id *string (uuid)
name *string
is_personal *boolean
status *enum: active | suspended
created_at *string (date-time)
role *Role

The caller's role.

subscriptionSubscription
entitlements *Entitlement []
quotaQuotaUsage

QuotaUsage object

Monthly quota use in the period the quota is currently counted for. After the stored subscription period ends, periods continue monthly from its start. Omitted when the organization has no subscription.

FieldTypeDescription
period_start *string (date-time)
period_end *string (date-time)
products *array of object

Subscription object

FieldTypeDescription
plan *enum: free | developer | growth | business | enterprise
plan_name *string
monthly_price_cents *integer
status *enum: trialing | active | past_due | canceled
current_period_start *string (date-time)
current_period_end *string (date-time)

Entitlement object

FieldTypeDescription
product *string
monthly_request_quota *integer (int64) | null

Null means unlimited.

rate_limit_per_minute *integer
historical_access *boolean
bulk_access *boolean

Member object

FieldTypeDescription
user_id *string (uuid)
email *string (email)
name *string
role *Role
joined_at *string (date-time)

APIKey object

FieldTypeDescription
id *integer (int64)
name *string
prefix *string

The first characters of the secret, for recognising the key.

environment *enum: live | test
product *string | null

The one product the key is scoped to; null for every product on the plan.

status *enum: active | expired | revoked
created_by_user_id *string (uuid) | null
created_at *string (date-time)
last_used_at *string (date-time) | null

Updated at most about once a minute.

expires_at *string (date-time) | null
revoked_at *string (date-time) | null

CreatedAPIKey object

FieldTypeDescription
id *integer (int64)
name *string
prefix *string

The first characters of the secret, for recognising the key.

environment *enum: live | test
product *string | null

The one product the key is scoped to; null for every product on the plan.

status *enum: active | expired | revoked
created_by_user_id *string (uuid) | null
created_at *string (date-time)
last_used_at *string (date-time) | null

Updated at most about once a minute.

expires_at *string (date-time) | null
revoked_at *string (date-time) | null
secret *string

The full key. Returned only in this response.

AuditEvent object

FieldTypeDescription
id *integer (int64)
actor_user_id *string (uuid) | null
actor_api_key_id *integer (int64) | null
action *string
target_type *string
target_id *string
metadata *object
ip *string
created_at *string (date-time)

UsageSummary object

FieldTypeDescription
organization_idstring (uuid)
api_key_idinteger (int64)
productstring
from *string (date)
to *string (date)
total_requests *integer (int64)
by_day *array of object
by_product *array of object
by_endpoint *array of object

* required field