Keys
Create, name and revoke a key, where the cap actually lives, and the header an agent sends.
A key raises the no-key allowance of 60 calls a day per IP to your plan's monthly cap, and it is the one thing submit_trap requires. Everything else works without one.
Create a key
Sign up at wellworn.dev/keys, confirm the address from the mail that arrives, then open /app/keys. Every key needs a name, up to 40 characters; use the machine or the job it belongs to, such as laptop, ci, staging, so the last-used column tells you something later.
The value is shown once, in the dialog that opens right after creation. It is stored as a SHA-256 hash, so nobody, including us, can read it back. Lose it and the fix is to create a new key and revoke the old one.
Sign-up refuses disposable addresses. The list is 200 domains and is matched on the exact domain, so a subdomain of a listed host passes; it is a spam control, not a security control.
What the list shows
| Column | What it holds |
|---|---|
| Name | The name you typed. Editing it is not open yet. |
| Prefix | The first characters of the key, always starting ww_, so you can tell two keys apart. |
| Created | The day the key was made, in UTC. |
| Last used | The day of the most recent verified call, or never. |
Last used comes from Better Auth's own lastRequest field on the key row, updated when the server verifies the token, so a key that only ever failed verification still reads never.
Revoke
Revoking deletes the key row. There is no undo and no grace period: the next call carrying that value is verified against nothing and the server answers 401 invalid key rather than dropping the caller to the no-key tier. Rotating a key is therefore create, change the config, then revoke, in that order.
The header
The key is a bearer token.
Authorization: Bearer ww_your_keyEvery client page in the Clients section shows where that header goes for that client. A typo is rejected with 401 instead of being silently downgraded, so a broken config shows up on the first call.
The cap belongs to the organization
Signing up creates one organization for you, and the key row points at it (references: "organization" in packages/auth/src/index.ts). The monthly cap is counted against the organization, so a second key buys nothing extra: it is a second label on the same allowance. Keys are visible to everyone in the organization, which is why one key per machine beats one key shared by hand.
Tiers
| Tier | Cap | Window | Burst |
|---|---|---|---|
| No key | 60 calls | day, per IP | 10 a minute |
| Free key | 2,000 calls | month, per organization | 30 a minute |
| Pro | 20,000 calls | month, per organization | 120 a minute |
| Team | 100,000 calls | month, pooled | 300 a minute |
The burst counter is a fixed 60-second window that starts at the first call of a burst and sits on top of the window cap, so a runaway loop cannot spend a month of calls in a minute. Full details in plans and credits.
What counts as a call
One tool call is one call. The initialize handshake, tools/list, and /health are not metered. A request to the plain-text traps endpoint at /api/traps goes through the same limiter, which is why the Claude Code hook is counted the same way a tool is.
At the cap
Nothing throws. The tool returns one line:
limit reached: no-key 60/60 today (resets 2026-09-09T00:00:00.000Z). Free key or plans: https://wellworn.dev/pricingThe agent reads that as an answer and carries on with the rest of its work. A keyed caller gets the same line with plan and this month in place of no-key and today.