# Authentication

URLpipe authenticates every request with an HTTP bearer token. The token is your project's API key — there is nothing else to configure: no OAuth flow, no signed requests, no session to keep alive.

## Sending your API key

Add an `Authorization` header with the value `Bearer YOUR_API_KEY` to every request. The scheme keyword `Bearer` is required, followed by a single space and then the key exactly as issued — no quotes, and no extra whitespace. Requests without a valid key are rejected with `401 Unauthorized` before any work is done, so a rejected request never spends credits.

```
curl -X POST https://urlpipe.dev/markdown \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com"}'
```

## Confirming your email address

A key starts working once one of the organization's admins has confirmed their email address, or as soon as the organization is on a paid plan. We send the link the moment you sign up; clicking it once brings every key in the organization — this one and any created later, by anyone on the team — to life. Until then, on the free plan, the API answers `403 Forbidden`:

403 Forbidden

```
{
  "error": "email_unverified",
  "message": "An admin of this organization needs to confirm their email address before the API can be used."
}
```

The key itself is valid, so sending it again — or rotating it for a new one — changes nothing. The dashboard and the Playground are not gated: you can sign in and use both while the address is unconfirmed. If the email never arrived, the admin signs in and uses **Account Settings → Send a confirmation link** to get another one.

## Testing your key

The quickest way to confirm a key works is to send any real request — the `/markdown` call above against a page you control is a good choice. A `200` (or a `422` about the URL itself) means the key authenticated; a `401` means the header never reached us in a form we accept. When you see a `401`, check that the header name is exactly `Authorization`, that the value starts with `Bearer`, and that no proxy or framework is stripping or rewriting the header in transit.

## How keys are scoped

Each API key belongs to a single **project**. A project owns its own request history and draws on its organization's monthly credit allowance. Using separate projects per app or environment keeps history clean and lets you rotate one key without disturbing the others. A common setup is one project per environment — `staging` and `production` — so a leaked staging key can be rotated without touching live traffic, and each environment's usage shows up separately in the dashboard.

## Storing and rotating your key

Your key is shown once, when you create the project. We store a hash of it and never the key itself, so it cannot be shown to you again — and a copy of our database is not a copy of your credentials. **Settings → API key** shows only its first few characters, which is enough to tell which key a server is running.

Lost it? Rotate it from that screen. You are shown the new key once, and the key it replaces keeps authenticating for 24 hours — so you can deploy the new one at your leisure instead of racing a window where live requests fail with `401`.

Rotated because the key leaked? Use **Stop accepting old key** once the new one is deployed. That closes the window immediately: a key we still honour is one that whoever took it can still spend.

## Keeping your key secure

Your API key is a secret: anyone who has it can spend your credits and read whatever your account can. Treat it like a password.

- Send every request over HTTPS — never plain HTTP, which exposes the key in transit.
- Keep the key server-side. Never embed it in browser JavaScript, mobile apps, or any code shipped to users, where it can be extracted.
- Load it from an environment variable or a secrets manager. Don't hard-code it in source or commit it to version control — scanners harvest public repositories within minutes.
- Use a distinct key per environment so you can rotate one without affecting the others.
- Rotate immediately if a key is ever exposed — then stop accepting the old one, rather than letting its 24-hour window run out on its own.

## Authentication errors

Two things cause a 401:

- The Authorization header is missing.
- The token doesn't match any active project key.

Everything else — a bad URL, a page that's too big, a timeout — is a `422` with a descriptive body. See [Errors](https://urlpipe.dev/docs/errors) for the full list.

Source: https://urlpipe.dev/docs/authentication
