# Authentication

BillerAPI uses two authentication mechanisms depending on the type of operation.

## Authentication Methods

Choose the right method for your use case

### API Key (Bearer)

Server-to-server API calls using your `bak_test_`/`bak_live_` API key.

`Authorization: Bearer bak_test_…`

### Access Tokens (Bearer)

Link-scoped tokens from exchange, accepted by supported detail and statement operations.

`Authorization: Bearer <token>`

## API Key

Use your API key for all server-to-server API calls: biller search, link token creation, webhook registration, and more. Send it as a `Bearer` token on every request — the key is self-contained, so no other header is needed.

```
Authorization: Bearer bak_test_…
```

### Getting Your Key

1. Sign up at the **Client Portal** to create a developer account
2. Navigate to **Dashboard → API Keys**
3. Copy your sandbox key, or generate a production key once you go live

### Key Formats

| Environment | Key Prefix | Mode | Base URL |
| --- | --- | --- | --- |
| Sandbox | `bak_test_*` | `test` | `https://sandbox.api.billerapi.com` |
| Production | `bak_live_*` | `live` | `https://api.billerapi.com` |

The key prefix tells you which environment you're in at a glance. Client-secret response objects also carry a `mode` field (`test` or `live`) so sandbox vs production is visible on the wire.

**Example: List billers with your API key**

**JavaScript**

```javascript
const response = await fetch('https://sandbox.api.billerapi.com/v1/billers', {
  headers: {
    'Authorization': `Bearer ${process.env.BILLERAPI_API_KEY}`,
  },
});
const data = await response.json();
```

**Python**

```python
import requests
import os

response = requests.get(
    'https://sandbox.api.billerapi.com/v1/billers',
    headers={'Authorization': f'Bearer {os.environ["BILLERAPI_API_KEY"]}'},
)
data = response.json()
```

**Go**

```go
req, _ := http.NewRequest("GET", "https://sandbox.api.billerapi.com/v1/billers", nil)
req.Header.Set("Authorization", "Bearer "+os.Getenv("BILLERAPI_API_KEY"))

resp, err := http.DefaultClient.Do(req)
if err != nil {
    log.Fatal(err)
}
defer resp.Body.Close()
```

> **Warning — Keep your key safe**
> Never expose your API key in client-side code (browser, mobile app). All API calls using your key must originate from your server.

> **Note — One credential per environment**
> Use a `bak_test_` key for sandbox and a `bak_live_` key for production. Do not combine keys with a separate client id or secret header.

## Access Tokens (Bearer)

Access tokens are scoped to a single linked account. You obtain them by exchanging the public token returned by Elements after a user completes the linking flow.

### How to Get an Access Token

1. **Create a link token** — `POST /v1/link-tokens` with your API key
2. **User completes Connect flow** — Elements opens an iframe where the user links their biller account
3. **Exchange the public token** — `POST /v1/link-tokens/:public_token/exchange` returns an `access_token`
4. **Use the access token** — Keep the durable `account_link_id` for server reads. Use the access token only on endpoints that explicitly document link-scoped authentication.

**Example: Fetch one bill with a link-scoped access token**

**JavaScript**

```javascript
const response = await fetch(
  'https://sandbox.api.billerapi.com/v1/bills/bill_123',
  {
    headers: {
      'Authorization': `Bearer ${accessToken}`,
    },
  }
);
const bills = await response.json();
```

**Python**

```python
response = requests.get(
    'https://sandbox.api.billerapi.com/v1/bills/bill_123',
    headers={'Authorization': f'Bearer {access_token}'},
)
bills = response.json()
```

**Go**

```go
req, _ := http.NewRequest("GET",
    "https://sandbox.api.billerapi.com/v1/bills/bill_123", nil)
req.Header.Set("Authorization", "Bearer "+accessToken)

resp, err := http.DefaultClient.Do(req)
```

## Environments

Use the sandbox environment for development and testing. Switch to production when you're ready to go live.

| Environment | Base URL | Description |
| --- | --- | --- |
| Sandbox | `https://sandbox.api.billerapi.com` | Test billers, deterministic data, no real accounts |
| Production | `https://api.billerapi.com` | Live billers, real account data |

> **Note**
> Sandbox uses test billers with magic account numbers that produce deterministic responses. See the [Getting Started](/docs/guides/getting-started) guide for sandbox test data.

## Error Handling

All errors return a consistent JSON response format.

**Error Response**

```json
{
  "error_code": "UNAUTHORIZED",
  "error_type": "auth",
  "error_message": "Invalid client credentials.",
  "docs_url": "https://docs.billerapi.com/errors/UNAUTHORIZED",
  "request_id": "d94f5e2a-8c3b-4f1e-9a7d-6b2c1e0f8a34"
}
```

### Common Error Codes

| Status | Meaning | Action |
| --- | --- | --- |
| `401` | Invalid or missing credentials | Check client ID/secret or refresh token |
| `403` | Insufficient permissions | Verify your account has the required scopes |
| `429` | Rate limit exceeded | Back off and retry after the Retry-After period |
| `500` | Internal server error | Retry with exponential backoff; contact support if persistent |

### Rate Limits

BillerAPI enforces per-client rate limits. The exact per-endpoint thresholds are **subject to change** — do not hard-code specific numbers. When you exceed a limit the API returns `429 Too Many Requests` with a `Retry-After` header (and a numeric `retry_after` field in the error body). Always honor it. See [Rate Limits](/docs/concepts/rate-limits) for the backoff strategy.

## Security Best Practices

- ✓ Store credentials in environment variables, never in source code
- ✓ Rotate client secrets periodically via the dashboard
- ✓ Use separate credentials for sandbox and production
- ✓ Verify webhook signatures before processing events
- ✗ Never expose client secrets in frontend code or public repositories
- ✗ Never log full credentials — redact secrets in logs

## Related API Reference

- [Billers API](/docs/api/billers) — Client credential endpoints
- [Link API](/docs/api/link-sessions) — Token create and exchange
- [Bills API](/docs/api/bills) — Bearer token endpoints
