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

# Authentication

Pivolio has two API surfaces, each authenticated differently.

## Ingestion — write key

Event-collection endpoints authenticate with a workspace **write key**, sent in
the `X-Write-Key` header. Note that all four required event fields must be
present — `event_id`, `event_name`, `event_time` (Unix **seconds**) and
`anonymous_id` — or the request returns `422`:

```bash
curl https://api.pivolio.com/track \
  -H "X-Write-Key: wk_live_xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "event_id": "01JQ8Z3M9V4K7C2N6P8R5T1W0X",
    "event_name": "page_view",
    "event_time": 1750000000,
    "anonymous_id": "anon_9f2c1d84-3b7a-4e56-8c10-2ad4f9b7e103"
  }'
```

A write key identifies a workspace and can only ingest events. It can't read
your data, list your customers, or change any setting. Create and rotate keys in
the dashboard under **Settings → API keys**.

## Two kinds of write key

The header is the same either way, but the keys are not interchangeable and one
of them is a secret.

* **First-party SDK key** — the key you pass to the browser SDK as `writeKey`.
  It is **public by design**: it ships in your JavaScript bundle, and anyone can
  read it out of your page source. That's acceptable because the worst it
  permits is sending events into your own workspace.
* **Integration key** — generated per inbound source (a webhook, Shopify) and
  used server-to-server against `/ingest/integration`. This one is a **secret**.
  Keep it in environment configuration, never in client code. See
  [Inbound webhook](/documentation/integrations/inbound-webhook).

> **Warning**
>
> The two are enforced, not merely conventional: `/ingest/integration` returns
> `403` if you present a first-party SDK key. Swapping one key for the other to
> "make it work" is a sign you're calling the wrong endpoint.

Because an SDK key is public, treat rotation as routine rather than an incident
response. Re-creating an integration source **rotates** its key, which
immediately invalidates the old one — update the caller in the same change.

## Passing the key another way

`/pixel` also accepts the key as a `wk` query parameter, because an `<img>` tag
can't set headers:

```bash
curl "https://api.pivolio.com/pixel?wk=wk_live_xxxxxxxxxxxx\
&event_id=01JQ8Z3M9V4K7C2N6P8R5T1W0X\
&event_name=page_view\
&event_time=1750000000\
&anonymous_id=anon_9f2c1d84-3b7a-4e56-8c10-2ad4f9b7e103\
&format=img"
```

Use this only for the SDK key. An integration secret in a URL ends up in
referrer headers, proxy logs and CDN caches.

## Management — session cookie

Workspace, destination, integration, reporting and account endpoints
authenticate with the **session cookie** issued when you sign in to the
dashboard. There are no management API tokens — these endpoints are designed for
the dashboard UI rather than server-to-server automation.

Practically, that means a write key will never get you access to reporting or
configuration. If you're scripting against a management endpoint, you're
authenticating as a signed-in user.

> **Note**
>
> Browse the **API Reference** to see which authentication each endpoint expects —
> ingestion endpoints take the write key, everything else uses the session.

## Related

* [Sending events over HTTP](/documentation/guides/http-api) — the full ingestion surface
  and the required event fields.
* [Errors](/documentation/guides/errors) — what a `401`, `403` or `422` means here.