> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.dealsignal.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.dealsignal.com/_mcp/server.

# Authentication

> How to authenticate, rotate, and manage your Dealsignal API keys.

## API key

All Dealsignal API requests authenticate with an `api_key`. Get your key from the Dealsignal dashboard.

For most endpoints, pass it as a **query-string parameter**:

```bash
curl "https://app.dealsignal.com/api/v1/users/credit_metrics?api_key=YOUR_API_KEY"
```

> **Tip**
>
> Send `Accept: application/json` on every request so that authentication errors come back as JSON.

> **Warning**
>
> Treat the key like a password. Never commit it to source control, log it, or expose it in client-side code.

---

## Key rotation

Dealsignal supports zero-downtime key rotation. When you roll your key:

1. A **new** `api_key` is minted and returned in the response.
2. Your **previous** key keeps working for a configurable grace window (`expires_in_hours`, default and maximum 48 hours).
3. You can roll multiple times — each rolled-away key gets its own independent expiry. At most **five** rolled-away keys stay active: a roll beyond that revokes the one closest to its expiry right away.

The typical deploy flow:

### Roll the key

```bash
curl -X POST "https://app.dealsignal.com/api/v1/auth/api_keys/roll" \
  -H "Content-Type: application/json" \
  -d '{
    "api_key": "YOUR_CURRENT_API_KEY",
    "expires_in_hours": 48
  }'
```

> **Warning**
>
> The `api_key` **must be in the request body** for the `roll` endpoint. Passing it in the query string returns `400` — query-string credentials leak into access logs, CDN logs, browser history, and `Referer` headers.

Response:

```json
{
  "api_key": "NEW_API_KEY_PLAINTEXT",
  "recommended_rotation_date": "2026-07-18T09:00:00Z",
  "previous_api_key_expires_at": "2026-05-20T09:00:00Z"
}
```

`recommended_rotation_date` is two months after the roll. It is a reminder, not an expiry: the key keeps working after that date until you roll it. `previous_api_key_expires_at` is when the key you just rolled away stops being accepted.

### Deploy the new key

Roll the new `api_key` out to your services. The old key keeps authenticating during the grace window, so partially-deployed fleets continue to work.

### Verify, then let the old key expire

Use `GET /api/v1/auth/api_keys` to confirm only one current key and watch the grace window close.

```bash
curl "https://app.dealsignal.com/api/v1/auth/api_keys?api_key=NEW_API_KEY_PLAINTEXT"
```

### Rate limiting

Rolls are rate-limited per user with a **5-minute window** — once you roll, the next roll for the same user is rejected until 5 minutes have passed. If you roll too often, the response is `429` with both a `Retry-After` header and a `retry_after_seconds` field in the body:

```json
{
  "error": "API key was rolled recently. Try again in 214 seconds.",
  "retry_after_seconds": 214
}
```

---

## Reference

| Endpoint                                                                   | Method | Purpose                                                                  |
| -------------------------------------------------------------------------- | ------ | ------------------------------------------------------------------------ |
| [`/api/v1/auth/api_keys`](/api-reference/authentication/list-api-keys)     | `GET`  | List current + previous keys with expiries. Plaintext is never returned. |
| [`/api/v1/auth/api_keys/roll`](/api-reference/authentication/roll-api-key) | `POST` | Mint a new key; park the current one with its own grace window.          |