Hermeseus Docs
Legacy docs

Authentication

HAPI v3 uses the OAuth2 client-credentials grant. You exchange a client_id and client_secret for a short-lived bearer access token, then send that token on every request.

There is no long-lived API key on the wire. The access token is the only credential a request carries, and it expires after an hour, which keeps a leaked token from being useful for long.

Your credentials

ValueExampleDescription
client_idcid_live_… / cid_test_…Public client identifier. The prefix tells you the environment.
client_secretsk_live_… / sk_test_…The secret. Never send it from a browser or mobile app; keep it on your server.

Get a token

POST/v3/HAPI/auth/tokens

Body parameters

NameTypeRequiredDescription
grant_typestringYesMust be client_credentials.
client_idstringYesYour client id.
client_secretstringYesYour client secret.
scopestringNoSpace-separated scopes to narrow the token. Defaults to every scope the client holds.

Credentials may go in the JSON body, or as HTTP Basic auth (client_id as the user, client_secret as the password):

curl -X POST https://api.hermeseus.com/v3/HAPI/auth/tokens \
  -u "cid_live_…:sk_live_…" \
  -H "Content-Type: application/json" \
  -d '{ "grant_type": "client_credentials" }'

Response

{
  "access_token": "hat_live_…",
  "token_type": "Bearer",
  "expires_in": 3600,
  "expires_at": "2026-08-27T17:36:36+00:00",
  "scope": "flights:read flights:write wallet:read",
  "environment": "live"
}
FieldDescription
access_tokenThe bearer token to send on every request.
token_typeAlways Bearer.
expires_inSeconds until the token expires (3600).
expires_atAbsolute expiry, RFC 3339 UTC.
scopeSpace-separated scopes granted to this token.
environmenttest or live, from the credential.

Use the token

Send it in the Authorization header:

Authorization: Bearer hat_live_…

Introspect a token

Confirm the office, environment, and scopes a token maps to.

GET/v3/HAPI/auth/introspect
{
  "active": true,
  "client_id": "cid_live_…",
  "environment": "live",
  "office": { "id": "off_2", "name": "Your Office" },
  "scopes": ["flights:read", "flights:write", "wallet:read"],
  "token_type": "Bearer",
  "expires_at": "2026-08-27T17:36:36+00:00"
}

Scopes

A token is limited to a set of scopes. Read endpoints need the :read scope for their product; endpoints that move money or create bookings need :write. A request missing a scope returns 403 insufficient_scope.

ScopeGrants
flights:readSearch flights, read offers, read orders.
flights:writeCreate orders, issue tickets, cancel, refund.
hotels:read / hotels:writeThe same split for hotels.
activities:read / activities:writeThe same split for activities.
wallet:readRead your office balance.

Environments

A test credential operates against a sandbox wallet: searches are real, but bookings never move real funds. A live credential operates against your real office balance. Because the environment is part of the credential, you never point at a different host, you just authenticate with the matching client.

Authentication errors

StatusCodeMeaning
400missing_credentialsNo client_id / client_secret supplied.
400unsupported_grant_typegrant_type was not client_credentials.
401invalid_clientThe client id or secret is wrong.
401missing_authorizationNo bearer token on the request.
401invalid_tokenThe token is unknown.
401expired_tokenThe token has expired; get a new one.
403insufficient_scopeThe token lacks a scope the endpoint requires.

See the errors reference for the full envelope.