NovedadesNuevo

Una sola API para todos los motores de respuesta con IA

API
Una solicitud a POST /v1/async/task, la tarea en cola que devuelve y la tarea terminada que llega por webhook

Envía un prompt a cualquier motor de IA compatible con una sola solicitud y recibe la respuesta como JSON estructurado, por webhook o por consulta.

Qué obtienes

  • Un único endpoint, POST /v1/async/task, para todos los motores. Elige el motor con taskType y el mercado con country.
  • El mismo formato para todos los motores: el id, el status y las marcas de tiempo de la tarea envuelven una response propia de cada motor.
  • Resultados como prefieras: un webhook a tu servidor en cuanto termina la tarea, o GET /v1/async/task/{id} cuando estés listo.
  • Reintentos seguros con idempotencyKey: si envías la misma clave otra vez, recibes la tarea que ya creaste.

Cómo funciona

Los motores de IA tardan de segundos a minutos en responder, así que cada solicitud se convierte en una tarea persistente. La tarea pasa de QUEUED a PROCESSING y termina como COMPLETED con la respuesta o como FAILED con el motivo. Si el motor sufre un error temporal, la tarea vuelve a la cola para otro intento, de modo que los fallos breves se reintentan antes de llegar a ti.

Añade webhook.url y enviaremos la tarea terminada a tu servidor, con hasta cinco intentos en unos 30 minutos. Las tareas terminadas también siguen disponibles para consulta durante 24 horas, así que el webhook y la consulta juntos cubren cada resultado.

Para qué sirve

  • Comprueba la visibilidad de tu marca desde tu propio backend con la frecuencia que quieras.
  • Envía el mismo prompt a varios motores y compara las respuestas una junto a otra.
  • Simplifica los trabajos largos: envía, sigue con lo tuyo y deja que el webhook traiga el resultado.

Envía la solicitud

Envía la solicitud con tu clave de API en la cabecera Authorization.

curl -X POST https://api.querying.ai/v1/async/task \
  -H "Authorization: Bearer $QUERYING_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "taskType": "CHATGPT",
    "payload": {
      "prompt": "Best coffee shops near me for working on a laptop",
      "country": "US"
    },
    "webhook": { "url": "https://your-server.example.com/hooks/querying" },
    "idempotencyKey": "laptop-cafes-us-0001"
  }'

Campos de la solicitud

taskTypestringObligatorio
El motor que se ejecuta, como CHATGPT o GOOGLE.
payloadobjectObligatorio
La entrada del motor: prompt o query, más country y las opciones del motor.
webhook.urlstring
Una dirección HTTPS de tu servidor. La tarea terminada se envía allí en cuanto se completa.
idempotencyKeystring
Tu propio ID para la solicitud. Cada clave crea una sola tarea por cuenta, así que un reenvío sigue siendo una sola tarea.

Respuesta

La llamada responde al instante con la tarea en QUEUED. credits queda en 0 hasta que la tarea termina, y idempotencyKey vuelve tal como lo enviaste.

JSON
{
  "success": true,
  "task": {
    "id": "…",
    "taskType": "CHATGPT",
    "status": "QUEUED",
    "priority": 1,
    "createdAt": "…",
    "idempotencyKey": "laptop-cafes-us-0001"
  },
  "credits": { "creditsToCharge": 0, "creditsCharged": 0 }
}

Recibe el resultado

Lee la tarea con GET /v1/async/task/{id} cada pocos segundos hasta que status sea COMPLETED o FAILED. Los resultados siguen disponibles 24 horas después de terminar la tarea.

curl https://api.querying.ai/v1/async/task/$TASK_ID \
  -H "Authorization: Bearer $QUERYING_API_KEY"

Una tarea terminada lleva los credits cobrados y la response del motor. Esta es real, recortada para que se lea mejor.

JSON
{
  "success": true,
  "task": {
    "id": "e5aba119-a26e-4f82-a965-35c9234a428b",
    "taskType": "CHATGPT",
    "status": "COMPLETED",
    "createdAt": "2026-10-02T15:41:03.858Z"
  },
  "credits": { "creditsToCharge": 2, "creditsCharged": 2 },
  "response": {
    "text": "Here are several **nearby cafés that look particularly suitable for laptop work**, based on current local listings and work-friendly details:\n…",
    "sources": [
      {
        "position": 1,
        "url": "https://awifiplace.com/cities/new-york",
        "label": "Best Coffee Shops to Work in New York (2026) | 103 Cafes with WiFi"
      }
    ],
    "searchQueries": [
      "best coffee shops for laptop work near me wifi outlets"
    ]
  }
}
task.statusstring
QUEUED, PROCESSING y al final COMPLETED con la respuesta o FAILED con error.
credits.creditsChargedinteger
Créditos cobrados por la tarea terminada. Una tarea fallida cobra 0.

