The API keys page is where every credential for your account lives. One primary key authenticates every endpoint; sub-keys, where your plan includes them, are scoped copies you can hand to a specific app, environment or teammate without giving away the primary.
The primary key
Every account gets exactly one primary key, created with the account. It reaches every API your plan includes, and it is what the samples throughout these docs use.
The card shows it masked until you reveal it, with a copy button beside it. Below that:
| Field | What it tells you |
|---|---|
| Plan | Which plan's limits this key carries |
| Total requests | Lifetime calls made with this key |
| Created | When the key was issued |
| Last used | The most recent call — the fastest way to spot a key nothing is using any more |
| Expires | The expiry date, or Never |
Last used is more useful than it looks. Before you revoke anything, it answers the question that stops most people from cleaning up old credentials: is anything still calling with this?
Scoped sub-keys
A sub-key is a second credential on the same account with its own restrictions and its own usage counter. It draws from the same credit balance and cannot exceed the plan's ceilings — it can only be narrower than the primary.
| Plan | Sub-keys |
|---|---|
| Free | Not included |
| Starter | Not included |
| Pro | 5 |
| Mega | 25 |
Reach for one whenever a key would otherwise sit somewhere you do not fully control: a staging environment, a contractor's laptop, a scheduled job, a client-side build you have not yet moved behind a proxy. Revoking a sub-key affects that one caller and nothing else, which is the entire point.
Restrictions
Each key has an Edit restrictions dialog with three tabs. They are gated by plan, because they solve problems that only appear at a certain size:
| Restriction | Plan | What it does |
|---|---|---|
| Block specific APIs | Pro and above | The key reaches everything by default; search and block individual APIs. Everything not blocked stays allowed. |
| Block VerveKit tools | Pro and above | Turn individual VerveKit tools off for this key. |
| IP allow-list and rate limit | Mega | Restrict the key to named IP addresses, and set a per-minute limit below your plan's default. |
The API-blocking model is a deny-list, not an allow-list, and that is worth internalising: a key with nothing blocked reaches every API in the catalog, and a newly launched API is reachable by every existing key from the moment it ships. If you need a key that can only ever call two endpoints, block the rest — there is no "allow only these" mode.
A custom rate limit can only go down. Leaving it blank uses your plan's default, which is the right choice unless you are deliberately capping a noisy client.
Blocked calls return 403 with a message naming the restriction, not 401. See
errors — sending a user to re-authenticate on a scoping failure sends them to
fix something that is not broken.
Expiry
Keys never expire by default. On paid plans you can set an expiry when you rotate, which turns the key into something that cleans itself up: useful for a contractor, a demo, or a migration where you want the old credential to die on a known date rather than on a reminder you might not act on.
An expired key returns 401, the same as a key that was never valid.
Rotation
Rotating replaces the key immediately. There is no grace period and no overlap window:
The current key stops working the moment you confirm. Every request still using it returns 401
until you deploy the replacement.
So the order matters. Have the new value ready to deploy before you rotate, not after — the page reloads with the new key on the card, and the window between rotating and shipping it is downtime. If your deployment takes minutes rather than seconds, rotate a sub-key instead: create the replacement, migrate, then delete the old one, which gives you the overlap the primary key does not offer.
Key rotation covers the zero-downtime sequence in detail.
Revoking a sub-key
Deleting a sub-key is permanent and immediate — anything using it starts receiving 401. Because
sub-keys are per-caller, that is a targeted action rather than an outage, which is exactly the
tradeoff they exist to give you.
The forms key
Accounts on plans that include embedded forms get a separate hosted forms key, shown on the same page. It is a distinct credential from your API key because it is designed to be public — it lives in a form embed on your site — and it can only submit to forms you have configured.
| Plan | Embedded forms |
|---|---|
| Free | Not included |
| Starter | Not included |
| Pro | 10 |
| Mega | 30 |
Do not substitute your API key for it, and do not put your API key in a page. The forms key exists precisely so that you never have to.
Keeping keys out of trouble
The failure mode is almost never a stolen key. It is a key committed to a repository, baked into a client bundle, or pasted into a support ticket.
- Read keys from the environment, never from source. Quickstart has the guard that fails loudly when the variable is unset.
- Never ship a key to a browser or a mobile app. Anything a client can run, a user can read. Proxy through your own backend.
- Use a different key per environment so a runaway test loop cannot spend production credits, and so the usage graph tells you which system is doing what.
- Check Last used before you revoke, and rotate on a schedule rather than only after an incident.
Next
Authentication covers the header, the rejection modes and what each status means. Key scoping, key rotation and sub-keys go deeper on each control above.