# Authentication

All requests to the iClosed.io API must include a valid API key. This page covers how authentication works, how to manage your keys, and how to keep them secure.

## Overview

| Detail | Value |
|  --- | --- |
| Method | Bearer token in the `Authorization` header |
| Token format | Must start with `iclosed_` prefix |
| Scope | Keys are tied to a user and account — requests run in that context |
| Transport | HTTPS only |


## Header Format

Include this header on every request:

```
Authorization: Bearer iclosed_<your-api-key>
```

Both `Bearer` (capitalised, with a space) and the `iclosed_` prefix are required. No other authentication method is supported.

## Obtaining an API Key

1. Log in at [app.iclosed.io](https://app.iclosed.io)
2. Go to **Settings → Developer → API Keys**
3. Click **Create API Key**, give it a name, and set an optional expiration date
4. Copy the key immediately — it will not be shown again after you leave the page
5. Store it in an environment variable or secrets manager (see [Security best practices](#security-best-practices))


> API access requires a **Business or Enterprise** plan. If you do not see an API Keys section, check your plan at [iclosed.io/pricing](https://iclosed.io/pricing).


## Key Lifecycle

| State | API behaviour |
|  --- | --- |
| Active | Requests succeed normally |
| Expired | `401` — `"message": "API key expired"` |
| Revoked | `401` — `"message": "Invalid API key"` |


**Rotating a key:**

1. Create a new key in Settings
2. Update your integration to use the new key
3. Revoke or delete the old key


## Code Examples

### cURL

```bash
curl -X GET "https://public.api.iclosed.io/v1/eventCalls?eventType=UPCOMING" \
  -H "Authorization: Bearer iclosed_YOUR_API_KEY" \
  -H "Content-Type: application/json"
```

### JavaScript (fetch)

```javascript
const response = await fetch('https://public.api.iclosed.io/v1/contacts', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer iclosed_YOUR_API_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    firstName: 'Jane',
    lastName: 'Doe',
    email: 'jane@example.com'
  })
});

const { data } = await response.json();
console.log(data.contact.id);
```

### Python

```python
import requests

response = requests.get(
    'https://public.api.iclosed.io/v1/eventCalls',
    params={'eventType': 'UPCOMING', 'limit': 20},
    headers={
        'Authorization': 'Bearer iclosed_YOUR_API_KEY',
        'Content-Type': 'application/json'
    }
)

data = response.json()
```

### Postman

1. Open your request → **Authorization** tab
2. Select **Bearer Token** from the Type dropdown
3. Paste your full key including the `iclosed_` prefix


## Authentication Error Responses

| HTTP Code | `message` value | `code` value | Cause |
|  --- | --- | --- | --- |
| `401` | `"API key is required"` | `MISSING_API_KEY` | `Authorization` header missing or token does not start with `iclosed_` |
| `401` | `"Invalid API key"` | — | Key is unknown, revoked, or malformed |
| `401` | `"API key expired"` | — | Key has passed its expiration date |
| `403` | `"Forbidden"` | — | Key exists but lacks permission for this resource |


Example 401 response body:

```json
{
  "message": "API key is required",
  "code": "MISSING_API_KEY"
}
```

## Security Best Practices

- **Never commit keys to version control.** Use environment variables, `.env` files (git-ignored), or a secrets manager.
- **One key per environment.** Create separate keys for production and development so you can revoke each independently.
- **One key per integration.** If iClosed connects to multiple tools, give each its own key.
- **Set expiration dates.** Short-lived keys reduce exposure if a key leaks.
- **Rotate after any suspected exposure.** Revoke the compromised key immediately and issue a new one.
- **HTTPS only.** Never send requests over plain HTTP.


## See Also

- [Rate Limiting](/docs/rate-limiting) — Request limits and backoff strategy
- [Errors](/docs/errors) — Full error code reference
- [API Reference](https://api-docs-iclosed.redocly.app/openapi/v1/openapi) — All endpoints