Webhooks

Con webhook.url, la tarea terminada llega a tu servidor como un POST con los mismos task, credits y response que devuelve la consulta. Una tarea fallida llega igual, con response.error y 0 créditos cobrados. Tres cabeceras firman cada entrega:

querying-webhook-idstring
El ID de la tarea. Cada entrega llega al menos una vez, así que úsalo para descartar repeticiones.
querying-webhook-timestampstring
Segundos Unix del momento de la firma. Acepta entregas firmadas en los últimos 5 minutos.
querying-webhook-signaturestring
v1, seguido del HMAC-SHA256 en base64 de {id}.{timestamp}.{body}, con el resumen SHA-256 de tu clave de API como clave.

Comprueba la firma sobre el cuerpo tal como llega, antes de analizarlo, y acepta la entrega cuando coincide:

import base64
import hashlib
import hmac
import os
import time


def verify_webhook(headers, body: bytes) -> bool:
    """body is the raw request body, before json.loads."""
    task_id = headers["querying-webhook-id"]
    timestamp = headers["querying-webhook-timestamp"]
    key = hashlib.sha256(os.environ["QUERYING_API_KEY"].encode()).digest()
    signed = f"{task_id}.{timestamp}.".encode() + body
    digest = hmac.new(key, signed, hashlib.sha256).digest()
    expected = "v1," + base64.b64encode(digest).decode()
    given = headers.get("querying-webhook-signature", "")
    fresh = abs(time.time() - int(timestamp)) <= 300
    return fresh and hmac.compare_digest(expected, given)

Responde con un estado 2xx en 30 segundos. Con otra respuesta, o pasados 30 segundos, la entrega se repite a los 2, 4, 8 y 16 minutos, cinco intentos en total, todos con el mismo querying-webhook-id.

Errores

Una solicitud rechazada responde al instante con success en false y un error con code, message y, en errores de campo, details. Queda fuera de la cola y cuesta 0 créditos.

VALIDATION_ERRORHTTP 400
Falta un campo o su valor está fuera de rango. details indica el campo.
MISSING_API_KEYHTTP 401
Falta la cabecera Authorization, o su clave es desconocida, caducó o fue revocada.
INSUFFICIENT_CREDITSHTTP 402
El saldo es menor que el precio de la tarea. Añade créditos o mejora el plan y vuelve a enviarla.
KEY_SCOPE_DENIEDHTTP 403
El motor queda fuera de los Motores permitidos de la clave. Usa otra clave o añade el motor en Gestionar clave.
RESOURCE_ALREADY_EXISTSHTTP 409
Ya existe en tu cuenta una tarea con este idempotencyKey, así que el envío sigue siendo una sola tarea. En un lote, el elemento cuenta como correcto.
PAYLOAD_TOO_LARGEHTTP 413
El cuerpo supera 1 MiB, u 8 MiB en un lote.
REGION_UNSUPPORTEDHTTP 422
country queda fuera de la lista de países del motor. Reenviar da el mismo resultado, por eso details.retryable es false.
PLAN_CONCURRENCY_LIMITHTTP 429
Tus tareas en cola y en curso llegaron al límite del plan: 2 en el plan gratuito, 10 en Basic, 25 en Pro, 50 en Scale y 100 en Max. Vuelve a enviar tras Retry-After segundos.
KEY_DAILY_CREDIT_LIMITHTTP 429
La clave agotó su Límite diario de créditos. Retry-After llega hasta la próxima medianoche UTC.
QUEUE_BACKPRESSUREHTTP 429
La cola del motor está llena por un momento. Vuelve a enviar tras Retry-After segundos.

Precio

Cada motor tiene su propio precio en créditos, y la tarea se cobra cuando se completa. Una tarea fallida libera los créditos que tenía reservados.

Más novedades

Recibe las novedades

Recibe las actualizaciones por correo.

Feed RSS