# Tracking keys API

> Manage the public keys that the tracking script uses to send events from your website.

Base URL: `https://api.emailit.com/v2`. Authenticate with `Authorization: Bearer <API key>`.

## Create a tracking key — POST /tracking-keys

> Create a public tracking key for the Emailit tracking script, optionally limited to your own sites.

# Create a tracking key

Creates a tracking key for the [tracking script](/docs/events/tracking-script/). The response includes the public `key` that goes into the script URL. Requires an API key with the `full` scope.

Tracking keys are public, so anyone can copy one from your page. They can only send workspace and custom events, never read data, and you can limit them to your own sites with `allowed_origins`. A workspace can have up to 25 tracking keys.

Website tracking is included with Pro, Business and Custom plans. Keys stay after a move to Pay as you go, but the tracking script's requests with them return `403`.

`POST /tracking-keys`

## Body parameters

- `name` (string): Name that tells you where the key is used, such as `Online shop`, up to 100 characters.

- `allowed_origins` (string[]): The sites allowed to send events with the key, up to 50. Empty or omitted means any site. Each entry is one of: - an origin, such as `https://shop.example.com`: that scheme, host and port only; - a host, such as `shop.example.com`: that host on any scheme or port; - a wildcard, such as `*.example.com`: `example.com` and all of its subdomains. Entries are stored in lowercase, without a trailing slash. A string with entries separated by spaces or commas is accepted too.

- `enabled` (boolean): `false` creates the key turned off.

## Returns

Returns `201 Created` with the [tracking key object](/docs/api-reference/tracking-keys/get/).

| Status | When |
| --- | --- |
| `403` | The API key doesn't have the `full` scope, or the workspace is on Pay as you go: `error` is `plan_required` and `required_plan` is `pro`. |
| `422` | A field is invalid, for example an entry in `allowed_origins` that isn't an origin, host or wildcard. `errors` is keyed by field and `message` repeats the first problem. Also returned with `code: "tracking_keys_limit"` when the workspace already has 25 tracking keys. |

**Request** `POST /tracking-keys`

**cURL**

```bash
curl -X POST https://api.emailit.com/v2/tracking-keys \
  -H "Authorization: Bearer $EMAILIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Online shop",
    "allowed_origins": ["https://shop.example.com", "*.example.com"]
  }'
```

**Node.js**

```javascript
const res = await fetch('https://api.emailit.com/v2/tracking-keys', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.EMAILIT_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    name: 'Online shop',
    allowed_origins: ['https://shop.example.com', '*.example.com'],
  }),
});
const trackingKey = await res.json();
```

**Python**

```python
import os, requests

r = requests.post(
    "https://api.emailit.com/v2/tracking-keys",
    headers={"Authorization": f"Bearer {os.environ['EMAILIT_API_KEY']}"},
    json={
        "name": "Online shop",
        "allowed_origins": ["https://shop.example.com", "*.example.com"],
    },
)
tracking_key = r.json()
```

**PHP**

```php
$client = new GuzzleHttp\Client(['base_uri' => 'https://api.emailit.com/v2/']);

$response = $client->post('tracking-keys', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('EMAILIT_API_KEY')],
    'json' => [
        'name' => 'Online shop',
        'allowed_origins' => ['https://shop.example.com', '*.example.com'],
    ],
]);
$trackingKey = json_decode($response->getBody(), true);
```

**201**

```json
{
  "object": "tracking_key",
  "id": "trk_2yHn5Pq2WcR7tY4uNs8KdV1bXj6",
  "name": "Online shop",
  "key": "pub_8fK2mQ9xLr4TzW7nB1cV5yH3dJ6sA0pE",
  "allowed_origins": ["https://shop.example.com", "*.example.com"],
  "enabled": true,
  "last_used_at": null,
  "created_at": "2026-10-19T08:05:00.000000+00:00",
  "updated_at": "2026-10-19T08:05:00.000000+00:00"
}
```

**403**

```json
{
  "error": "plan_required",
  "required_plan": "pro",
  "message": "Website tracking is included with Pro and Business."
}
```

**422**

