API keys and account
Keys, sign-in and support.
Create a key
- Open API Keys in the dashboard.
- Name it after where it's used, such as
litellmorstaging(1–40 characters). - Select Create API key and copy it. It is shown once.
You can have 10 keys. All of them share your account's credits, prices, models and limits; more keys don't add capacity. Keep them out of source control and out of browsers. You can create keys before you buy credits, but requests need credits.
Track use
API Keys shows each key's status and when it was last used. Usage lists recent requests with the key name, model, tokens, time to first token and cost. Spend totals are for the whole account.
Replace or revoke a key
Keys can be revoked, not renamed or rotated. Revoke stops the key at once. To swap a key without downtime: create a new one, update every connection, check it works, then revoke the old one. If a key leaks, revoke it immediately.
Wallet accounts
An account can be created by paying instead of signing up: POST https://caft.dev/api/x402/register?amount_usd=5 charges $5–$500 of USDC on Base through x402 and creates the account. The wallet is the account's identity. Get a quote first — the same POST without a payment header returns the payment details and charges nothing.
import { x402Client } from "@x402/core/client";
import { registerExactEvmScheme } from "@x402/evm/exact/client";
import { wrapFetchWithPayment } from "@x402/fetch";
import { privateKeyToAccount } from "viem/accounts";
// The account signs the USDC authorization; it needs no ETH.
const account = privateKeyToAccount(process.env.WALLET_PRIVATE_KEY as `0x${string}`);
const client = x402Client.fromConfig({
schemes: [],
spendControls: { maxAmountPerPayment: "$5" },
});
registerExactEvmScheme(client, { signer: account });
// No Authorization header: the payment itself opens the account.
// Send the request once — do not retry a paid request.
const res = await wrapFetchWithPayment(fetch, client)(
"https://caft.dev/api/x402/register?amount_usd=5",
{ method: "POST" },
);
const body = await res.json(); // 201: { api_key, api_key_id, ... }Store api_key at once; it is shown once. If the register response was lost (status 202 provisioning), create a key through /api/wallet/keys below — it lands on the same account.
| Status | Outcome |
|---|---|
| 201 | Account created. The body carries api_key; store it at once, it is shown once. |
| 200 | The wallet already had an account; the payment was credited to it as a top-up (wallet_registered_credited). |
| 202 | The account is being set up (provisioning). Get a key with POST /api/wallet/keys, action create. |
| 409 | This wallet already has an account (wallet_registered). Nothing was charged; get a key with POST /api/wallet/keys, add credit with POST /api/x402/topup. |
Key management without a dashboard: POST https://caft.dev/api/wallet/keys with a signed SIWE message. The message must bind caft.dev, be signed by the registered wallet, carry a fresh nonce, and carry the statement that names the action exactly — caft wallet keys: create, caft wallet keys: list, or caft wallet keys: revoke <id>. Each message works once.
import { createSiweMessage } from "viem/siwe";
const message = createSiweMessage({
address: account.address,
domain: "caft.dev",
uri: "https://caft.dev",
chainId: 8453,
version: "1",
nonce: crypto.randomUUID().replaceAll("-", ""),
statement: "caft wallet keys: create", // or "caft wallet keys: list", or `caft wallet keys: revoke ${id}`
issuedAt: new Date(),
expirationTime: new Date(Date.now() + 5 * 60_000),
});
const signature = await account.signMessage({ message });
// then POST { message, signature, action } as JSON, once per messageaction: "create", optionalname(1–40 characters) → 201{ api_key, api_key_id, name }. Up to 10 keys per account.action: "list"→ 200 with masked keys.action: "revoke",id→ 200{ revoked: id }.
Wallet accounts have no email and no dashboard login. If you lose the wallet, the account cannot be recovered. Error codes are on Wallet account errors.
Sign-in
- Email and password (10 characters or more). Reset links last an hour and work once.
- Passkeys: add or remove them in Account.
- Google or GitHub, where shown on the sign-in page.
Changing your password signs out your other sessions.
Teams
Accounts are single-user; there are no organizations yet. A team can share one account's keys, with one key per person or app so each can be revoked alone.
Support
Email support@caft.dev with the time, the model and the first few characters of the key. Never send a whole key.