> ## Documentation Index
> Fetch the complete documentation index at: https://docs.revcenter.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# API Keys & Credentials

> Managing the keys Revcenter depends on

The **Credentials** page (`/admin/credentials`) manages the API keys the app calls out
to. Keys saved here take effect **immediately** — no Vercel environment variable to set,
no redeploy.

## The providers

| Provider    | Used for                                               | Required                               |
| ----------- | ------------------------------------------------------ | -------------------------------------- |
| Harvest API | LinkedIn company, job, and profile data                | Yes                                    |
| Serper      | Google search dorks                                    | Yes                                    |
| Anthropic   | Criteria extraction (the calibrate screen) + rationale | Yes                                    |
| Supabase    | Database, storage, realtime                            | Yes — infrastructure, not managed here |
| Prospeo     | Email / mobile enrichment waterfall                    | No                                     |
| HeyReach    | LinkedIn sequencer                                     | No — not wired up yet                  |
| SmartLead   | Email sequencer                                        | No — not wired up yet                  |

Each row on the Credentials page shows a real logo (via logo.dev), the provider's
purpose, and a status:

* **`db-managed`** — an active key is stored, encrypted, in the database.
* **`.env`** — no database key, but the corresponding environment variable is set on the
  server (e.g. `HARVEST_API_KEY`). Still usable; just not rotatable from this page yet.
* **`not configured`** — neither. Adapters that need this provider will fail clearly
  rather than silently degrading.

## Adding or rotating a key

Click **Add key**, paste the key, and save. Rotating a key doesn't overwrite the old
one — the previous key is deactivated (`is_active = false`, `retired_at` set) and a new
row is inserted, so there's an audit trail of every key that was ever active.

**Deactivate** requires a confirm click (the button becomes Confirm / Cancel) before it
takes effect — no accidental one-click removal of a working key.

## How this stays secure

* Keys are encrypted with **AES-256-GCM** before they ever touch the database
  (`lib/crypto.ts`), using a server-only `CREDENTIAL_ENCRYPTION_KEY`.
* The browser never receives a key back in plaintext — only a masked hint like
  `px_test_••••2345`, generated at save time and never re-derivable from the stored
  ciphertext.
* Decryption happens exclusively in server-side code
  (`lib/domain/credentials.getProviderApiKey`), which resolves a database-stored key
  first and only falls back to the environment variable if nothing is active in the
  database.
* Every credential is scoped to your organization — the same encrypted key isn't shared
  across organizations, and the lookup always goes through your current session.

## Which endpoints actually consume a saved key today

As of this writing, only **Anthropic** is wired into a real code path
(`lib/providers/anthropic.ts`, used by the calibrate screen's extraction call). Harvest
and Serper keys save and encrypt correctly, but nothing in the app calls those APIs yet —
their provider adapters land in a later phase. Once they do, they'll automatically pick
up whatever's saved here with no additional wiring.
