Ir al contenido
Guía de la API

Solicitudes

Ver como Markdown Actualizado

Una solicitud es una llamada a un modelo. Tiene un id (req_…), un estado, su coste en créditos de API (1000 = 1 USD) y, cuando tiene éxito, los archivos generados. El mismo objeto se devuelve desde cada endpoint siguiente, para cada modelo.

Buscar un modelo

El catálogo de los 1496 modelos es JSON público (no se necesita ninguna clave):

terminal
curl "https://api.doitong.com/v1/models?category=text-to-video&lab=Google&limit=20"
Parámetro de consulta Significado
q Palabras que deben aparecer todas en el nombre, id, fabricante o etiquetas, por ejemplo kling 3.
category Un id de categoría, por ejemplo text-to-video o upscale. GET https://api.doitong.com/v1/categories enumera las 21 categorías con sus recuentos.
lab El fabricante del modelo, por nombre o id, por ejemplo Google o black-forest-labs.
family Un id de family de una fila anterior: cada variante de un modelo (pro, fast, image-to-video, …).
mode exact (el precio se calcula a partir de la entrada), measured (a partir de la longitud o el tamaño de los archivos de entrada), estimate (un precio estimado por ejecución) o metered (se cobra según el uso real, hasta un máximo por ejecución).
limit, cursor Tamaño de página (de 1 a 100, predeterminado 50) y el next_cursor de la página anterior.

Cada fila tiene id, name, lab, category, family, summary, tags, output_kind, docs_url y un objeto price (consulta Precios). GET https://api.doitong.com/v1/models/{model_id} añade el esquema JSON completo de entrada y salida, los nombres canónicos de los parámetros, las reglas de precios y un ejemplo de entrada. Una category o mode desconocida devuelve 400 invalid_parameter.

Ejecutar un modelo

terminal
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": "..."}'
  • El cuerpo es la entrada del modelo, un objeto JSON. Cada página de modelo enumera sus parámetros.
  • La entrada se valida antes de cobrar nada. Una entrada no válida devuelve 422 invalid_input con el param problemático y no cuesta nada.
  • ?wait=N (hasta 20 segundos) mantiene la llamada abierta hasta que termina la solicitud o se agota el tiempo.
  • ?webhook_url=https://… envía un POST firmado a esa URL cuando termina la solicitud (consulta Webhooks).
  • ?storage=permanent o ?storage=temporary elige durante cuánto tiempo se conservan los archivos de salida; si se omite, se aplica la configuración de la cuenta (consulta Dónde se almacenan los archivos).

La respuesta es 202 Accepted mientras la solicitud siga en curso y 200 OK cuando termina dentro del tiempo de espera (o cuando es una repetición, como se explica más abajo). Las cabeceras Location y Doitong-Request-Id contienen la URL y el id de la solicitud.

Estados

Ciclo de vida de la solicitud
  1. queued Aceptada y cobrada; esperando a un worker
  2. running El modelo está generando
  3. Estados finales:
    • succeededPresupuesto cobrado; outputs[] contiene URL en nuestro almacenamiento
    • failedReembolsada automáticamente; el error explica el motivo
    • canceledDetenida antes de obtener un resultado; reembolsada
Estado Significado Final
queued Aceptada y cobrada; espera a un trabajador. queue_position puede mostrar su posición en la cola. no
running El modelo está generando. no
succeeded Terminada. outputs enumera los archivos. sí
failed El modelo o un límite la ha detenido. error indica el motivo. Se reembolsan los créditos de API. sí
canceled Cancelada antes de producir un resultado. Se reembolsan los créditos de API. sí

Una solicitud que supera su límite de tiempo falla con el código timeout y se reembolsa: 15 minutos para imágenes, 60 minutos para vídeo, 30 minutos para audio y todo lo demás.

El objeto de solicitud

