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

# Authentication

> Learn where your API key goes and how to keep it safe.

Authentication is how HaulStow knows which business and developer application is making a request. You authenticate by sending an API key in the HTTP `Authorization` header.

## Your first authenticated request

Every API request needs this header:

```http theme={null}
Authorization: Bearer hsg_test_key_your_complete_key
```

There is exactly one space between `Bearer` and the key. A complete `curl` example looks like this:

```bash theme={null}
curl "https://sandbox.developer.haulstow.co/v1/deliveries" \
  --header "Authorization: Bearer $HAULSTOW_API_KEY"
```

Live keys start with `hsg_live_key_`. Test keys start with `hsg_test_key_`. The complete value is a secret, just like a password.

<Warning>
  Never place an API key in React, Vue, Angular, browser JavaScript, a mobile app, source control, screenshots, logs, analytics, or support messages. The public API intentionally has no CORS support because it is designed for backend-to-backend calls.
</Warning>

## Where the key should live

Save the key in a server-side secret manager or environment variable. Your request flow should look like this:

```text theme={null}
Customer's browser -> Your backend -> HaulStow API
                          |
                          +-- API key stays here
```

Do not send the HaulStow key to your customer's browser. If your frontend needs to create a delivery, it should call an endpoint on your backend, and your backend should make the HaulStow request.

## Environments

| Key type | Base URL                                   | Key prefix         | Data and effects                          |
| -------- | ------------------------------------------ | ------------------ | ----------------------------------------- |
| Test     | `https://sandbox.developer.haulstow.co/v1` | `hsg_test_key_...` | Simulated data with no real-world effects |
| Live     | `https://developer.haulstow.co/v1`         | `hsg_live_key_...` | Real operational deliveries               |

The key and URL must belong to the same environment. There is no environment field in the request body.

* Test key + sandbox URL: correct.
* Live key + live URL: correct.
* Test key + live URL: `401 ENVIRONMENT_MISMATCH`.
* Live key + sandbox URL: `401 ENVIRONMENT_MISMATCH`.

## Scopes

A scope is one permission attached to an API key. For example, a read-only dashboard may need `deliveries:read` but not `deliveries:write`.

| Scope              | Allows                                                            |
| ------------------ | ----------------------------------------------------------------- |
| `quotes:read`      | Calculate quotes                                                  |
| `recipients:read`  | List and retrieve recipients and addresses                        |
| `recipients:write` | Create or reuse recipients and addresses                          |
| `deliveries:read`  | List deliveries, retrieve a delivery, and read its event timeline |
| `deliveries:write` | Create or cancel deliveries and use sandbox transition helpers    |

If the key is valid but lacks the needed scope, the API returns `403 INSUFFICIENT_SCOPE`. Create or rotate a key with the correct scope in the developer portal; scopes cannot be added by sending them in an API request.

## Key lifecycle

### Creating a key

The developer portal shows a new key once. Copy it immediately into your secret manager. HaulStow cannot show the complete key again.

### Rotating a key

Rotation creates a new key but leaves the old one working. This lets you update your server without downtime:

1. Create the replacement key.
2. Save it in your secret manager.
3. Deploy your server with the replacement.
4. Confirm requests are working.
5. Revoke the old key.

### Revoked or expired keys

* A revoked key returns `401 API_KEY_REVOKED`.
* An expired key returns `401 API_KEY_EXPIRED`.
* A disabled developer application makes all its keys invalid.

Keep live and test credentials in separate configuration. Never substitute one automatically when the other fails.

## If authentication fails

Check these in order:

1. The header begins with `Authorization: Bearer `.
2. You copied the complete key without extra spaces or quotation marks.
3. The test/live key matches the sandbox/live URL.
4. The key has the scope shown on the endpoint's reference page.
5. The key is not expired or revoked and the application is active.

See [common errors](/errors) for exact response codes.
