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

# Authentication

> How to authenticate with the GeniusForms API

# Authentication

All API requests require authentication via an API key.

## API Keys

API keys are passed in the `X-API-Key` header:

```bash theme={null}
curl https://geniusforms.ai/api/v1/forms \
  -H "X-API-Key: gf_sk_live_YOUR_API_KEY"
```

### Key Format

GeniusForms API keys follow this format:

| Prefix        | Environment           |
| ------------- | --------------------- |
| `gf_sk_live_` | Production            |
| `gf_sk_test_` | Sandbox (coming soon) |

### Creating API Keys

1. Go to your [dashboard](https://geniusforms.ai/dashboard)
2. Navigate to **Settings → API Keys**
3. Click **Create API Key**
4. Optionally name your key and set a rate limit
5. Copy the key immediately - it's only shown once!

<Warning>
  **Security Best Practices**

  * Never expose API keys in client-side code
  * Store keys in environment variables
  * Rotate keys if you suspect they've been compromised
  * Use form-scoped keys when possible for least-privilege access
</Warning>

## Rate Limits

Each API key has a daily request limit that resets at midnight UTC. The limit depends on your [plan](/pricing):

| Plan              | Default Limit       |
| ----------------- | ------------------- |
| Free              | 1,000 requests/day  |
| Builder (\$19/mo) | 5,000 requests/day  |
| Scale (\$49/mo)   | 10,000 requests/day |

You can customize limits when creating a key (100, 500, 1,000, 5,000, or 10,000).

### Rate Limit Headers

Every response includes rate limit information:

```
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 847
X-RateLimit-Reset: 1707264000
```

| Header                  | Description                      |
| ----------------------- | -------------------------------- |
| `X-RateLimit-Limit`     | Your daily request limit         |
| `X-RateLimit-Remaining` | Requests remaining today         |
| `X-RateLimit-Reset`     | Unix timestamp when limit resets |

### Handling Rate Limits

When you exceed your limit, you'll receive a `429` response:

```json theme={null}
{
  "error": "rate_limit_exceeded",
  "message": "Daily rate limit of 1000 requests exceeded. Resets at midnight UTC.",
  "resetAt": "2026-02-10T00:00:00Z",
  "tier": "free",
  "upgradeUrl": "/settings?tab=api"
}
```

## Credit Headers

Every response also includes [AI credit](/pricing) information:

```
X-Credits-Remaining: 45
X-Credits-Used: 5
X-Monthly-Allowance: 500
```

| Header                | Description                        |
| --------------------- | ---------------------------------- |
| `X-Credits-Remaining` | Credits left in your billing cycle |
| `X-Credits-Used`      | Credits consumed by this request   |
| `X-Monthly-Allowance` | Total monthly credit allowance     |

See [Pricing & Credits](/pricing) for details on the credit system.

## Form-Scoped Keys

For enhanced security, you can create keys scoped to a specific form:

* Can only access that form's data
* Cannot create new forms
* Cannot access other forms' responses

This is ideal for integrations that only need access to a single form.

## Error Responses

| Status | Error                  | Description                                                                             |
| ------ | ---------------------- | --------------------------------------------------------------------------------------- |
| 401    | `unauthorized`         | Missing, invalid, or revoked API key                                                    |
| 402    | `insufficient_credits` | Not enough AI credits for this operation ([details](/pricing#insufficient-credits-402)) |
| 403    | `forbidden`            | Key doesn't have access to this resource                                                |
| 429    | `rate_limit_exceeded`  | Daily request limit exceeded                                                            |

Example error response:

```json theme={null}
{
  "error": "unauthorized",
  "message": "Invalid or expired API key"
}
```