```json
{
  "error": "allowed_origins \"https://shop.example.com/checkout\" is not an origin (https://example.com), a host (example.com) or a wildcard (*.example.com)",
  "message": "allowed_origins \"https://shop.example.com/checkout\" is not an origin (https://example.com), a host (example.com) or a wildcard (*.example.com)",
  "errors": {
    "allowed_origins": ["\"https://shop.example.com/checkout\" is not an origin (https://example.com), a host (example.com) or a wildcard (*.example.com)"]
  }
}
```

---
Source: https://emailit.com/docs/api-reference/tracking-keys/create/

## Retrieve a tracking key — GET /tracking-keys/{id}

> Retrieve a tracking key for the Emailit tracking script, with its public key, allowed sites and last use.

# Retrieve a tracking key

Retrieves a tracking key. Tracking keys are public keys for the [tracking script](/docs/events/tracking-script/): they go into your web pages and can only send workspace and custom events. Requires an API key with the `full` scope.

`GET /tracking-keys/{id}`

## Path parameters

- `id` (string, required): The tracking key's ID (`trk_…`) or the key itself (`pub_…`).

## Returns

Returns the tracking key object.

- `object` (string): Always `tracking_key`.

- `id` (string): ID of the tracking key, prefixed `trk_`.

- `name` (string): Name that tells you where the key is used.

- `key` (string): The public key: `pub_` followed by 32 letters and digits. It's part of the script URL, so it's returned on every read.

