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

# Authentication

> Every API request must include a valid API key in the X-API-KEY header.

# Authentication

Every API request must include a valid API key in the `X-API-KEY` header.

```bash theme={null}
curl -X POST \
  "https://instance.prod.onboardapp.io/api/gateway/execute/{project_hash}/api" \
  -H "Content-Type: application/json" \
  -H "X-API-KEY: your-api-key" \
  -d '{ ... }'
```

## API keys

Each key is scoped to a single project. One project, one key.

**Environment separation.** Staging and production use different keys. A staging key does not authenticate against the production URL. Your project hash is the same across environments, but the keys are not interchangeable.

**Storage.** Store keys in environment variables or a secrets manager (AWS Secrets Manager, HashiCorp Vault, GCP Secret Manager). Never commit keys to version control, embed them in client-side JavaScript, or log them in application output.

<Tip>
  Store API keys in a dedicated secrets manager (AWS Secrets Manager, HashiCorp Vault, GCP Secret Manager) for production deployments. Environment variables are the minimum acceptable approach.
</Tip>

<CodeGroup>
  ```bash Shell theme={null}
  # Environment variable
  export ZENOO_API_KEY="your-api-key"

  # Use in your application
  curl -H "X-API-KEY: $ZENOO_API_KEY" ...
  ```

  ```javascript Node.js theme={null}
  const apiKey = process.env.ZENOO_API_KEY;
  ```

  ```python Python theme={null}
  import os
  api_key = os.environ["ZENOO_API_KEY"]
  ```
</CodeGroup>

## Key rotation

Contact Zenoo support to rotate your API key. The process:

<Steps>
  <Step title="Request a new key">
    Contact Zenoo support to request a new API key for your project.
  </Step>

  <Step title="Receive the new key">
    Zenoo generates the new key and revokes the old one immediately.
  </Step>

  <Step title="Deploy the new key">
    Deploy the new key to all applications, environment variables, and CI/CD secrets immediately after receiving it.
  </Step>
</Steps>

<Note>
  There is no grace period where both keys are active. Plan your deployment before requesting rotation. Update all configuration, environment variables, and CI/CD secrets, then deploy immediately after receiving the new key.
</Note>

Rotate your key immediately if you suspect it has been compromised. Rotate proactively on a regular schedule as part of your security practices.

## Error responses

| Status | Error Code     | Meaning                                                   |
| ------ | -------------- | --------------------------------------------------------- |
| `401`  | `UNAUTHORIZED` | The `X-API-KEY` header is missing or the key is invalid   |
| `403`  | `FORBIDDEN`    | The key is valid but does not have access to this project |

### 401 Unauthorized

```json theme={null}
{
  "error": "UNAUTHORIZED",
  "message": "Missing or invalid API key",
  "request_id": "req-a1b2c3d4"
}
```

Check that the `X-API-KEY` header is present and contains the correct key for your environment. If the key was recently rotated, retrieve the new key from your secrets manager.

Do not retry 401 errors. The same key will fail every time.

### 403 Forbidden

```json theme={null}
{
  "error": "FORBIDDEN",
  "message": "API key does not have access to this project",
  "request_id": "req-e5f6g7h8"
}
```

The key is valid but not authorized for the project hash in the URL. Verify you are using the correct project hash, or contact Zenoo support to check key-to-project bindings.

## Security rules

<Warning>
  * Never expose API keys in client-side code (browser JavaScript, mobile apps).
  * Never commit keys to Git repositories, even private ones.
  * Never log API keys in application output or error messages.
  * Store keys in environment variables or a dedicated secrets manager.
  * Use HTTPS for all API requests. HTTP is not supported.
  * Rotate keys immediately if a compromise is suspected.
</Warning>

See also: [Webhook Signatures](/guides/webhooks#signature-verification) and [Security Best Practices](/getting-started/security-best-practices).
