---
name: banxa-api-authentication
description: Sign requests to the Banxa APIs correctly - HMAC-SHA256 for the Native API, x-api-key for Hosted Checkout - and verify inbound webhooks. Use when writing or debugging Banxa API calls, or when a request returns 401 or a nonce error.
---

# Authenticate against the Banxa APIs

Banxa runs **no OAuth authorization server**. There is no
`/.well-known/openid-configuration` and no `/.well-known/oauth-authorization-server`.
Do not look for one. Credentials are issued to onboarded partners and cannot be
provisioned programmatically - see <https://docs.banxa.com/auth.md>.

## Native API - HMAC-SHA256

Every request carries a signature built from the API secret:

```
Authorization: Bearer API_KEY:SIGNATURE:NONCE
```

Build the canonical string, newline-separated, then HMAC-SHA256 it with the
secret and hex-encode:

```
GET   METHOD\nPATH_WITH_QUERY\nNONCE
POST  METHOD\nPATH\nNONCE\nCOMPACT_JSON_BODY
```

Rules that decide whether it works:

- Use the **request path only**. Never the full URL with the domain.
- The JSON body must be compact - no whitespace between elements.
- `NONCE` is a Unix timestamp in **microseconds, 16 digits**, unique per request.

Nonce precision is the most common production failure. Seconds and milliseconds
are accepted, but two requests generated in the same millisecond produce the same
nonce and the second is rejected as reused (error `40003`). Multiplying a
millisecond clock by 1000 pads the digits without adding precision and does not
fix it - read from a clock with genuine sub-millisecond resolution.

## Hosted Checkout - API key

```
x-api-key: YOUR_API_KEY
```

The partner reference is part of every path: `https://api.banxa.com/{partnerRef}/v2/...`.
One exception: `POST /v2/identities/token/share` requires the same HMAC signing
as the Native API.

## Webhooks - verify, then acknowledge

Banxa signs every outbound webhook with HMAC-SHA256. Verify the signature before
processing anything, return HTTP 200 immediately, and process asynchronously.
The canonical string differs from the outbound one - see the webhooks page.

## Handling limits

Production allows 500 requests per minute per IP across all endpoints; sandbox
allows 120 per minute per merchant. Both return HTTP 429. Back off exponentially
and prefer webhooks over polling for order status.

## Never

- Put an API secret in frontend, mobile, or any client-side code. An agent
  running on a user's device must call Banxa through a backend the partner controls.
- Mix sandbox credentials with production base URLs, or the reverse.

## Reference

- Native API authentication: <https://docs.banxa.com/products/native-api/docs/getting-started/authentication>
- Hosted Checkout authentication: <https://docs.banxa.com/products/hosted-checkout/docs/getting-started/authentication-and-environments>
- Obtaining credentials: <https://docs.banxa.com/auth.md>