- `allowed_origins` (string[]): The sites that may send events with this key. Empty means any site. See [Allowed sites](/docs/events/tracking-script/#allowed-sites).

- `enabled` (boolean): `false` when the key is turned off. Events sent with a disabled key are rejected.

- `last_used_at` (string | null): When the key last sent events, updated at most every 10 minutes. `null` if it has never been used.

- `created_at, updated_at` (string): Timestamps in UTC.

Returns `404` with `error: "Tracking key not found"` if no key matches.

**Request** `GET /tracking-keys/{id}`

**cURL**

```bash
curl https://api.emailit.com/v2/tracking-keys/trk_2yHn5Pq2WcR7tY4uNs8KdV1bXj6 \
  -H "Authorization: Bearer $EMAILIT_API_KEY"
```

**Node.js**

```javascript
const res = await fetch('https://api.emailit.com/v2/tracking-keys/trk_2yHn5Pq2WcR7tY4uNs8KdV1bXj6', {
  headers: { Authorization: `Bearer ${process.env.EMAILIT_API_KEY}` },
});
const trackingKey = await res.json();
```

**Python**

```python
import os, requests

r = requests.get(
    "https://api.emailit.com/v2/tracking-keys/trk_2yHn5Pq2WcR7tY4uNs8KdV1bXj6",
    headers={"Authorization": f"Bearer {os.environ['EMAILIT_API_KEY']}"},
)
tracking_key = r.json()
```

**PHP**

```php
$client = new GuzzleHttp\Client(['base_uri' => 'https://api.emailit.com/v2/']);

$response = $client->get('tracking-keys/trk_2yHn5Pq2WcR7tY4uNs8KdV1bXj6', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('EMAILIT_API_KEY')],
]);
$trackingKey = json_decode($response->getBody(), true);
```

**200**

```json
{
  "object": "tracking_key",
  "id": "trk_2yHn5Pq2WcR7tY4uNs8KdV1bXj6",
  "name": "Online shop",
  "key": "pub_8fK2mQ9xLr4TzW7nB1cV5yH3dJ6sA0pE",
  "allowed_origins": ["https://shop.example.com", "*.example.com"],
  "enabled": true,
  "last_used_at": "2026-10-19T09:40:00.000000+00:00",
  "created_at": "2026-10-19T08:05:00.000000+00:00",
  "updated_at": "2026-10-19T08:05:00.000000+00:00"
}
```

**404**

```json
{
  "error": "Tracking key not found"
}
```

---
Source: https://emailit.com/docs/api-reference/tracking-keys/get/

## Update a tracking key — POST /tracking-keys/{id}

> Rename a tracking key, change its allowed sites, or turn it off and on. The public key stays the same.

# Update a tracking key

Updates the fields you pass and leaves the others unchanged. The public `key` never changes; to replace a key, create a new one, update your pages and delete the old one. Requires an API key with the `full` scope.

Changes can take up to a minute to apply everywhere.

`POST /tracking-keys/{id}`

## Path parameters

- `id` (string, required): The tracking key's ID (`trk_…`) or the key itself (`pub_…`).

## Body parameters

- `name` (string): New name, up to 100 characters. Can't be empty.

- `allowed_origins` (string[]): Replaces the list of allowed sites, with the same rules as on [create](/docs/api-reference/tracking-keys/create/#body-parameters). `[]` allows any site.

- `enabled` (boolean): `false` turns the key off: the tracking script keeps loading, but its events are rejected with `403`. `true` turns it back on.

## Returns

Returns the updated [tracking key object](/docs/api-reference/tracking-keys/get/).

| Status | When |
| --- | --- |
| `404` | No tracking key matches `id`. |
| `422` | A field is invalid. `errors` is keyed by field and `message` repeats the first problem. |

**Request** `POST /tracking-keys/{id}`

**cURL**

```bash
curl -X POST https://api.emailit.com/v2/tracking-keys/trk_2yHn5Pq2WcR7tY4uNs8KdV1bXj6 \
  -H "Authorization: Bearer $EMAILIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "allowed_origins": ["https://shop.example.com", "https://www.example.com"] }'
```

**Node.js**

```javascript
const res = await fetch('https://api.emailit.com/v2/tracking-keys/trk_2yHn5Pq2WcR7tY4uNs8KdV1bXj6', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.EMAILIT_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ allowed_origins: ['https://shop.example.com', 'https://www.example.com'] }),
});
const trackingKey = await res.json();
```

**Python**

```python
import os, requests

r = requests.post(
    "https://api.emailit.com/v2/tracking-keys/trk_2yHn5Pq2WcR7tY4uNs8KdV1bXj6",
    headers={"Authorization": f"Bearer {os.environ['EMAILIT_API_KEY']}"},
    json={"allowed_origins": ["https://shop.example.com", "https://www.example.com"]},
)
tracking_key = r.json()
```

**PHP**

```php
$client = new GuzzleHttp\Client(['base_uri' => 'https://api.emailit.com/v2/']);

$response = $client->post('tracking-keys/trk_2yHn5Pq2WcR7tY4uNs8KdV1bXj6', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('EMAILIT_API_KEY')],
    'json' => ['allowed_origins' => ['https://shop.example.com', 'https://www.example.com']],
]);
$trackingKey = json_decode($response->getBody(), true);
```

**200**

```json
{
  "object": "tracking_key",
  "id": "trk_2yHn5Pq2WcR7tY4uNs8KdV1bXj6",
  "name": "Online shop",
  "key": "pub_8fK2mQ9xLr4TzW7nB1cV5yH3dJ6sA0pE",
  "allowed_origins": ["https://shop.example.com", "https://www.example.com"],
  "enabled": true,
  "last_used_at": "2026-10-19T09:40:00.000000+00:00",
  "created_at": "2026-10-19T08:05:00.000000+00:00",
  "updated_at": "2026-10-19T10:20:00.000000+00:00"
}
```

---
Source: https://emailit.com/docs/api-reference/tracking-keys/update/

## List tracking keys — GET /tracking-keys

> List the workspace's tracking keys for the Emailit tracking script, newest first.

# List tracking keys

Returns all of the workspace's tracking keys, newest first. A workspace has at most 25, so the list isn't paginated. Requires an API key with the `full` scope.

`GET /tracking-keys`

## Query parameters

- `search` (string): Case-insensitive match on part of the name.

- `match`, `order`, `direction`: see [Filtering](https://emailit.com/docs/api-reference/filtering/).

### Filter keys

Filters use `key.condition=value` query parameters, for example `enabled.exact=true`. See [Filtering](/docs/api-reference/filtering/) for the conditions per type.

| Key | Type | Notes |
| --- | --- | --- |
| `name` | string | |
| `enabled` | boolean | |
| `created_at` | date | |
| `last_used_at` | date | |

Sort keys for `order`: `name`, `enabled`, `created_at`, `last_used_at`. The default is `created_at`, newest first.

## Returns

- `data` (object[]): The [tracking key objects](/docs/api-reference/tracking-keys/get/), including each public `key`.

**Request** `GET /tracking-keys`

**cURL**

```bash
curl https://api.emailit.com/v2/tracking-keys \
  -H "Authorization: Bearer $EMAILIT_API_KEY"
```

**Node.js**

```javascript
const res = await fetch('https://api.emailit.com/v2/tracking-keys', {
  headers: { Authorization: `Bearer ${process.env.EMAILIT_API_KEY}` },
});
const { data } = await res.json();
```

**Python**

```python
import os, requests

r = requests.get(
    "https://api.emailit.com/v2/tracking-keys",
    headers={"Authorization": f"Bearer {os.environ['EMAILIT_API_KEY']}"},
)
tracking_keys = r.json()["data"]
```

**PHP**

```php
$client = new GuzzleHttp\Client(['base_uri' => 'https://api.emailit.com/v2/']);

$response = $client->get('tracking-keys', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('EMAILIT_API_KEY')],
]);
$trackingKeys = json_decode($response->getBody(), true)['data'];
```

**200**

```json
{
  "data": [
    {
      "object": "tracking_key",
      "id": "trk_2yHn5Pq2WcR7tY4uNs8KdV1bXj6",
      "name": "Online shop",
      "key": "pub_8fK2mQ9xLr4TzW7nB1cV5yH3dJ6sA0pE",
      "allowed_origins": ["https://shop.example.com", "*.example.com"],
      "enabled": true,
      "last_used_at": "2026-10-19T09:40:00.000000+00:00",
      "created_at": "2026-10-19T08:05:00.000000+00:00",
      "updated_at": "2026-10-19T08:05:00.000000+00:00"
    }
  ]
}
```

---
Source: https://emailit.com/docs/api-reference/tracking-keys/list/

## Delete a tracking key — DELETE /tracking-keys/{id}

> Delete a tracking key. Pages that still use it stop sending events; events already recorded are kept.

# Delete a tracking key

Deletes a tracking key. Requires an API key with the `full` scope.

Pages that still load the script with this key keep working, but their events are rejected and not recorded. Events already recorded with the key are kept. To stop events for a while without changing your pages, turn the key off with [Update a tracking key](/docs/api-reference/tracking-keys/update/) instead.

`DELETE /tracking-keys/{id}`

## Path parameters

- `id` (string, required): The tracking key's ID (`trk_…`) or the key itself (`pub_…`).

## Returns

- `object` (string): Always `tracking_key`.

- `id` (string): ID of the deleted key.

- `deleted` (boolean): Always `true`.

Returns `404` if no tracking key matches.

**Request** `DELETE /tracking-keys/{id}`

**cURL**

```bash
curl -X DELETE https://api.emailit.com/v2/tracking-keys/trk_2yHn5Pq2WcR7tY4uNs8KdV1bXj6 \
  -H "Authorization: Bearer $EMAILIT_API_KEY"
```

**Node.js**

```javascript
const res = await fetch('https://api.emailit.com/v2/tracking-keys/trk_2yHn5Pq2WcR7tY4uNs8KdV1bXj6', {
  method: 'DELETE',
  headers: { Authorization: `Bearer ${process.env.EMAILIT_API_KEY}` },
});
const result = await res.json();
```

**Python**

```python
import os, requests

r = requests.delete(
    "https://api.emailit.com/v2/tracking-keys/trk_2yHn5Pq2WcR7tY4uNs8KdV1bXj6",
    headers={"Authorization": f"Bearer {os.environ['EMAILIT_API_KEY']}"},
)
result = r.json()
```

**PHP**

```php
$client = new GuzzleHttp\Client(['base_uri' => 'https://api.emailit.com/v2/']);

$response = $client->delete('tracking-keys/trk_2yHn5Pq2WcR7tY4uNs8KdV1bXj6', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('EMAILIT_API_KEY')],
]);
$result = json_decode($response->getBody(), true);
```

**200**

```json
{
  "object": "tracking_key",
  "id": "trk_2yHn5Pq2WcR7tY4uNs8KdV1bXj6",
  "deleted": true
}
```

---
Source: https://emailit.com/docs/api-reference/tracking-keys/delete/