JSON
{
  "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 es igual para todos los modelos: una entrada por cada archivo generado con type (image, video, audio, file o 3d), una url en nuestro almacenamiento, content_type y, cuando se conocen, file_size, width, height, duration.
  • output es el objeto de resultado propio del modelo (sus campos aparecen en cada página de modelo), con las mismas URL.
  • storage indica cómo se conservan los archivos: mode (permanent o temporary), bytes almacenados, expires_at (cuándo se elimina un archivo temporal, null para los permanentes) y expired (true cuando los archivos ya no están disponibles).
  • cost.credits es el precio de la llamada en créditos de API (cost.usd en USD), cost.charged lo debitado del saldo de API y cost.refunded lo devuelto. En un modelo metered, cost.credits es el máximo retenido al principio (cost.held); cuando la ejecución tiene éxito, cost.settled indica cuánto ha supuesto el uso y el resto del máximo aparece en cost.refunded (consulta Cobro según el uso).
  • Cuando una solicitud falla, error es { "type": …, "code": …, "message": … }.

Leer una solicitud

terminal
curl "https://api.doitong.com/v1/requests/req_8k2m4q7x1z9c3v5b6n0p2r4t?wait=20" \
  -H "Authorization: Bearer $DOITONG_API_KEY"
  • ?wait=N (hasta 20 segundos) hace una espera larga: la llamada devuelve el resultado en cuanto la solicitud es final o, tras N segundos, el estado actual. Repetir esta llamada es la forma más sencilla de esperar un resultado.
  • ?logs=1 añade las líneas del registro de progreso del modelo (las 50 últimas) como logs.

Solo puedes leer solicitudes de tu propia cuenta; cualquier otro id devuelve 404 request_not_found.

Enumerar solicitudes

terminal
curl "https://api.doitong.com/v1/requests?limit=20&status=succeeded&model=flux/schnell" \
  -H "Authorization: Bearer $DOITONG_API_KEY"

De más recientes a más antiguas. limit va de 1 a 100 (predeterminado 20); status y model filtran los resultados. La respuesta es { "object": "list", "data": [ … ], "has_more": true, "next_cursor": "req_…" }; pasa cursor=<next_cursor> para obtener la página siguiente.

Cancelar una solicitud

terminal
curl -X POST "https://api.doitong.com/v1/requests/req_8k2m4q7x1z9c3v5b6n0p2r4t/cancel" \
  -H "Authorization: Bearer $DOITONG_API_KEY"
  • Cancelada antes de que se inicie el modelo: el estado pasa a canceled, se reembolsan los créditos de API y recibes 200.
  • Ya generándose: la cancelación se reenvía y recibes 202 con "cancel_requested": true. Si el modelo termina de todos modos, la solicitud tiene éxito con normalidad y se cobra.
  • Ya finalizada: 409 not_cancelable (una solicitud que ya está canceled simplemente devuelve 200).

Eliminar los archivos de una solicitud

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

Elimina ahora nuestras copias de los archivos de salida de la solicitud y detiene su cargo de almacenamiento. La respuesta es el objeto de solicitud con storage.expired: true; sus URL permanecen en el registro, pero dejan de funcionar. Volver a llamarlo no cambia nada (200). Una solicitud que sigue queued o running aún no tiene archivos: 409 request_active. Requiere models:run.

Idempotencia: reintentar sin pagar dos veces

Las redes fallan. Para reintentar una ejecución de forma segura, envía una cabecera Idempotency-Key (cualquier cadena de hasta 255 caracteres, única por operación, por ejemplo tu propio id de pedido):

  • Misma clave y mismo cuerpo que antes: recibes la solicitud original (200, cabecera Idempotent-Replayed: true) y no se vuelve a cobrar nada.
  • Misma clave y cuerpo después de una ejecución que falló antes de llegar al modelo (upstream_error o internal_error al enviar, insufficient_credits, budget_exceeded, too_many_inflight): no se produjo nada ni se cobró nada, por lo que el reintento vuelve a ejecutar el modelo en lugar de devolver el error.
  • Misma clave con un cuerpo diferente: 409 idempotency_mismatch.
  • Las claves están vinculadas a la clave de API que las envió.

Dónde se almacenan los archivos

Cada archivo de salida se copia en nuestro almacenamiento antes de marcar la solicitud como succeeded, por lo que las URL de outputs están en nuestros propios hosts y puedes enlazarlas directamente. Tú eliges cuánto tiempo permanecen:

Modo Duración Precio
permanent (predeterminado) Hasta que los elimines 100 créditos de API (0,10 $) por GB al mes, cobrados diariamente del saldo de API
temporary 7 días y después se eliminan Gratis
  • La configuración de la cuenta decide el comportamiento de las solicitudes nuevas: el interruptor «Conservar archivos para siempre» del panel de control, o PATCH https://api.doitong.com/v1/account/storage con {"mode": "temporary"}. GET https://api.doitong.com/v1/account lo muestra en storage, junto con los bytes que conservas y la estimación mensual.
  • ?storage=permanent|temporary en una ejecución (el argumento storage de la herramienta MCP run) lo sobrescribe para esa ejecución.
  • Cambiar la configuración nunca afecta a los archivos que ya tienes; elimínalos con DELETE /requests/{id}/files.
  • Cuando el saldo de API no puede pagar el almacenamiento, no se cobra nada y recibes un correo electrónico: haz una recarga en un plazo de 30 días o los archivos conservados pasarán a ser temporales y se eliminarán 7 días después.

En el caso poco frecuente de que falle nuestra copia, la entrada tendrá "stored": false y la URL será la original y de corta duración: descárgala pronto.