Auth & billing
One credential model, one monthly pool. Everything authenticates with an API key, and metered transforms draw from your plan's credits.
Getting a key
There are three ways to get a key, and they all authenticate identically:
- Dashboard — create and revoke keys at Credentials. The raw key is shown once.
- CLI —
tk loginmints a key through a browser approval flow. - OAuth — MCP and other OAuth clients receive a minted token.
Authenticating
Keys are prefixed tk_. Send one as a bearer token on every request.
Authorization: Bearer tk_your_key_hereconst tk = new TransformKit({ apiKey: process.env.API_KEY! });Keys are secrets
A TransformKit key grants full account access and spends your quota — treat it like a database password or a Stripe secret key, not a public token. Keep it server-side in an environment variable. If it ever leaks, revoke it under Credentials and issue a new one. To transform from a browser, post the file to an endpoint of yours that runs the SDK — see Next.js.Credits & quota
Your plan includes a pool of monthly credits. A successful transform costs one credit; failed jobs are refunded. A pipeline costs one credit per output, so a two-output pipeline is two credits. All of your keys share the same monthly pool — it's billed per account, not per key.
What counts:
- Metered:
POST /v1/pipelines— one credit per output (a three-output fan-out over ten files spends thirty credits). - Free: uploads, job polling, results,
/v1/me,/health, and key management.
Error contract
When you run out of credits or hit the burst limit, the API responds with a machine-readable code:
402 plan_required— no active plan with credits.402 quota_exceeded— monthly credits exhausted. Upgrade your plan to continue.429 rate_limited— too many requests in a short window (a burst limit, separate from monthly credits). Back off and retry.
Through the SDK, these surface per file: runQueue and runPipeline return ok: false with the reason in error rather than throwing, so one exhausted call never fails the rest of the batch. (A malformed pipeline is the exception — it throws a TransformKitError before anything uploads.)
const results = await tk.runQueue(files, 'image').convert({ format: 'webp' });
for (const r of results) {
if (!r.ok) console.error(r.filename, r.error); // e.g. "This request needs 1 credit(s)…"
}Data retention
Inputs and outputs are removed from storage about 24 hours after a job is created, and result URLs expire with them. TransformKit transforms media; it doesn't store it long-term. Copy anything you need to keep to your own storage while the signed URL is valid.
Next steps
- Quickstart — get a key and run your first transform.
- HTTP & curl — the raw endpoints and status codes.