> ## Documentation Index
> Fetch the complete documentation index at: https://docs.zerogen.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Test keys

> Rehearse requests, failures, refusals, and delays on placeholder media at no charge.

A test key, which starts with `zg_test_`, accepts exactly the requests that a
live key accepts. Validation and quotes are real: ZeroGen checks each request
against the real model's schema and prices it at your organization's rates.
Only the work differs:

* Generations run on ZeroGen's Echo provider, which returns placeholder media
  in the requested format, count, size, and duration. The placeholder
  rehearses the shape of a live output, not its content.
* Nothing reaches a model provider, and nothing is charged.
* A generation holds nothing from your balance or spend limits, so its quote is
  for information only.

Create a test key in ZeroGen under **Settings → API keys**.

## The API sandbox

Test keys work only inside your organization's **API sandbox** project, which
ZeroGen creates the first time a test key needs it. `GET /v1/me` returns its ID
as `sandbox.projectId`.

* Every generation and upload from a test key lands in the sandbox, and a
  `projectId` for any other project returns `404 not_found`.
* A test key can't read, list, or cancel anything outside the sandbox.
* ZeroGen deletes what test keys make or upload in the sandbox after 7 days.

## Billing on test generations

A test generation reports `billing.mode` as `test`, with `state` and every
amount `null`:

```json theme={null}
{
  "mode": "test",
  "state": null,
  "quotedMicroUsd": null,
  "heldMicroUsd": null,
  "chargedMicroUsd": null
}
```

A test key's quote reports `billing.mode` as `test` and the real
`quotedMicroUsd` that a live create would hold.

## Rehearse outcomes

Add a `test` object to a create to rehearse what a live request can meet.
ZeroGen never reads directives from the prompt; only the `test` object controls
the outcome.

```bash theme={null}
curl https://api.zerogen.com/v1/generations \
  -H "Authorization: Bearer $ZEROGEN_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 4b3a2f1e-0d9c-4b8a-8f7e-6d5c4b3a2f1e" \
  -d '{
    "model": "openai/gpt-image-2/generate",
    "prompt": "A lighthouse at dawn",
    "output": { "count": 2 },
    "test": {
      "outputs": ["succeeded", "content_moderation"],
      "delaySeconds": 10
    }
  }'
```

This generation ends after about 10 seconds as `partial`: the first output
succeeds, and the second fails with the `content_moderation` error a live
output would return.

| Field | Description |
| - | - |
| `outputs` | Each output's outcome, in order, as a list of 1 to 4 values: `succeeded`, or one of the error codes a live output can end with: `provider_error`, `provider_timeout`, `content_moderation`, or `input_rejected`. Outputs you leave out succeed. Each failure returns the same error envelope, `message` and `retryable` included, as the live failure. |
| `reject` | Refuse the create with a live refusal and start nothing: `insufficient_balance` (`402`), `rate_limited` (`429` with `Retry-After`), or `model_unavailable` (`400`). A quote ignores `reject`. |
| `delaySeconds` | Seconds, from 0 to 60, before each output ends. Use it to rehearse polling and `Prefer: wait`. |

Only test keys accept `test`. A live key's request with a `test` object fails
with `400 validation_failed`, and `param` is `test`.

## Limits on test keys

Test keys have their own limits, so test traffic never delays live work:

* Test keys count against a separate per-user request window. For details,
  see [Rate limits](https://docs.zerogen.com/rate-limits.md).
* Each organization's test keys can have 4 generations queued or running at
  once.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.