API

Sandbox

Build and test your integration for free with test keys; runs are simulated and nothing is charged.

The sandbox is a separate copy of the API for building and testing. It takes the same requests, validates them the same way and answers with the same response shapes, but it never runs a model and never spends credits.

LiveSandbox
Base URLhttps://api-live.aitopia.aihttps://api-sandbox.aitopia.ai
Keyaitk_live_...aitk_test_...
RunsReal models, real filesSimulated, sample files
CreditsChargedNever charged
Input validation and price estimateYesYes, the same

#Test keys

Create a test key under profile menu > API keys on aitopia.ai, next to your live keys. Test keys count toward the same limit of 10 active keys, have their own webhook secret and can be revoked the same way.

A key works only on its own server. A test key sent to the live server, or a live key sent to the sandbox, is refused, so a test setup can never spend credits by accident:

JSON
{
  "error": {
    "code": "KEY_ENVIRONMENT_MISMATCH",
    "message": "This is a sandbox (test) key. Send it to https://api-sandbox.aitopia.ai, or use a live key here.",
    "retryable": false
  }
}

Switching an integration from sandbox to live means changing two values: the base URL and the key.

Shell
export AITOPIA_BASE="https://api-sandbox.aitopia.ai"
export AITOPIA_KEY="aitk_test_..."

#What is real and what is simulated

The same as live:

  • GET /v1/models and GET /v1/models/{model_id}: the real catalogue, input schemas and prices.
  • Validation: a request the live API would refuse (unknown model, missing or invalid field) is refused in the sandbox with the same error.
  • ?dry_run=true: the real price estimate. credits_available is the sandbox balance.
  • File uploads (POST /v1/uploads, POST /v1/uploads/link): real and free, so you can test your upload code end to end.
  • Rate limits, webhook signatures and retries, ?wait, cancel, error format.

Simulated:

  • Submits (POST /v1/models/{model_id}, POST /v1/edit, POST /v1/batch) answer 202 with a request_id as usual, but no model runs. The request is queued for about a second, then running, then finishes after a few seconds (images about 4 s, audio about 5 s, video about 8 s).
  • A completed request returns a sample file of the right kind: an image, a video or an audio clip. credits_estimated holds the real estimate; nothing is charged.
  • POST /v1/edit is not planned in the sandbox (no plan_token is needed or produced) and finishes like a run.
  • GET /v1/account/balance returns a fixed play balance of 10000 credits with "sandbox": true.

Sandbox requests and live requests are kept apart: a test key cannot read or cancel a live request, and a live key cannot see a sandbox one.

#Testing failures

Send X-Sandbox-Outcome on a sandbox submit to choose how the simulated run ends:

ValueResult
completed (default)The request completes with a sample file.
failedThe request fails with UPSTREAM_RUN_FAILED and retryable: true, as a provider failure would.
partialFor POST /v1/batch: the first item fails, the others complete, and the request ends partial. A single run fails.

The header is ignored on the live server.

curl
curl -X POST "https://api-sandbox.aitopia.ai/v1/models/google/nano-banana-2?wait=10" \
  -H "Authorization: Key $AITOPIA_KEY" \
  -H "Content-Type: application/json" \
  -H "X-Sandbox-Outcome: failed" \
  -d '{"prompt": "a red bicycle"}'
Node.js
const res = await fetch("https://api-sandbox.aitopia.ai/v1/models/google/nano-banana-2?wait=10", {
  method: "POST",
  headers: {
    Authorization: `Key ${process.env.AITOPIA_KEY}`,
    "Content-Type": "application/json",
    "X-Sandbox-Outcome": "failed",
  },
  body: JSON.stringify({ prompt: "a red bicycle" }),
});
const request = await res.json();
console.log(request.status, request.error);
Python
import os, requests

r = requests.post(
    "https://api-sandbox.aitopia.ai/v1/models/google/nano-banana-2",
    params={"wait": 10},
    headers={
        "Authorization": f"Key {os.environ['AITOPIA_KEY']}",
        "X-Sandbox-Outcome": "failed",
    },
    json={"prompt": "a red bicycle"},
)
print(r.json()["status"], r.json().get("error"))

#Webhooks in the sandbox

A sandbox submit with webhook_url gets its webhook like a live one: signed with the test key's webhook secret, retried on failure, with sandbox URLs in status_url, result_url and cancel_url. Use it to test your receiver and signature check before going live.

#Going live

  1. Create a live key under profile menu > API keys.
  2. Replace the base URL with https://api-live.aitopia.ai and the key with the live key.
  3. Make sure the account has credits (Billing & retention).

Nothing else changes: request and response shapes are the same.

AITOPIA REST API · Live https://api-live.aitopia.ai/v1 · Sandbox https://api-sandbox.aitopia.ai/v1