# Potarix Enricher - Authentication

Machine-readable auth reference for the Potarix Enricher API.

The Enricher's primary auth is **bearer API keys**: obtain one long-lived API key (it starts with `ptk_live_`) and send it on every billable and account request. Two OAuth 2.0 flows are also available for platforms that prefer them (see [OAuth 2.0](#oauth-20) below): `client_credentials` (machine-to-machine, bills the key owner) and `authorization_code` with PKCE (per-user login + consent, bills each end user's own credits). There is no token-refresh endpoint; tokens are short-lived, just request a new one.

## Auth method

- **Type:** HTTP bearer token
- **Header:** `Authorization`
- **Scheme:** `Bearer`
- **Token format:** `ptk_live_` followed by an opaque secret
- **Example header:** `Authorization: Bearer ptk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`

## How to get a key (headless, no browser)

Both endpoints take `{ "email", "password" }` and return the key once. Store it immediately.

### New account

```bash
curl -s -X POST https://api.potarix.com/enricher/auth/signup \
  -H "Content-Type: application/json" \
  -d '{ "email": "you@company.com", "password": "a-strong-password", "label": "my-agent" }'
# -> { "api_key": "ptk_live_...", "key_prefix": "ptk_live_...", "credits_remaining": 25 }
```

A new account is granted **25 free trial credits**. If the email already exists you get `409`; use `/auth/api-keys` instead.

### Existing account

```bash
curl -s -X POST https://api.potarix.com/enricher/auth/api-keys \
  -H "Content-Type: application/json" \
  -d '{ "email": "you@company.com", "password": "a-strong-password" }'
# -> { "api_key": "ptk_live_...", "key_prefix": "ptk_live_..." }
```

The key is shown **once**. Keep it in an env var or secret store. Never commit it.

## Using the key

```bash
export PTK="ptk_live_..."

curl -s -X POST https://api.potarix.com/enricher/find-website \
  -H "Authorization: Bearer $PTK" \
  -H "Content-Type: application/json" \
  -d '{ "company_name": "Stripe Inc." }'
```

## Auth-related endpoints

| Endpoint | Method | Auth | Purpose |
|---|---|---|---|
| `/auth/signup` | POST | none | Create an account and mint the first API key (25 free trial credits). |
| `/auth/api-keys` | POST | none | Mint a fresh API key for an existing account from email + password. |
| `/me` | GET | bearer | Profile, credit balance, has_saved_card, API-key count. |
| `/credits` | GET | bearer | Credit balance only. Also a cheap auth health check. |

## Error responses

- `401 Unauthorized` - missing or invalid key. The response carries a `WWW-Authenticate` header pointing here:
  `WWW-Authenticate: Bearer realm="potarix-enricher", error="invalid_token", docs="https://enricher.potarix.com/auth.md"`
- `402 Payment Required` - valid key but out of credits. Top up via `POST /billing/topup`, then retry.

## OAuth 2.0

Two grant types, both returning a short-lived `Bearer` access token (`expires_in: 3600`) that you send exactly like an API key. Discovery starts at the protected-resource metadata `https://enricher.potarix.com/.well-known/oauth-protected-resource` (RFC 9728), whose `authorization_servers` point to the authorization-server metadata `https://enricher.potarix.com/.well-known/oauth-authorization-server` (RFC 8414, includes an `agent_auth` block). A `401` from the API also carries `WWW-Authenticate: Bearer ... resource_metadata="https://enricher.potarix.com/.well-known/oauth-protected-resource"`.

### client_credentials (machine-to-machine)

Exchange an existing `ptk_live_` key for a token. Resolves to the **same account** as the key, so it bills the key owner.

```bash
curl -s -X POST https://api.potarix.com/enricher/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials&client_secret=ptk_live_..."
```

### authorization_code + PKCE (per-user login, bills each user)

For multi-user products (e.g. a public ChatGPT GPT) where **each end user pays with their own credits**, not the builder's. Public client, no `client_secret`; PKCE (`S256`) protects the exchange.

1. Send the user to the authorization endpoint:
   `GET https://api.potarix.com/enricher/oauth/authorize?response_type=code&client_id=YOUR_CLIENT_ID&redirect_uri=YOUR_CALLBACK&scope=enricher:all&state=RANDOM&code_challenge=BASE64URL_SHA256(verifier)&code_challenge_method=S256`
2. The user signs into Potarix and approves on a consent screen.
3. We redirect back to your `redirect_uri` with `?code=...&state=...`.
4. Exchange the code:

```bash
curl -s -X POST https://api.potarix.com/enricher/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=authorization_code&code=THE_CODE&redirect_uri=YOUR_CALLBACK&client_id=YOUR_CLIENT_ID&code_verifier=THE_VERIFIER"
# -> { "access_token": "...", "token_type": "Bearer", "expires_in": 3600, "scope": "enricher:all" }
```

The token's subject is the consenting user, so `/find-*` calls draw down **that user's** credit balance. Authorization codes are single-use and expire in 10 minutes. Your `redirect_uri` must be pre-registered.

## Notes

- One key authenticates everything; scopes are not used.
- Rotate a key by minting a new one via `/auth/api-keys` (or from the Settings page in the dashboard).
- Base URL for every call: `https://api.potarix.com/enricher`.
