> ## Documentation Index
> Fetch the complete documentation index at: https://docs.velafi.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Authentication

> Sign a request with your API key and secret to get a business token from GET /v2/token/generate, then send the token in the X-BH-TOKEN header.

VelaFi authenticates API requests in two steps. First, your server signs a request with your **API key** and **API secret** and calls `GET /v2/token/generate` to get a **business token**. Then it sends that token in the `X-BH-TOKEN` header on every other authenticated request. The API key itself never goes in `X-BH-TOKEN`.

| Header | Value | Send it on |
| - | - | - |
| `X-BH-APIKEY` | Your API key | `GET /v2/token/generate` only |
| `X-BH-TOKEN` | The token returned by `GET /v2/token/generate` | Every other authenticated request |

Never send your API secret in any header or parameter. It stays on your server and is used only to compute the `signature` query parameter of the token request.

## Before You Start

You need all three of the following before you can get a token:

* **API access enabled.** VelaFi must enable API access on your account. Until it does, token requests fail with code `-5033`.
* **An API key and API secret.** Create them on the **API Management** page of the VelaFi dashboard. See [Create Your API Key](https://docs.velafi.com/docs/guides/creating-api-key.md).
* **An IP whitelist on the key.** A key with no whitelisted IP addresses cannot get a token (code `-1023`). Add the public IP addresses of the servers that will call the API.

## Step 1 — Get a Token

Sign the string `timestamp=<ms>` with your API secret (HMAC-SHA256, lowercase hex) and call `GET /v2/token/generate` with your API key in the `X-BH-APIKEY` header:

```bash theme={null}
API_KEY="your_api_key"
API_SECRET="your_api_secret"
TIMESTAMP=$(( $(date +%s) * 1000 ))
SIGNATURE=$(printf 'timestamp=%s' "$TIMESTAMP" | openssl dgst -sha256 -hmac "$API_SECRET" | sed 's/^.*= //')

curl --request GET \
  --url "https://api-test.velafi.com/v2/token/generate?timestamp=${TIMESTAMP}&signature=${SIGNATURE}" \
  --header "X-BH-APIKEY: ${API_KEY}"
```

A successful response contains the token and its expiry time:

```json theme={null}
{
  "code": 200,
  "msg": "SUCCESS",
  "data": {
    "token": "00000000-0000-0000-0000-000000000006",
    "expireTime": "1740568725231"
  }
}
```

## Step 2 — Send the Token

Include the token in the `X-BH-TOKEN` header on every authenticated request:

```http theme={null}
X-BH-TOKEN: your_token
```

**Example — authenticated GET request with curl**

```bash theme={null}
curl --request GET \
  --url https://api.velafi.com/v2/user/account \
  --header "X-BH-TOKEN: your_token"
```

See [Generate Token](https://docs.velafi.com/api-reference/generate-token.md) for the full token request reference.

## Token Lifetime

Every token expires. The `expireTime` field in the token response is the expiry time as a Unix timestamp in milliseconds. Request a new token before that time. A request with an expired or unknown token fails with code `-1022`.

## Authentication Errors

Authentication failures return HTTP status `400`. The `code` field in the body is negative and identifies the problem:

```json theme={null}
{
  "code": -1022,
  "msg": "Signature for this request is not valid."
}
```

| Code | Returned by | Meaning |
| - | - | - |
| `-1002` | Token request | The `X-BH-APIKEY` header is missing or malformed. |
| `-1002` | API call | The `X-BH-TOKEN` header is missing. |
| `-1004` | Token request | The `signature` query parameter is missing, or `timestamp` is missing while other query parameters are sent. The `msg` names the missing parameter. |
| `-1103` | Token request | The request has no query parameters, or `signature` is the only one. |
| `-1022` | Token request | The signature does not match, or the API key does not exist. |
| `-1022` | API call | The token is invalid or has expired. Request a new token. |
| `-1023` | Token request or API call | The API key has no IP whitelist. |
| `-2015` | Token request | The API key or your account is disabled, or the request IP address is not on the key's whitelist. |
| `-2015` | API call | The API key has been disabled or deleted, or your account is disabled. |
| `-2019` | API call | The request IP address is not on the key's whitelist. |
| `-5033` | Token request | API access is not enabled on your account. Contact VelaFi. |

## Sandbox vs. Production Keys

> [tab] Sandbox
>
> Use your **sandbox key** with the test base URL during development and QA:
>
> ```
> Base URL: https://api-test.velafi.com
> Token:    GET https://api-test.velafi.com/v2/token/generate
> Header:   X-BH-TOKEN: your_sandbox_token
> ```
>
> Sandbox transactions do not move real funds. Use them freely to explore the API, test edge cases, and validate your integration end-to-end before go-live.

> [tab] Production
>
> Use your **production key** with the live base URL only when your integration is complete and verified:
>
> ```
> Base URL: https://api.velafi.com
> Token:    GET https://api.velafi.com/v2/token/generate
> Header:   X-BH-TOKEN: your_production_token
> ```
>
> Production requests initiate real financial transactions. Treat your production key with the same care as a private cryptographic key.

> [!WARNING]
>
> Never use sandbox credentials against the production URL, or production credentials against the sandbox URL. Keep the two sets separate in your configuration.

## Security Best Practices

Follow these practices to protect your API key and limit your exposure in the event of a breach.

> [accordion] Never expose the key in client-side code
>
> Your API key, API secret, and tokens must only be used in server-side code. Do not embed them in browser JavaScript, mobile app binaries, public repositories, or any environment accessible to end users. Use environment variables or a secrets manager (such as AWS Secrets Manager, HashiCorp Vault, or GCP Secret Manager) to inject keys at runtime.

> [accordion] Rotate keys regularly
>
> Establish a key rotation policy — for example, every 90 days — even if you have no reason to suspect a compromise. Create the new key on the API Management page, add its IP whitelist, switch your systems to it, then delete the old key.

> [accordion] Configure IP whitelisting
>
> The IP whitelist is required. A key with no whitelist cannot get a token (code `-1023`). A token request from an IP address that is not on the list fails with code `-2015`, and an API call from such an address fails with code `-2019`. Keep the list limited to the servers that call the API.
>
> To set it, open **API Management** in the VelaFi dashboard and select **Whitelist** on the key. You can add up to 5 IPv4 or IPv6 addresses per key. Enter each address individually; CIDR ranges are not accepted.

> [accordion] Monitor for anomalous usage
>
> Log every token request and API call your systems make, and alert on calls you do not expect. If you detect suspicious activity, delete the key on the API Management page, create a new one, and contact VelaFi support.


## Related topics

- [Introduction](https://docs.velafi.com/docs/introduction.md)
- [Error Codes](https://docs.velafi.com/docs/error-codes.md)
- [Get Account Details](https://docs.velafi.com/api-reference/account/get-account-details.md)
- [List Whitelist Addresses](https://docs.velafi.com/api-reference/crypto-wallet/get-whitelist-addresses.md)
- [Delete a Whitelist Address](https://docs.velafi.com/api-reference/crypto-wallet/delete-whitelist-address.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.