{"openapi":"3.1.0","info":{"title":"Tovano API","version":"1.0.0","summary":"One API, one balance and one invoice for image, video, audio and text models.","description":"All amounts are integer micro-dollars (`1 USD = 1_000_000`), in fields ending in `_micro`. Every call is charged per unit at the model's public price. A failed task is never charged. Long-running models run as tasks: create one, then poll it or receive a signed webhook. Text models also speak the OpenAI chat completions format, including streaming.","contact":{"name":"Tovano","url":"https://tovano.ai","email":"hello@tovano.ai"}},"servers":[{"url":"https://tovano.ai"}],"security":[{"bearerAuth":[]}],"tags":[{"name":"Models"},{"name":"Tasks"},{"name":"Chat"},{"name":"Billing"}],"paths":{"/v1/models":{"get":{"tags":["Models"],"operationId":"listModels","summary":"List models with type, unit and price","responses":{"200":{"description":"Models you can call.","content":{"application/json":{"schema":{"type":"object","properties":{"object":{"const":"list"},"data":{"type":"array","items":{"$ref":"#/components/schemas/Model"}}}}}}},"401":{"description":"Missing, invalid or revoked API key (`invalid_api_key`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit reached (`rate_limited`). Wait for the `Retry-After` seconds.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}}}}}}},"/v1/models/{id}":{"get":{"tags":["Models"],"operationId":"getModel","summary":"One model, with its input schema","parameters":[{"name":"id","in":"path","required":true,"description":"Model id. The slash may be sent as is (`/v1/models/image/demo-1`) or encoded.","schema":{"type":"string","enum":["image/demo-1","video/demo-1","audio/demo-tts-1","text/demo-chat-1","agent/ad-kit-1"]}}],"responses":{"200":{"description":"The model.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Model"}}}},"401":{"description":"Missing, invalid or revoked API key (`invalid_api_key`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown model.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit reached (`rate_limited`). Wait for the `Retry-After` seconds.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}}}}}}},"/v1/tasks":{"post":{"tags":["Tasks"],"operationId":"createTask","summary":"Run a model","description":"Creates a task and reserves its estimated cost. The real amount is charged when it completes; a failed task is not charged.","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"},{"$ref":"#/components/parameters/Customer"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["model","input"],"properties":{"model":{"type":"string","enum":["image/demo-1","video/demo-1","audio/demo-tts-1","text/demo-chat-1","agent/ad-kit-1"]},"input":{"type":"object","description":"Model input. See the model's `input_schema`."},"customer":{"type":"string","maxLength":128,"description":"Your own end-customer id, for usage per customer."},"webhook_url":{"type":"string","format":"uri","description":"Receives the task object when it finishes."}}},"examples":{"image":{"value":{"model":"image/demo-1","input":{"prompt":"Product photo of a blue ceramic mug","n":2},"customer":"client-0482"}},"agent":{"value":{"model":"agent/ad-kit-1","input":{"product":"A reusable water bottle","tone":"playful"}}}}}}},"responses":{"201":{"description":"The task, usually `queued`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Task"}}}},"401":{"description":"Missing, invalid or revoked API key (`invalid_api_key`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Not enough credits (`insufficient_credits`) or monthly spend limit reached (`spend_limit_reached`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown model.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Idempotency-Key reused with a different request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid input (`invalid_request`). `param` names the field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit reached (`rate_limited`). Wait for the `Retry-After` seconds.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}}}}}},"get":{"tags":["Tasks"],"operationId":"listTasks","summary":"List tasks, newest first","parameters":[{"name":"status","in":"query","schema":{"type":"string","enum":["queued","running","completed","failed"]}},{"name":"model","in":"query","schema":{"type":"string"}},{"name":"customer","in":"query","schema":{"type":"string"}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"name":"cursor","in":"query","schema":{"type":"string"},"description":"`next_cursor` from the previous page."}],"responses":{"200":{"description":"A page of tasks.","content":{"application/json":{"schema":{"type":"object","properties":{"object":{"const":"list"},"data":{"type":"array","items":{"$ref":"#/components/schemas/Task"}},"next_cursor":{"type":["string","null"]}}}}}},"401":{"description":"Missing, invalid or revoked API key (`invalid_api_key`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit reached (`rate_limited`). Wait for the `Retry-After` seconds.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}}}}}}},"/v1/tasks/{id}":{"get":{"tags":["Tasks"],"operationId":"getTask","summary":"Task status, output, units and charge","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The task.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Task"}}}},"401":{"description":"Missing, invalid or revoked API key (`invalid_api_key`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown task.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit reached (`rate_limited`). Wait for the `Retry-After` seconds.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}}}}}}},"/v1/chat/completions":{"post":{"tags":["Chat"],"operationId":"createChatCompletion","summary":"Chat with a text model (OpenAI-compatible)","description":"Same request and response as OpenAI's chat completions, including `stream: true` (server-sent events ending with `data: [DONE]`). Charged by input and output tokens. Point any OpenAI client at `https://tovano.ai/v1` with your Tovano key.","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"},{"$ref":"#/components/parameters/Customer"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["model","messages"],"properties":{"model":{"type":"string","enum":["text/demo-chat-1"]},"messages":{"type":"array","items":{"type":"object","required":["role","content"],"properties":{"role":{"type":"string","enum":["system","user","assistant"]},"content":{"type":"string"}}}},"max_tokens":{"type":"integer","minimum":1,"maximum":8192,"default":1024},"temperature":{"type":"number","minimum":0,"maximum":2},"stream":{"type":"boolean","default":false},"stream_options":{"type":"object","properties":{"include_usage":{"type":"boolean"}}},"customer":{"type":"string"}}},"example":{"model":"text/demo-chat-1","messages":[{"role":"user","content":"Write a tagline for a coffee shop."}]}}}},"responses":{"200":{"description":"A chat completion, or an event stream when `stream` is true. The `X-Tovano-Task-Id` header names the task.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"object":{"const":"chat.completion"},"created":{"type":"integer"},"model":{"type":"string"},"choices":{"type":"array","items":{"type":"object","properties":{"index":{"type":"integer"},"message":{"type":"object","properties":{"role":{"const":"assistant"},"content":{"type":"string"}}},"finish_reason":{"type":"string","enum":["stop","length"]}}}},"usage":{"type":"object","properties":{"prompt_tokens":{"type":"integer"},"completion_tokens":{"type":"integer"},"total_tokens":{"type":"integer"}}}}}},"text/event-stream":{"schema":{"type":"string"}}}},"401":{"description":"Missing, invalid or revoked API key (`invalid_api_key`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Not enough credits.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit reached (`rate_limited`). Wait for the `Retry-After` seconds.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}}}},"502":{"description":"The model provider failed (`provider_error`). You were not charged.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/balance":{"get":{"tags":["Billing"],"operationId":"getBalance","summary":"Current balance","responses":{"200":{"description":"Balance in micro-dollars.","content":{"application/json":{"schema":{"type":"object","properties":{"object":{"const":"balance"},"balance_micro":{"type":"integer"},"reserved_micro":{"type":"integer","description":"Held by running tasks."},"available_micro":{"type":"integer"},"spent_this_month_micro":{"type":"integer"},"spend_limit_micro":{"type":["integer","null"]},"currency":{"const":"usd"}}}}}},"401":{"description":"Missing, invalid or revoked API key (`invalid_api_key`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit reached (`rate_limited`). Wait for the `Retry-After` seconds.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}}}}}}},"/v1/usage":{"get":{"tags":["Billing"],"operationId":"getUsage","summary":"Usage and spend, grouped","parameters":[{"name":"group_by","in":"query","schema":{"type":"string","enum":["model","customer","day","project","key"],"default":"model"}},{"name":"from","in":"query","schema":{"type":"string","format":"date"},"description":"Default: start of this month (UTC)."},{"name":"to","in":"query","schema":{"type":"string","format":"date"},"description":"Inclusive. Default: now."},{"name":"customer","in":"query","schema":{"type":"string"}},{"name":"model","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Usage rows.","content":{"application/json":{"schema":{"type":"object","properties":{"group_by":{"type":"string"},"from":{"type":"string"},"to":{"type":"string"},"total_micro":{"type":"integer"},"total_tasks":{"type":"integer"},"data":{"type":"array","items":{"type":"object","properties":{"key":{"type":["string","null"]},"tasks":{"type":"integer"},"units":{"type":"number"},"charged_micro":{"type":"integer"},"input_tokens":{"type":"integer"},"output_tokens":{"type":"integer"}}}}}}}}},"401":{"description":"Missing, invalid or revoked API key (`invalid_api_key`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit reached (`rate_limited`). Wait for the `Retry-After` seconds.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}}}}}}}},"webhooks":{"taskFinished":{"post":{"summary":"A task completed or failed","description":"POSTed to the task's `webhook_url`. Header `Tovano-Signature: t=<unix>,v1=<hex HMAC-SHA256 of \"t.body\" with the project's webhook secret>`. Reply with any 2xx. Failed deliveries are retried three times (after 10 s, 1 min and 5 min).","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Task"}}}},"responses":{"200":{"description":"Received."}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"API key: `tvn_live_...`"}},"parameters":{"IdempotencyKey":{"name":"Idempotency-Key","in":"header","schema":{"type":"string","maxLength":255},"description":"Retry safely: the same key and body return the first response for 24 hours."},"Customer":{"name":"X-Tovano-Customer","in":"header","schema":{"type":"string","maxLength":128},"description":"Your end-customer id. Same as the `customer` body field."}},"schemas":{"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["type","code","message"],"properties":{"type":{"type":"string","examples":["billing_error"]},"code":{"type":"string","enum":["invalid_api_key","insufficient_credits","spend_limit_reached","not_found","invalid_request","conflict","rate_limited","internal_error","provider_error"]},"message":{"type":"string"},"param":{"type":"string"}}}}},"Task":{"type":"object","properties":{"id":{"type":"string","examples":["tsk_9f2cA1b2C3d4E5f6G7h8"]},"object":{"const":"task"},"model":{"type":"string","examples":["image/demo-1"]},"status":{"type":"string","enum":["queued","running","completed","failed"]},"customer":{"type":["string","null"],"examples":["client-0482"]},"project_id":{"type":"string"},"parent_id":{"type":["string","null"],"description":"Set on the steps of an agent job."},"step":{"type":["string","null"],"description":"Agent step name, for example `copy` or `image`."},"input":{"type":"object"},"output":{"type":["object","null"],"description":"Model output. Files appear as objects with a signed `url` (valid for at least 7 days), `file_id`, `content_type` and `size`.","examples":[{"images":[{"url":"https://tovano.ai/files/fil_...","content_type":"image/png","width":512,"height":512}]}]},"unit":{"type":"string","enum":["image","second","minute","1k_chars","1m_input_tokens","run"]},"units":{"type":"number","description":"Billed quantity in `unit`s, for example 4 images or 0.000412 (× 1M tokens)."},"usage":{"type":"object","description":"Text models: token counts.","properties":{"input_tokens":{"type":"integer"},"output_tokens":{"type":"integer"}}},"estimate_micro":{"type":"integer","description":"The most this task could cost; reserved when it started."},"charged_micro":{"type":"integer","description":"What was charged, in micro-dollars. Always 0 for a failed task."},"error":{"type":["object","null"],"properties":{"code":{"type":"string"},"message":{"type":"string"}}},"steps":{"type":"array","items":{"$ref":"#/components/schemas/Task"},"description":"Agent jobs only."},"created_at":{"type":"string","format":"date-time"},"started_at":{"type":["string","null"],"format":"date-time"},"completed_at":{"type":["string","null"],"format":"date-time"}}},"Model":{"type":"object","properties":{"id":{"type":"string","examples":["image/demo-1"]},"object":{"const":"model"},"type":{"type":"string","enum":["image","video","audio","text","agent"]},"name":{"type":"string"},"description":{"type":"string"},"unit":{"type":"string"},"price_micro":{"type":"integer","description":"Price per unit in micro-dollars (1 USD = 1,000,000)."},"output_unit":{"type":"string","description":"Text models: `1m_output_tokens`."},"output_price_micro":{"type":"integer"},"available":{"type":"boolean"},"input_schema":{"type":"object","description":"JSON Schema for `input` (single-model endpoint only)."}}}}}}