# Authentication

The Bento API uses Basic authentication with your publishable key and secret key. Every request also requires your site UUID as a query parameter.

---

## Getting Your Keys {{ id: 'getting-your-keys' }}

You'll need three credentials to authenticate:

| Credential          | Where to find it    | Purpose                      |
| ------------------- | ------------------- | ---------------------------- |
| **Publishable Key** | Settings → API Keys | Username for Basic auth      |
| **Secret Key**      | Settings → API Keys | Password for Basic auth      |
| **Site UUID**       | Settings → API Keys | Identifies which site to use |


> Each site in your Bento account has its own set of API keys. Make sure you're using the correct keys for the site you want to work with.


To get your keys:

1. Log in to [Bento](https://app.bentonow.com)
2. Go to **Settings** → **API Keys**
3. Copy your Publishable Key, Secret Key, and Site UUID

---

## Basic Authentication {{ id: 'basic-authentication' }}

Bento uses [HTTP Basic Authentication](https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication#basic_authentication_scheme). Your credentials are sent as a Base64-encoded string in the `Authorization` header.

### Encoding Your Credentials

Combine your publishable key and secret key with a colon, then Base64 encode:

```bash
echo -n "your_publishable_key:your_secret_key" | base64
# Output: eW91cl9wdWJsaXNoYWJsZV9rZXk6eW91cl9zZWNyZXRfa2V5
```

### Using the Authorization Header

```
Authorization: Basic eW91cl9wdWJsaXNoYWJsZV9rZXk6eW91cl9zZWNyZXRfa2V5
```

### Shortcut: URL-Based Auth

Most HTTP clients support embedding credentials in the URL:

```
https://PUBLISHABLE_KEY:SECRET_KEY@app.bentonow.com/api/v1/...
```

This is convenient for testing but avoid using it in client-side code where the URL might be logged or exposed.

---

## Site UUID {{ id: 'site-uuid' }}

Every API request must include your `site_uuid` as a query parameter. This tells Bento which site's data to access.

```
https://app.bentonow.com/api/v1/fetch/tags?site_uuid=YOUR_SITE_UUID
```


> ⚠️ **Warning**
> Forgetting the `site_uuid` is a common mistake. You'll get a `401 Unauthorized` error if it's missing.


---

## Making Requests {{ id: 'making-requests' }}

### Required Headers

Every request needs these headers:

| Header          | Value                             | Required     |
| --------------- | --------------------------------- | ------------ |
| `Authorization` | `Basic {base64_credentials}`      | Yes          |
| `User-Agent`    | Your app name (e.g., `MyApp/1.0`) | Yes          |
| `Content-Type`  | `application/json`                | For POST/PUT |


> 🚨 **Important**
> **The User-Agent header is required.** Requests without it are blocked by Cloudflare and will fail silently or return HTML instead of JSON.


### Complete Example

```bash
curl -X GET 'https://app.bentonow.com/api/v1/fetch/tags?site_uuid=YOUR_SITE_UUID' \
  -H 'Authorization: Basic YOUR_BASE64_CREDENTIALS' \
  -H 'User-Agent: MyApp/1.0' \
  -H 'Content-Type: application/json'
```

### Language Examples


```js {{ title: 'Node.js' }}
const credentials = Buffer.from(`${publishableKey}:${secretKey}`).toString('base64')

const response = await fetch(`https://app.bentonow.com/api/v1/fetch/tags?site_uuid=${siteUuid}`, {
  headers: {
    Authorization: `Basic ${credentials}`,
    'User-Agent': 'MyApp/1.0',
    'Content-Type': 'application/json',
  },
})
```

```python {{ title: 'Python' }}
import base64
import requests

credentials = base64.b64encode(f"{publishable_key}:{secret_key}".encode()).decode()

response = requests.get(
    f"https://app.bentonow.com/api/v1/fetch/tags?site_uuid={site_uuid}",
    headers={
        "Authorization": f"Basic {credentials}",
        "User-Agent": "MyApp/1.0",
        "Content-Type": "application/json",
    }
)
```

```ruby {{ title: 'Ruby' }}
require 'base64'
require 'net/http'

credentials = Base64.strict_encode64("#{publishable_key}:#{secret_key}")

uri = URI("https://app.bentonow.com/api/v1/fetch/tags?site_uuid=#{site_uuid}")
request = Net::HTTP::Get.new(uri)
request["Authorization"] = "Basic #{credentials}"
request["User-Agent"] = "MyApp/1.0"
request["Content-Type"] = "application/json"

response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
  http.request(request)
end
```

```php {{ title: 'PHP' }}
$credentials = base64_encode("{$publishableKey}:{$secretKey}");

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://app.bentonow.com/api/v1/fetch/tags?site_uuid={$siteUuid}");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Basic {$credentials}",
    "User-Agent: MyApp/1.0",
    "Content-Type: application/json",
]);

$response = curl_exec($ch);
```


> **Tip:** Use our official SDKs instead of making raw HTTP requests. They handle authentication automatically. See [all available SDKs](/docs/sdks).


---

## Security Best Practices {{ id: 'security-best-practices' }}

### Do

- Store API keys in environment variables
- Use server-side code for API calls
- Rotate keys if they're ever exposed
- Use different keys for development and production

### Don't

- Commit API keys to version control
- Expose keys in client-side JavaScript
- Share keys in plain text (emails, Slack, etc.)
- Use the same keys across multiple applications

### Environment Variables Example

```bash {{ title: '.env' }}
BENTO_PUBLISHABLE_KEY=your_publishable_key
BENTO_SECRET_KEY=your_secret_key
BENTO_SITE_UUID=your_site_uuid
```

```js {{ title: 'Node.js' }}
const publishableKey = process.env.BENTO_PUBLISHABLE_KEY
const secretKey = process.env.BENTO_SECRET_KEY
const siteUuid = process.env.BENTO_SITE_UUID
```

---

## Common Errors {{ id: 'common-errors' }}

| Error                         | Cause                                    | Solution                                                                             |
| ----------------------------- | ---------------------------------------- | ------------------------------------------------------------------------------------ |
| `401 Unauthorized`            | Invalid credentials or missing site_uuid | Double-check your keys and ensure site_uuid is in the query string                   |
| `403 Forbidden`               | IP blocked or account issue              | Contact support@bentonow.com                                                         |
| HTML response instead of JSON | Missing User-Agent header                | Add `User-Agent: YourApp/1.0` to your request headers                                |
| `BLOCKED` response            | Cloudflare protection triggered          | Ensure User-Agent header is present and looks legitimate                             |
| `429 Too Many Requests`       | Rate limit exceeded                      | Slow down requests, see [rate limits](/docs/developer_guides/introduction#reference) |

### Debugging Tips

1. **Test with cURL first** - If cURL works but your code doesn't, the issue is in your code
2. **Check the response body** - Error messages often explain what went wrong
3. **Verify Base64 encoding** - A common mistake is encoding with line breaks or padding issues
4. **Confirm site_uuid** - Each site has a unique UUID; using the wrong one will fail

---

## Next Steps

- [API Quickstart](/docs/quickstart) - Make your first API call
- [Events API](/docs/events_api) - Track user behavior
- [Subscribers API](/docs/subscribers) - Manage your contacts
- [SDKs](/docs/sdks) - Use our official libraries