Pedidos
Um pedido é uma chamada de um modelo. Tem um id (req_…), um estado, o seu custo em créditos de API (1000 = 1 USD) e, quando é concluído com sucesso, os ficheiros gerados. O mesmo objeto é devolvido por todos os endpoints abaixo, para todos os modelos.
Encontrar um modelo
O catálogo dos 1496 modelos é um JSON público (não é necessária uma chave):
curl "https://api.doitong.com/v1/models?category=text-to-video&lab=Google&limit=20"
| Parâmetro de consulta | Significado |
|---|---|
q |
Palavras que têm de aparecer todas no nome, id, fabricante ou etiquetas, por exemplo kling 3. |
category |
Um id de categoria, por exemplo text-to-video ou upscale. GET https://api.doitong.com/v1/categories lista as 21 categorias com as respetivas contagens. |
lab |
O fabricante do modelo, por nome ou id, por exemplo Google ou black-forest-labs. |
family |
Um id de family de uma linha anterior: todas as variantes de um modelo (pro, fast, image-to-video, …). |
mode |
exact (o preço é calculado a partir da entrada), measured (a partir da duração ou do tamanho dos ficheiros de entrada), estimate (um preço estimado por execução) ou metered (cobrado com base na utilização real, até a um máximo por execução). |
limit, cursor |
Tamanho da página (1 a 100, predefinição 50) e o next_cursor da página anterior. |
Cada linha tem id, name, lab, category, family, summary, tags, output_kind, docs_url e um objeto price (consulte Preços). GET https://api.doitong.com/v1/models/{model_id} acrescenta o JSON Schema completo da entrada e da saída, os nomes canónicos dos parâmetros, as regras de preço e um exemplo de entrada. Uma category ou mode desconhecida resulta em 400 invalid_parameter.
Executar um modelo
curl -X POST "https://api.doitong.com/v1/run/{model_id}?wait=20" \
-H "Authorization: Bearer $DOITONG_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-1842-cover" \
-d '{"prompt": "..."}'
- O corpo é a entrada do modelo, um objeto JSON. Cada página de modelo lista os seus parâmetros.
- A entrada é validada antes de qualquer cobrança. Uma entrada inválida devolve
422 invalid_inputcom oparamque causou o problema e não tem qualquer custo. ?wait=N(até 20 segundos) mantém a chamada aberta até o pedido terminar ou o tempo esgotar-se.?webhook_url=https://…envia um POST assinado para esse URL quando o pedido termina (consulte Webhooks).?storage=permanentou?storage=temporaryescolhe durante quanto tempo os ficheiros de saída são mantidos; sem este parâmetro, aplica-se a definição da conta (consulte Onde ficam os ficheiros).
A resposta é 202 Accepted enquanto o pedido ainda está a ser processado e 200 OK quando terminou dentro do período de espera (ou quando é uma repetição, conforme descrito abaixo). Os cabeçalhos Location e Doitong-Request-Id contêm o URL e o id do pedido.
Estados
-
queuedAceite e cobrado, à espera de um worker -
runningO modelo está a gerar -
Estados finais:
succeededO orçamento foi debitado; outputs[] contém URLs no nosso armazenamentofailedReembolsado automaticamente; o erro indica o motivocanceledParado antes de obter um resultado; reembolsado
| Estado | Significado | Final |
|---|---|---|
queued |
Aceite e cobrado, à espera de um worker. queue_position pode mostrar a posição na fila. |
não |
running |
O modelo está a gerar. | não |
succeeded |
Concluído. outputs lista os ficheiros. |
sim |
failed |
O modelo ou um limite interrompeu-o. error indica o motivo. Os créditos de API são reembolsados. |
sim |
canceled |
Cancelado antes de produzir um resultado. Os créditos de API são reembolsados. | sim |
Um pedido que exceda o seu limite de tempo falha com o código timeout e é reembolsado: 15 minutos para imagens, 60 minutos para vídeo, 30 minutos para áudio e tudo o resto.
O objeto do pedido
{
"id": "req_8k2m4q7x1z9c3v5b6n0p2r4t",
"object": "request",
"model": "flux/schnell",
"status": "succeeded",
"created_at": "2026-10-20T12:00:00Z",
"started_at": "2026-10-20T12:00:01Z",
"completed_at": "2026-10-20T12:00:02Z",
"queue_position": null,
"cost": { "credits": 3, "usd": "0.003", "charged": 3, "refunded": 0 },
"input": { "prompt": "..." },
"output": { "images": [ { "url": "https://content.doitong.com/dev-api/…/0-output.jpeg", "width": 1024, "height": 768 } ] },
"outputs": [
{ "type": "image", "url": "https://content.doitong.com/dev-api/…/0-output.jpeg", "content_type": "image/jpeg",
"width": 1024, "height": 768, "file_size": 183920, "stored": true }
],
"error": null,
"metrics": { "inference_seconds": 1.2 },
"storage": { "mode": "permanent", "bytes": 183920, "expires_at": null, "expired": false },
"urls": {
"self": "https://api.doitong.com/v1/requests/req_8k2m4q7x1z9c3v5b6n0p2r4t",
"cancel": "https://api.doitong.com/v1/requests/req_8k2m4q7x1z9c3v5b6n0p2r4t/cancel"
}
}
outputsé igual para todos os modelos: uma entrada por ficheiro gerado comtype(image,video,audio,fileou3d), umurlno nosso armazenamento,content_typee, quando conhecidos,file_size,width,height,duration.outputé o próprio objeto de resultado do modelo (os respetivos campos estão listados em cada página de modelo), com os mesmos URLs.storageindica como os ficheiros são mantidos:mode(permanentoutemporary),bytesarmazenados,expires_at(quando um ficheiro temporário é eliminado,nullpara os permanentes) eexpired(truequando os ficheiros já desapareceram).cost.creditsé o preço da chamada em créditos de API (cost.usdem USD),cost.chargedé o montante debitado do saldo de API ecost.refundedé o montante devolvido. Para um modelometered,cost.creditsé o máximo retido no início (cost.held); quando a execução é concluída com sucesso,cost.settledindica o custo efetivo da utilização e o restante do máximo está emcost.refunded(consulte Cobrado com base na utilização).- Quando um pedido falha,
erroré{ "type": …, "code": …, "message": … }.
Consultar um pedido
curl "https://api.doitong.com/v1/requests/req_8k2m4q7x1z9c3v5b6n0p2r4t?wait=20" \
-H "Authorization: Bearer $DOITONG_API_KEY"
?wait=N(até 20 segundos) faz long polling: a chamada devolve o resultado assim que o pedido chega a um estado final ou, após N segundos, o estado atual. Repetir esta chamada é a forma mais simples de aguardar um resultado.?logs=1acrescenta as linhas do registo de progresso do modelo (as últimas 50) comologs.
Só pode consultar pedidos da sua própria conta; qualquer outro id resulta em 404 request_not_found.
Listar pedidos
curl "https://api.doitong.com/v1/requests?limit=20&status=succeeded&model=flux/schnell" \
-H "Authorization: Bearer $DOITONG_API_KEY"
Do mais recente para o mais antigo. limit varia entre 1 e 100 (predefinição 20); status e model funcionam como filtros. A resposta é { "object": "list", "data": [ … ], "has_more": true, "next_cursor": "req_…" }; passe cursor=<next_cursor> para obter a página seguinte.
Cancelar um pedido
curl -X POST "https://api.doitong.com/v1/requests/req_8k2m4q7x1z9c3v5b6n0p2r4t/cancel" \
-H "Authorization: Bearer $DOITONG_API_KEY"
- Cancelado antes de o modelo começar: o estado passa a
canceled, os créditos de API são reembolsados e recebe200. - Já em geração: o cancelamento é encaminhado e recebe
202com"cancel_requested": true. Se o modelo terminar mesmo assim, o pedido é concluído normalmente e cobrado. - Já num estado final:
409 not_cancelable(um pedido que já estejacanceleddevolve simplesmente200).
Eliminar os ficheiros de um pedido
curl -X DELETE "https://api.doitong.com/v1/requests/req_8k2m4q7x1z9c3v5b6n0p2r4t/files" \
-H "Authorization: Bearer $DOITONG_API_KEY"
Elimina agora as nossas cópias dos ficheiros de saída do pedido e interrompe a cobrança do armazenamento. A resposta é o objeto do pedido com storage.expired: true; os URLs permanecem no registo, mas deixam de funcionar. Chamá-lo novamente não altera nada (200). Um pedido que ainda esteja queued ou running ainda não tem ficheiros: 409 request_active. Requer models:run.
Idempotência: repetir sem pagar duas vezes
As redes falham. Para repetir uma execução em segurança, envie um cabeçalho Idempotency-Key (qualquer sequência com até 255 caracteres, única por operação, por exemplo o seu próprio id de encomenda):
- A mesma chave e o mesmo corpo de antes: recebe o pedido original (
200, cabeçalhoIdempotent-Replayed: true) e não há nova cobrança. - A mesma chave e o mesmo corpo depois de uma execução que falhou antes de chegar ao modelo (
upstream_errorouinternal_errorno envio,insufficient_credits,budget_exceeded,too_many_inflight): nada foi produzido nem cobrado, por isso a repetição executa novamente o modelo em vez de devolver a falha. - A mesma chave com um corpo diferente:
409 idempotency_mismatch. - As chaves estão associadas à chave de API que as enviou.
Onde ficam os ficheiros
Cada ficheiro de saída é copiado para o nosso armazenamento antes de o pedido ser marcado como succeeded, pelo que os URLs em outputs apontam para os nossos próprios hosts e podem ser ligados diretamente. A duração da retenção é uma escolha sua:
| Modo | Duração | Preço |
|---|---|---|
permanent (predefinição) |
Até os eliminar | 100 créditos de API (0,10 $) por GB por mês, cobrados diariamente ao saldo de API |
temporary |
7 dias, depois são eliminados | Gratuito |
- A definição da conta aplica-se aos novos pedidos: o interruptor "Guardar ficheiros para sempre" no dashboard ou
PATCH https://api.doitong.com/v1/account/storagecom{"mode": "temporary"}.GET https://api.doitong.com/v1/accountmostra-a emstorage, juntamente com os bytes que mantém e a estimativa mensal. ?storage=permanent|temporarynuma execução (o argumentostorageda ferramentarundo MCP) substitui-a nessa execução.- Alterar a definição nunca afeta os ficheiros que já possui; elimine-os com
DELETE /requests/{id}/files. - Quando o saldo de API não consegue pagar o armazenamento, nada é cobrado e recebe um email: faça um carregamento no prazo de 30 dias ou os ficheiros mantidos passam a temporários e são eliminados 7 dias depois.
No caso raro de a nossa cópia falhar, a entrada tem "stored": false e o URL é o original, de curta duração: descarregue-o rapidamente.