Authentication · API key

Access

API Authentication

Customers authenticate the HZURA Sports API and HZURA Casino API with an API key. The calling IP must match that customer's CIDR allow-list. Casino routes always require the key. Sports routes can also admit a legacy public-IP policy with no key.

API key

Admin-managed customers receive an API key. Send it on every sports or casino call except GET /api/v1/health.

The key is shown once when it is generated. Store it on the server that calls the API. Do not put it in a browser bundle, a mobile app, or source control.

HeaderRequiredRule
Authorization: Bearer <key>API-key accountsPreferred. If both headers are present, this value is the key.
X-Api-Key: <key>API-key accountsUsed when Authorization is absent or is not Bearer.
Accept: application/jsonRecommendedResponses are JSON either way.
HTTP
GET /api/v1/sports HTTP/1.1
Host: api.hzura.com
Authorization: Bearer YOUR_API_KEY
Accept: application/json
  • A present Authorization: Bearer value wins over X-Api-Key, including when the bearer token is empty.
  • An empty bearer token or an empty X-Api-Key is still treated as a supplied key. The request does not fall through to legacy IP access.
  • Other Authorization schemes are ignored. A legacy IP client can send an unrelated Authorization header and still be matched by IP.
  • A missing key, an empty supplied key, an unknown key, a disabled customer, and a CIDR miss all return 403 ip_not_allowed with message Client address is not allowed.

Customer identification

The API key resolves the customer. Callers do not send customer_id or customerId. Casino catalog, launch, and wallet use that resolved customer only.

Sports sport lists and rate limits also come from the customer policy when a key is supplied. GET /api/v1/sports returns the sports that policy allows.

IP and CIDR access

The address that must match is the public IP the API sees for the caller, after trusted-proxy forwarding. Hostnames, including ngrok domains, are not an access control.

For an API-key customer, that IP must fall inside allowed_cidrs for the customer. An empty CIDR list denies every request. Register the stable public egress IP of each server that will call the API before integration.

127.0.0.1, a Docker bridge address, or a home NAT address is not a production server IP.

Legacy keyless sports access

If the request supplies no API key, sports routes can still be admitted by an enabled public-IP policy. That policy is an exact client IP, not a customer record. It can allow a sport list and its own rate limit.

This path is current public behavior for sports only. It does not identify a casino customer, so casino games, launch, and wallet reject it with 403 ip_not_allowed.

Sports and Casino

RouteAPI keyCalling IPRate limit
GET /api/v1/healthNot requiredNot checkedNot applied
Sports routesRequired for API-key accounts. Omitted only for a legacy IP policy.Customer CIDR, or the legacy IP policyPer customer when a key is used. Per IP for a legacy client.
Casino games, launch, and walletRequired. The key selects the customer.That customer's CIDR allow-listNot applied. Casino paths do not return rate_limited.

Unknown paths under the public API still require admission. A caller who is not allowed receives ip_not_allowed rather than not_found.

GET /metrics is an operator metrics endpoint. It is not a client JSON route and is not covered here.

Security notes

  • Call the API over HTTPS.
  • Treat the API key as a secret. Rotate it with the operator if it is exposed.
  • Policies can change without an API restart. A loaded policy is reused for one second, so a change is visible on the next read after that.
  • A valid sport that is not on the client policy is 403 sport_not_allowed. An unknown sport key is 400 invalid_sport.
  • Casino can be disabled for an otherwise valid key. That is 403 casino_access_disabled, which is distinct from ip_not_allowed.
  • Launch and wallet bodies reject unknown JSON fields. Do not send provider credentials or a return URL.
  • The numeric rate-limit budget is configured per client. It is not a fixed public number. On 429, wait for the Retry-After header, in seconds.