Authentication

X-API-Key: om_<data|exec>_<live|test>_… · Authorization: Bearer <jwt>

Three credentials reach the Flow API: a workspace API key, a marketplace app's install key, and a signed-in person's session. Every /flow/v1 endpoint accepts the same headers.

Pick the right credential

CredentialWho holds itActs onHeader
Workspace API keyyou — a developer, a desk, an organizationyour own account; with X-OpenMarkets-Account and connect:trade, one of your Connect usersX-API-Key
Install keyyour marketplace app, per signed-in userthat user's own account, within the scopes they consented toX-API-Key
Player sessiona person in the console or a first-party apptheir own account; the act-as header is ignoredAuthorization: Bearer

Send both headers and the API key wins. A third-party app never asks people for an OpenMarkets password: it gets an install key through Sign in with OpenMarkets, and an organization acts for its own users through Connect.

Key format

Keys are 45 characters. The prefix is structure, the rest is the secret:

om_data_live_<32 characters, base64url>

om_        OpenMarkets
data       key type — data (reads) or exec (reads + orders)
live       environment — live, or test (reads real markets, cannot move money)
...        the secret material

The first 16 characters (om_data_live_a7K) are the key_prefix the console shows and are safe to log. The full string is a password.

Type and environment are fixed at mint. A data key never places an order, whatever the plan grants; a test key never moves real money. Going live means minting a live key, not promoting one. See Test mode.

What a key can do

A key is narrowed by its plan and, optionally, by its own scopes: effective = plan ∩ key scopes. A key with no scopes set inherits everything the plan grants. What that resolves to is reported by GET /flow/v1/auth/me — read can_execute before offering trading, and the per-key rate limits, which can exceed the documented defaults.

A missing entitlement answers 403 entitlement_required with the missing codes in details.missing; on an install key it is 403 scope_not_granted, because the person declined it.

Passing the key

REST requests authenticate with the header:

curl https://api.openmarkets.ai/flow/v1/contests \
  -H "X-API-Key: om_data_live_..."

WebSocket connections pass it as a query parameter, because browsers do not allow custom headers on the handshake:

wss://api.openmarkets.ai/flow/v1/stream?api_key=om_data_live_...

The AI pass-through takes it where the provider key would go — the OpenAI SDK sends it as Authorization: Bearer om_…, which is also accepted. See AI Connect.

Plaintext is shown once

OpenMarkets does not store the plaintext of your key. Only a SHA-256 hash persists. The plaintext is displayed once, at mint. If it is lost, revoke and mint a new one.

Errors

Authentication failures return HTTP 401 with the standard envelope:

{
  "error": {
    "code": "missing_credentials",
    "message": "Missing X-API-Key header or Authorization: Bearer <jwt>"
  }
}
  • missing_credentials — neither header present.
  • invalid_api_key — unknown, revoked or expired key.
  • invalid_jwt — the session token failed verification or expired.
  • install_revoked — an app install key whose install was uninstalled or revoked.

Revoking a key

Console → API keys

Revoke from the console; it takes effect within 60 seconds (the resolution cache). After that the key answers invalid_api_key. Mint a replacement first if the key is in production — there is no rotate-in-place.

Practice

  • Keep keys in a secret manager, never in source control or a client bundle.
  • One key per environment and per deployment, so revoking one breaks nothing else.
  • Mint execution keys only where orders are placed; read everything else with a data key.
  • Rotate on a schedule and whenever someone with access leaves.