Documentation sections
Authentication
Every calculator call carries an API key, on every plan; a free key costs nothing. The calculator routes, the job routes and the usage endpoint take it in either header.
Keys start with rfc_. A key is shown once, when it is created, and never again: only its hash is stored.
Send the key
Send the key in the X-API-Key header, or as Authorization: Bearer rfc_…. A request with no key is refused with 401 and a keyUrl; a key that was never issued, or was revoked, is refused with 401 too. A 401 is never about the allowance: a spent allowance is 402 (see Errors).
The allowance belongs to the account
The calls of all an account's keys, revoked ones included, count against one monthly figure; it resets at the start of each calendar month in UTC, and every call is still attributed to the key that made it.
| Plan | Calls a month, and keys |
|---|---|
| Free | 5 calls a month, 1 API key |
| Pro | 100 calls a month, 3 API keys |
| API | 10,000 calls a month, 5 API keys |
Get a key
A person gets one from the dashboard. A program has two ways to hand its user one, and both give an ordinary rfc_ key, metered, listed and revocable like any other.
A key link
Open https://rftools.io/dashboard/?newKey=1&client=<clientId>[&label=<text>] in the user's browser. clientId names the program and matches ^[a-z0-9][a-z0-9-]{1,39}$, for example kicad-plugin; a value that does not match is ignored, not refused. A signed-out user signs in or signs up and comes back to the same link. The dashboard opens its create-key dialog with the label filled in (<clientId> — <date> unless the link gave one), and shows the key once for the user to paste into the program.
The dialog calls POST /api/py/v1/apikeys, which a signed-in session may call directly; the body is optional. An account at its key limit is refused with 400 and asked to revoke a key first.
The device grant, for a program with no browser
The OAuth 2.0 device authorization grant (RFC 8628) gets a key to a program (a plugin, a CLI, a local MCP server) without the user pasting anything. The program asks for a code, shows the user the code and https://rftools.io/device/, and polls. The user signs in there, sees the name the program gave for itself, and approves or denies. On approval the program's next poll returns the key, once. Both endpoints take JSON or a form body.
- A code is 8 letters from
BCDFGHJKLMNPQRSTVWXZ, shown asXXXX-XXXX, and expires 10 minutes after it is issued. - Poll no faster than
interval(5 s to start with). - The key counts toward the account's key limit; an account at its limit is asked to revoke a key first.
- Show the user the code only. The
device_codeis the program's secret until it is exchanged. - The Python library does all of this:
rftools login, orrftools.Client().login().
While waiting, the token endpoint answers 400 with an RFC 8628 error:
| error | What it means |
|---|---|
| authorization_pending | The user has not decided yet. Keep polling at the interval. |
| slow_down | Polled faster than the interval. The interval grows by 5 s; the body carries the new interval. |
| access_denied | The user denied the code, or the account reached its key limit before the key was collected. Stop polling. |
| expired_token | The code expired (10 minutes after it was issued) or its key was already collected. Start again. |
| invalid_grant | The device code was issued to another client_id. |
| invalid_request / unsupported_grant_type | A parameter is missing or the grant_type is wrong. |
The device-grant endpoints are held to the no-credential rate limit, whatever they carry.