Skip to content
Getting started

Quickstart

View as Markdown Updated

Run your first generation in a few minutes. All 1,496 models take the same kind of request and return the same request object, for images, video and audio: learn it once here.

1. Get an API key

Create a key at https://doitong.com/developers/dashboard#keys and keep it in an environment variable: it is shown only once. Each key can carry its own budget, so you can hand one to an agent without risking the whole account. GET /account returns your API balance.

export DOITONG_API_KEY="doitong_..."

curl "https://api.doitong.com/v1/account" \
  -H "Authorization: Bearer $DOITONG_API_KEY"

Runs are paid from your account's API balance in API credits: 1,000 API credits = $1, and every model costs exactly its maker's price. Top up at https://doitong.com/developers/dashboard#balance.

2. Quote, then run

POST /quote/{model_id} takes the input JSON and returns the exact price. It needs no key and costs nothing. Running the same input costs exactly that: the quote is the charge. (A model charged by usage is the exception: its quote is the most the run can cost, and the unused part is refunded after the run.)

curl -X POST "https://api.doitong.com/v1/quote/kling-video/v3/pro/image-to-video" \
  -H "Content-Type: application/json" \
  -d '{"image": "https://example.com/fox.jpg", "duration": 5, "generate_audio": true}'
200 OK · quote
{
  "object": "quote",
  "model": "kling-video/v3/pro/image-to-video",
  "credits": 840,
  "usd": "0.84",
  "unit": "second",
  "quantity": 5,
  "unit_credits": 168,
  "mode": "exact",
  "breakdown": "5 s × 168 API credits"
}

Then send the same body to POST /run/{model_id}. Add ?wait=20 to hold the connection for up to 20 seconds: a fast model returns the finished result in one round trip. Send an Idempotency-Key header so that a retry never runs (or charges) twice.

curl -X POST "https://api.doitong.com/v1/run/flux/schnell?wait=20" \
  -H "Authorization: Bearer $DOITONG_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: lighthouse-001" \
  -d '{"prompt": "A lighthouse on a rocky coast at dusk, warm light in the window"}'

The response is a request object:

200 OK · request
{
  "id": "req_8k2m4q7x1z9c3v5b6n0p2r4t",
  "object": "request",
  "model": "flux/schnell",
  "status": "succeeded",
  "cost": { "credits": 3, "usd": "0.003", "charged": 3, "refunded": 0 },
  "outputs": [
    { "type": "image", "url": "https://content.doitong.com/dev-api/2026/10/20/req_8k2m4q7x1z9c3v5b6n0p2r4t/0-output.jpeg",
      "content_type": "image/jpeg", "width": 1024, "height": 768, "stored": true }
  ],
  "error": null
}

3. Follow the status

If the model is still working when the wait ends, you get 202 Accepted with the request's id and its current status. Every request moves through the same lifecycle:

Request lifecycle
  1. queued Accepted and charged, waiting for a worker
  2. running The model is generating
  3. Final statuses:
    • succeededCharged the quote; outputs[] hold URLs on our storage
    • failedRefunded automatically; error says why
    • canceledStopped before a result; refunded

Read the request again with its id. ?wait=20 works here too, so a simple loop is enough:

curl "https://api.doitong.com/v1/requests/req_8k2m4q7x1z9c3v5b6n0p2r4t?wait=20" \
  -H "Authorization: Bearer $DOITONG_API_KEY"

When status is succeeded, outputs[].url holds links to the files on our storage. If the request failed or was canceled, its API credits are refunded automatically and error says why. Cancel anything still queued or running:

terminal
curl -X POST "https://api.doitong.com/v1/requests/req_8k2m4q7x1z9c3v5b6n0p2r4t/cancel" \
  -H "Authorization: Bearer $DOITONG_API_KEY"

For long video jobs you can skip polling and pass a webhook_url instead (see Webhooks).

4. Files

Pass any public URL as an input, or ask POST /files for an upload URL, PUT the file there and use the returned file_url (see Files). A succeeded request lists its results in outputs[] with type, content type and, when known, dimensions and duration.

terminal
curl -X POST "https://api.doitong.com/v1/files" \
  -H "Authorization: Bearer $DOITONG_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"filename": "fox.jpg", "content_type": "image/jpeg", "size": 482113}'

Errors

Every model fails the same way: one envelope with a type, an exact code, the offending param and every problem in details, so an agent can fix the request without reading prose. Nothing is charged for an invalid request.

422 Unprocessable Entity
{
  "error": {
    "type": "invalid_request",
    "code": "invalid_input",
    "message": "duration must be one of 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15.",
    "param": "duration",
    "details": [ { "param": "duration", "message": "duration must be one of 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15." } ],
    "request_id": null,
    "doc_url": "https://doitong.com/developers/docs/errors#invalid_input"
  }
}

Every type and code is listed in Errors.

Pricing

Prices are in USD and API credits and shown on every model page before you run. Each request carries cost with credits, usd, charged and refunded. A run is charged when it is accepted; failed and canceled requests are refunded automatically. Some models are priced exactly from the input, some by the length or size of the files you send, others charge an estimated price per run: either way the quote is what you pay. A few models (language and vision models, voice, processing-time tools) are charged by usage: the quote is the most the run can cost, and the part the run did not use is refunded automatically. See Pricing.

MCP and AI agents

Connect any MCP client to https://api.doitong.com/v1/mcp with the same Bearer key. Your agent can search the catalog, quote and run models, and read every docs page as Markdown.

Claude Code
claude mcp add --transport http doitong-models https://api.doitong.com/v1/mcp \
  --header "Authorization: Bearer YOUR_API_KEY"

Next steps