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.
  • CLItk login mints 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_here
const 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.

Compare plans and manage your subscription on Pricing.

Next steps

  • Quickstart — get a key and run your first transform.
  • HTTP & curl — the raw endpoints and status codes.