# Authentication

How to create an API key, send it, scope it to the right permissions, and keep it out of your browser bundle.

Source: https://sourceloop.ai/help/api/authentication/

---

Every request carries a SourceLoop API key as a bearer token. There is no separate login step, no token exchange, and no expiry to refresh.

```bash
curl -s "https://app.sourceloop.ai/api/v1/me" \
  -H "Authorization: Bearer $SOURCELOOP_API_KEY"
```

Keys look like `slk_live_…`. If you prefer a dedicated header, `X-API-Key` is accepted and behaves identically. Never pass a key in the query string: URLs end up in server logs, browser history, and referrer headers.

## Create a key

In the app, go to **Settings, Developers, API keys** and create one. The full key is shown once, at creation. We store only a hash of it, so a lost key is replaced rather than recovered.

Two things to decide when you create it:

- **Which websites it covers.** A key can be scoped to one website or to every website in the workspace. Agency keys usually cover all of them, so one credential can pull every client.
- **Which scopes it carries.** See below.

## Scopes

A key only does what its scopes allow. Ask for the narrowest set that makes your integration work, so a leaked reporting key cannot move a deal.

| Scope | Grants |
|---|---|
| `metrics:read` | Aggregated metrics, breakdowns, timeseries, funnels, paths, products, ad performance, attribution coverage |
| `conversions:read` | The contact ledger, single contacts, their journeys, and `/v1/changes` |
| `conversions:write` | Update a contact's status, value or notes |
| `companies:read` | Companies, firmographics, pipeline rollups, company journeys |
| `companies:write` | Update company firmographics |
| `deals:read` | Deals, pipelines and stages, deal values, deal journeys |
| `deals:write` | Move a deal or change its value, written through to the CRM that owns it |
| `events:write` | Send server-side events |
| `pii:read` | Return real email addresses, phone numbers and names instead of masked ones |

`pii:read` is the one to think hardest about, and the one to be deliberate about at creation time: **new keys include it by default**. A key without it still works, but email, phone and name come back masked. Leave it off for anything analytical, and for any key you hand to an AI assistant. See [Data provenance and PII »](/help/api/provenance/).

Three endpoints need no scope at all beyond a valid key: `GET /v1/me`, `GET /v1/websites`, and `GET /v1/schema`.

## Check what a key can do

`GET /v1/me` answers it directly, which makes it the right first call in any integration and the right thing to log when something returns `403`.

```bash
curl -s "https://app.sourceloop.ai/api/v1/me" \
  -H "Authorization: Bearer $SOURCELOOP_API_KEY"
```

A request that is missing a scope fails with `403` and an `insufficient-scope` problem document naming the scope it wanted. You do not have to guess.

## Where to keep the key

Server side only. The API is built for server-to-server and agent use, and a key in a browser bundle is a key in every visitor's devtools. We deliberately do not reflect an origin for browser calls.

If you want attribution from browser code, that is what the tracking pixel and the SDK are for. See [Install the SourceLoop SDK »](/help/install-the-sourceloop-sdk/), which uses a public `websiteId` rather than a secret key.

## Rotating and revoking

Create the replacement first, deploy it, then revoke the old one. Revocation takes effect immediately, and a revoked key returns `401` on the next call. Every key records when it was last used, so you can tell which are dormant before you remove them.

Rate limits are counted per workspace, not per key, so minting a second key does not buy a second budget. See [Errors and rate limits »](/help/api/errors/).