Authentication

The Hexolus Payment Gateway authenticates every request with a long-lived bearer API key. There is no OAuth flow, no session cookie, and no signed request body — possession of a valid hxk_* token grants full client-scoped access to the API.

See also: Errors, Payments.

Token format

Tokens follow a fixed three-part layout:

hxk_<8-char-prefix>_<43-char-base64url-random>
Segment Length Purpose
hxk 3 Brand prefix. Constant. Lets log scrubbers and secret scanners detect a leaked key by substring.
prefix 8 Random; stored in plaintext in our database as a safe public identifier. Surfaces in audit logs.
random 43 URL-safe base64 (32 random bytes). Never stored — we keep only SHA-256(full_token) at rest.

A full token is therefore 56 characters: 3 + 1 + 8 + 1 + 43. An example (do not use this — it's illustrative):

hxk_a1b2c3d4_VGhpc0lzQVNhbXBsZVRva2VuU3RyaW5nUmFuZG9tQnl0ZXNYWQ

Obtaining a key

API keys are minted by the Hexolus operator on your behalf at:

# Staging
https://staging.hexolus.com/admin/clients/<your-client-id>/api-keys

# Production
https://hexolus.com/admin/clients/<your-client-id>/api-keys

Admin UI lives on the apex host (hexolus.com / staging.hexolus.com); the api.* subdomains serve the integration API only.

Each newly created key is shown once as plaintext immediately after generation. After you dismiss the modal, only the prefix and the SHA-256 hash remain — Hexolus cannot recover the plaintext later. If you lose a key, request a new one and revoke the old.

This "reveal once" policy is why your integration should pull the key out of the admin UI directly into your secret manager (or .env on a single-host deploy) at provisioning time, never via copy/paste into a chat thread.

Authorization header

Every request must include:

Authorization: Bearer hxk_<prefix>_<random>

The header is case-sensitive on the scheme (Bearer, not bearer). Any other scheme — Basic, Token, ApiKey — is rejected with 401.

curl -sS https://api-staging.hexolus.com/v1/balance \
  -H "Authorization: Bearer hxk_a1b2c3d4_VGhpc0lzQVNhbXBsZVRva2VuU3RyaW5nUmFuZG9tQnl0ZXNYWQ"

Error responses

All authentication failures return HTTP 401 Unauthorized with the standard error envelope:

{ "message": "missing bearer token", "code": "auth" }
message Cause
missing bearer token No Authorization header, or scheme was not Bearer.
empty bearer token Authorization: Bearer with no token.
malformed token Token did not parse as hxk_<prefix>_<tail>.
invalid credentials Prefix not found, OR prefix found but the SHA-256 hash did not match.
key expired The key's expires_at is set and is in the past.

Hexolus deliberately does not distinguish "unknown prefix" from "wrong tail" in the public error message — both surface as invalid credentials — so a caller cannot use response timing or wording to enumerate valid prefixes.

Optional fields

Best practices

  1. Store secrets in a secret manager (AWS Secrets Manager, Vault, Doppler, Kubernetes Secrets, etc.). Do not commit them to git.
  2. Never log the full token. It is safe to log only the prefix (the first 12 characters: hxk_<8-char-prefix>). Hexolus's own logs follow this rule.
  3. Rotate at least every 90 days. Provision a new key, deploy it to all workloads, then revoke the old one. There is no rolling-window grace — a revoked key 401s immediately.
  4. One key per workload. If you run staging + production + a CI job, mint three separate keys so you can revoke a leaked CI key without impacting production traffic.
  5. Use HTTPS only. Hexolus refuses plaintext HTTP. Pinning is optional but encouraged for mobile / desktop clients.
  6. Treat 401 as terminal. Do not retry an authentication failure — it indicates a configuration problem, not a transient one. See Errors for the retryable codes.