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

# Authentication

> API keys and how to use them with the SDK and direct API calls

## API key format

All Nippy keys use the `npk_live_` prefix followed by a random string:

```
npk_live_a1b2c3d4e5f6...
```

Each key is tied to a specific `businessId`. The server resolves your business automatically from the key — you don't need to pass it in SDK methods, but you do in direct REST API calls.

<Warning>
  Never expose your key in client-side code (browser, mobile app). Use it only in your backend.
</Warning>

## With the SDK

Pass it in the constructor once:

```typescript theme={null}
import { NippyClient } from '@nippy/sdk'

const nippy = new NippyClient({
  apiKey: process.env.NIPPY_API_KEY,  // never hardcoded
  baseUrl: 'https://ms.nippy.la'
})
```

The SDK includes it automatically in every request. You don't need to manage it manually.

## With direct REST API calls

For administration endpoints (creating campaigns, rules, viewing logs) that don't go through the SDK, include both headers:

```http theme={null}
x-api-key: npk_live_xxx
x-business-id: your-business-id
```

Example:

```bash theme={null}
curl https://ms.nippy.la/v1/public/campaigns \
  -H "x-api-key: npk_live_xxx" \
  -H "x-business-id: your-business-id"
```

## Authentication errors

| HTTP code          | Cause                                                  | Fix                                                     |
| ------------------ | ------------------------------------------------------ | ------------------------------------------------------- |
| `401 Unauthorized` | Key invalid, expired, or missing                       | Verify the key is correct and in the `x-api-key` header |
| `403 Forbidden`    | The key does not have access to the requested resource | Verify the `businessId` matches your key                |

```typescript theme={null}
import { NippyError, NippyErrorCodes } from '@nippy/sdk'

try {
  await nippy.spin({ userId, campaignId })
} catch (error) {
  if (error instanceof NippyError && error.code === NippyErrorCodes.UNAUTHORIZED) {
    // verify the API key is valid
  }
}
```

## Best practices

* Store the key in environment variables (`NIPPY_API_KEY`)
* Rotate the key if you suspect it was compromised — contact us at [support@nippy.la](mailto:support@nippy.la)
* Use a single `NippyClient` instance per process; do not recreate it per request
