Skip to content
dhanu docs
Browse pages

Guides

Go from test to live

Build against a test key that spends nothing, then switch to a live key, what changes, what does not, and the checklist before you flip.

A key’s mode is baked into its prefix, dhanu_sk_test_… or dhanu_sk_live_…, and chosen when it is created. A test key goes through authentication, scope, validation, rate limits and idempotency exactly like a live one, then answers with fixtures instead of running a model or starting a task, and never spends a credit. Everything that works against a test key works against a live one.

What a test key returns

CallTest mode
images.generateA 1×1 PNG, same bytes every time
text.generate / text.streamA short reply that names itself as a fixture
tasks.trigger / tasks.createA task_test_… task that is created nowhere
tasks.messagesA two-message transcript for that task
embeddings.createDeterministic 8-dimensional vectors
transcriptions.createA fixture transcript
ocr.extractAn already-succeeded job
videos.generateA ready video with no bytes to download
workflows.runA fixture task

Reads that need real rows, listing staff, workflows, files, tasks, return the workspace’s real data with either key, since reading spends nothing.

The checklist

  1. Scope the live key as narrowly as the test key. Same packages or operations; the console shows what each key may call and me() confirms it from code.
  2. Set a monthly spend cap and an expiry on the live key. A cap turns a runaway loop into a key_spend_limit_reached error instead of a bill.
  3. Send idempotency keys on every POST that creates something. The SDKs add one automatically when they retry; pass your own (an order id, a ticket id) so a retry from your side is safe too.
  4. Handle insufficient_credits and rate_limited. A test key never returns them; a live key will, on the day the workspace runs dry or a burst hits the limit. Back off on Retry-After.
  5. Verify webhooks with the live endpoint’s secret: each endpoint has its own.
  6. Keep the test key for CI. Contract tests against fixtures catch a broken integration before it touches credits.

Flipping

Mint the live key, put it in the production environment as DHANU_API_KEY, deploy. Nothing in your code changes: the SDK reads the mode from the key, and me().key.mode tells you which one a process is holding.

const me = await dhanu.me();
if (me.key.mode !== "live") throw new Error("production is holding a test key");

Leaked keys are revoked for you: GitHub’s secret scanning reports a dhanu_sk_ that lands in a public repository, and the key is disabled and the workspace notified within minutes. Revoke a key yourself in the console or with dhanu keys revoke <id>.