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

# API Keys

> Live vs Test keys: when to use each, idempotency, and security.

ReallyQuickEmails authenticates each request with prefixed Secret Keys. Each project has **two distinct keys**: one for production traffic (Live) and one for development (Test).

***

## Live vs Test

| Mode     | Prefix                     | When to use it                                                | Behavior                                                                                                                                                                                        |
| -------- | -------------------------- | ------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Live** | `sk_proj_*` or `sk_live_*` | Production traffic: real customers, real emails, real metrics | Counts against your monthly quota. Outbound webhook fires to `webhook_url`. Inbound replies to `inbound_webhook_url`.                                                                           |
| **Test** | `sk_test_*`                | Development, staging, sandbox, E2E suites                     | Sends real emails and **also** consumes monthly quota. Activity is flagged with `is_test=true` and filtered out of the dashboard. Webhooks go to `webhook_url_dev` / `inbound_webhook_url_dev`. |

> `sk_proj_*` and `sk_live_*` work identically — both are **live mode** and are valid indefinitely.

### Detailed Test Mode behavior

`sk_test_*` keys let you develop and iterate without polluting your production metrics:

* **Real sends**: the email reaches the inbox just like in live. This is deliberate, so you can test deliverability, visual rendering, and email client behavior.
* **Consumes monthly quota**: the send is real, so it counts against the plan's monthly limit just like a live send.
* **Activity with `is_test=true`**: every send is recorded in Activity with the `is_test: true` flag. The dashboard filters out these records when the Live/Test toggle is in Live mode.
* **Separate webhooks**: outbound events (`email.delivery`, `email.bounce`, `email.open`, `email.click`) and inbound replies are routed to the `*_dev` URLs. If the `_dev` URL isn't configured, the event isn't delivered — there is **no** fallback to the live `webhook_url`.
* **Dashboard toggle**: the sidebar has a global Live/Test switch that filters Activity, Campaigns, and metrics according to the mode.

See [Live and Test Modes](/en/concepts/test-mode) for webhook routing and edge cases.

***

## Where to find your Secret Keys

1. Log in to the [RQE dashboard](https://app.reallyquickemails.com).
2. Navigate to the project where you want to get the credentials.
3. In the side menu, open **Integrations → API Keys**.
4. There you'll find:
   * **Production** (Live) — `sk_live_*` or `sk_proj_*`.
   * **Test** — `sk_test_*`. Can be generated/regenerated independently of the live key.

Each key has separate show/copy/regenerate controls. Regenerating the live key does **not** affect the test key, and vice versa.

***

## Usage

Pass the key as a Bearer token in the `Authorization` header:

```
Authorization: Bearer sk_live_your_secret_key
```

```bash theme={null}
# Live
curl -X POST https://api.reallyquickemails.com/v1/send-email \
  -H "Authorization: Bearer sk_live_your_secret_key" \
  -H "Content-Type: application/json" \
  -d '{
    "recipient_email": "recipient@example.com",
    "sender_email": "noreply@yourdomain.com",
    "subject": "Hello",
    "html_body": "<h1>Hello!</h1>"
  }'

# Test (same endpoint, only the key prefix changes)
curl -X POST https://api.reallyquickemails.com/v1/send-email \
  -H "Authorization: Bearer sk_test_your_test_key" \
  -H "Content-Type: application/json" \
  -d '{
    "recipient_email": "qa@yourdomain.com",
    "sender_email": "noreply@yourdomain.com",
    "subject": "Smoke test",
    "html_body": "<p>Test from staging</p>"
  }'
```

> **Important:** every API endpoint accepts both live and test keys. RQE determines the send's mode solely by the key prefix — there is **no** `mode` parameter or special headers to force a different mode.

### Invalid prefix errors

If you pass a key with an unknown prefix (e.g. `sk_dev_`), you receive `401 Unauthorized`:

```json theme={null}
{ "error": "Invalid API key prefix. Expected sk_proj_*, sk_live_* or sk_test_*." }
```

***

## Idempotency

The `POST /send-email` ([advanced API](/en/api-reference/send-email)) and `POST /v1/send-batch` endpoints support optional idempotency via the `Idempotency-Key` header:

```
Idempotency-Key: order-12345-confirmation
```

* The key is an arbitrary string of 1 to 256 characters.
* The first request's response is cached for **24 hours**, scoped to `(project_id, idempotency_key)`.
* If another request arrives with the same key within the window, RQE returns the **cached response** from the first request, with the `Idempotency-Replayed: true` header.
* `5xx` responses are not cached — you can retry with the same key.
* Useful for network retries with no risk of double sending. Works identically in live and test.

> `POST /v1/send-email` and `POST /v1/send-template-email` do **not** support `Idempotency-Key`. If you need idempotency on individual sends, use the [advanced API](/en/api-reference/send-email).

***

## Dry Run

To validate the payload and variables without sending the email, use `POST /send-email` ([advanced API](/en/api-reference/send-email), `recipient`/`sender`/`html` fields) with `dry_run: true` in the body:

```bash theme={null}
curl -X POST https://api.reallyquickemails.com/send-email \
  -H "Authorization: Bearer sk_test_your_test_key" \
  -H "Content-Type: application/json" \
  -d '{
    "recipient": "recipient@example.com",
    "sender": "noreply@yourdomain.com",
    "subject": "Hello {{name}}",
    "html": "<h1>Hello {{name}}</h1>",
    "data": { "name": "Mary" },
    "dry_run": true
  }'
```

Response:

```json theme={null}
{
  "dry_run": true,
  "test_mode": true,
  "sample_cart_items_injected": false,
  "would_send": {
    "to": ["recipient@example.com"],
    "cc": [],
    "bcc": [],
    "from": "noreply@yourdomain.com",
    "subject": "Hello Mary",
    "html_preview": "<h1>Hello Mary</h1>",
    "template_id": null,
    "variables_used": ["name"]
  }
}
```

Nothing is sent, nothing is queued, no activity is recorded, and no quota is consumed. Useful for CI or to validate templates before a bulk send. `dry_run` is **not** available on `/v1/send-email`. See [dry run details](/en/api-reference/send-email#dry-run).

***

## Security

* **Never expose your Secret Keys in client code** (frontend, mobile apps, public repos). Use them only from the backend.
* **Environment variables** — store in `.env`, never hardcoded:

```bash theme={null}
# .env
RQE_LIVE_KEY=sk_live_your_secret_key
RQE_TEST_KEY=sk_test_your_test_key
```

```javascript theme={null}
// Node.js example — use the correct key based on the environment
const apiKey = process.env.NODE_ENV === 'production'
  ? process.env.RQE_LIVE_KEY
  : process.env.RQE_TEST_KEY;

const response = await fetch("https://api.reallyquickemails.com/v1/send-email", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${apiKey}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    recipient_email: "customer@example.com",
    sender_email: "noreply@yourdomain.com",
    subject: "Hello",
    html_body: "<h1>Hello!</h1>",
  }),
});
```

* **Rotate your keys periodically.** If you suspect one has been compromised, regenerate it from the dashboard. The previous key is invalidated instantly.
* **Add `.env` to your `.gitignore`** so you don't push credentials to the repository.
* **Keep live and test isolated** across environments. Using the `sk_live_*` key in staging pollutes metrics and consumes quota.
