QueryWin encuentra las búsquedas por las que tu sitio ya obtiene impresiones sin tener ninguna página que las responda, redacta el artículo que falta y prepara tu producto para enviarlo a directorios, plataformas de lanzamiento, comunidades y los sitios que las respuestas de IA ya citan. Esta API pone ambos flujos en manos de tus scripts y asistentes de IA. La publicación y los envíos se siguen haciendo con tus propias credenciales y cuentas: QueryWin nunca se conecta a tu CMS ni envía nada por su cuenta.
Tres pasos. Todo lo que sigue es una llamada REST normal con una sola cabecera.
1
Crear una clave
En el panel de QueryWin, en “API”. La clave en texto plano solo se muestra una vez, al crearla. Concede solo los permisos que necesites: una clave sin ninguna casilla marcada es de solo lectura.
2
Enviarla como token Bearer
Añade Authorization: Bearer qw_live_… a cada petición. X-API-Key también funciona, para las herramientas que solo permiten definir una cabecera.
3
Consultar qué escribir y obtener el borrador
La lista de temas es gratuita y no consume créditos. Generar un esquema o un borrador descuenta créditos y requiere el permiso spend.
bash
# 1. Sitios sobre los que puede actuar esta clave
curl "https://www.querywin.com/api/v1/sites" \
-H "Authorization: Bearer $QUERYWIN_API_KEY"
# 2. Qué escribir esta semana (gratis, sin créditos)
curl "https://www.querywin.com/api/v1/topics?siteId=YOUR_SITE_ID" \
-H "Authorization: Bearer $QUERYWIN_API_KEY"
bash
# 3. Obtener el borrador (Markdown + JSON-LD con los datos ya completados)
curl "https://www.querywin.com/api/v1/topics/article?siteId=YOUR_SITE_ID&key=standard%20wardrobe%20depth" \
-H "Authorization: Bearer $QUERYWIN_API_KEY"
# 4. Tu script lo publica en tu propio blog y luego devuelve la URL
curl -X POST https://www.querywin.com/api/v1/topics/published \
-H "Authorization: Bearer $QUERYWIN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"siteId": "YOUR_SITE_ID",
"key": "standard wardrobe depth",
"url": "https://example.com/blog/standard-wardrobe-depth"
}'
Todas las respuestas van envueltas: {"success": true, "data": …}. Los errores son códigos legibles por máquina, nunca frases: QueryWin es multilingüe, y una frase en inglés escrita en el código acabaría mostrándose tal cual en una página en español.
El flujo de contenido
Cinco pasos, y solo dos tienen coste. El paso 4 es tuyo: QueryWin te entrega el Markdown y los datos estructurados, y la publicación la haces tú.
Paso
Endpoint
Coste
Encontrar búsquedas con impresiones pero sin página
GET /v1/topics
Gratis
Generar un esquema respaldado por datos
POST /v1/topics/outline
Créditos
Convertirlo en un borrador listo para publicar
POST /v1/topics/article
Créditos
Publicarlo en tu propio blog
tu propio CMS
—
Devolver la URL a QueryWin
POST /v1/topics/published
Gratis
QueryWin nunca se conecta a tu CMS, nunca guarda las credenciales de tu sitio y nunca pulsa “Publicar” por ti. Esta API te entrega el contenido; la escritura se hace en tu máquina, con tus propias credenciales. Ese es el límite, no una forma de saltárselo.
El flujo de difusión
Siete pasos, y solo uno tiene coste. El paso 6 es tuyo: QueryWin te entrega los contenidos de envío de cada canal, y el envío lo haces tú (o tu agente, con tus propias cuentas). Después, QueryWin vuelve a comprobar por su cuenta cada ficha publicada.
Paso
Endpoint
Coste
Listar tus productos y el grado de completitud de cada perfil
GET /v1/products
Gratis
Listar dónde enviar, por orden de relevancia, incluidos los sitios que citan las respuestas de IA
GET /v1/channels?productId=
Gratis
Crear una campaña con los canales elegidos
POST /v1/campaigns
Gratis
Obtener los contenidos preparados de una tarea
GET /v1/tasks/{id}
Gratis
Reescribirlos para ese canal
POST /v1/tasks/{id}/materials
Créditos
Enviarlos
tus propias cuentas
—
Informar del envío y, después, de la publicación con la URL de la ficha
POST /v1/tasks/{id}/status
Gratis
published es lo que tú has declarado; verified es lo que QueryWin vio al volver a comprobar la ficha unas 72 horas después: un enlace a tu producto en los directorios (también los de herramientas de IA) y una mención en el resto. Son campos distintos. Y un sitio que citan las respuestas de IA (citedByAi) es un sitio al que merece la pena dirigirse; no es una promesa de que vaya a incluirte.
Permisos
Cada clave lleva los permisos (scopes) concedidos al crearla. GET /v1/usage los devuelve, así que no tienes que descubrirlos topándote con un 403.
read
Siempre activo
Todos los endpoints GET: sitios, huecos de contenido, esquemas, borradores, productos, canales, campañas, tareas y sus contenidos, uso.
publish
Desactivado por defecto
Crear y actualizar perfiles de producto, importar imágenes y registrar lo que ha pasado: la URL de un artículo publicado (que también se envía a Bing, Yandex, Seznam y Naver, no a Google), una campaña nueva, una tarea marcada como enviada o publicada. Es gratis, pero cada llamada crea un registro con consecuencias: las campañas cuentan para el límite de tu plan y una ficha publicada se vuelve a comprobar.
spend
Desactivado por defecto
Generar esquemas y borradores, y reescribir contenidos de envío para un canal. Estas acciones descuentan créditos. Concede este permiso solo si quieres que quien hace la llamada (un script o un asistente de IA) pueda gastar por su cuenta.
No hay jerarquía: publish no implica spend, y spend no implica publish. Son tipos de riesgo distintos. Una llamada para la que tu clave no tiene permiso devuelve un 403 con missing_scope_<name> y los permisos que sí tienes.
Consumo de créditos
Dos endpoints descuentan créditos: POST /v1/topics/outline y POST /v1/topics/article. Los protegen tres salvaguardas.
Salvaguarda
Qué evita
confirmSpend
Un script que sigue gastando créditos después de una subida de precio.
Límite diario
Un bucle descontrolado que agota el saldo en una noche. Devuelve un 429 con la hora de reinicio.
Huella de la entrada
Cobrar dos veces por el mismo tema. Las entradas idénticas devuelven gratis el resultado en caché, así que puedes reintentar sin riesgo una petición que ha agotado el tiempo de espera.
confirmSpend es un límite de autorización, no un importe exacto. Envía un valor mayor o igual que el precio actual y se te cobrará lo que cueste realmente, a menudo cero si el resultado está en caché. Si el precio llega a superar tu límite, la llamada falla con confirm_spend_too_low en lugar de cobrar más sin avisar.
Convenciones
Tres reglas que se cumplen en todos los endpoints.
Los errores son códigos, nunca frases. Léelos, pero no los muestres sin procesar: están pensados para que los conviertas en tus propios textos.
Un resultado de negocio no es un error
Una llamada de generación que no ha podido producir un resultado válido devuelve HTTP 200 con data.ok = false y un código data.failure, para que puedas distinguirla de un fallo de autenticación o de una conexión caída. Estas llamadas no se cobran.
120 peticiones por minuto y por clave. Si superas esa cifra, recibes un 429 con la hora de reinicio. Es independiente del límite diario de generación descrito arriba.
MCP para agentes de IA
Ambos flujos están disponibles a través del Model Context Protocol, con la misma clave y la misma cabecera de autenticación. Añade el servidor a Claude Code, Cursor, n8n o cualquier otra herramienta compatible con MCP sobre HTTP.
Diecinueve herramientas. Perfiles de producto: create_product, get_product, update_product, import_product_image. Contenido: list_sites, get_usage, list_content_gaps, get_outline, get_article_draft, generate_outline, generate_article_draft, mark_published. Difusión: list_products, list_channels, create_campaign, list_tasks, get_task, write_task_materials, report_task_status. Pregúntale a tu asistente qué escribir esta semana o dónde enviar tu producto a continuación, y lo averiguará por su cuenta.
prompt
Usando el servidor MCP de QueryWin, encuentra los tres huecos de contenido más grandes de mi sitio,
muéstrame las búsquedas que hay detrás de cada uno y dime cuánto costaría redactar el borrador del primero.
Las herramientas se filtran por permiso. Con una clave de solo lectura, las herramientas de generación ni siquiera aparecen en la lista de herramientas del asistente: un agente no puede llamar a una herramienta que no ve. Dale a cada agente su propia clave para poder revocarla sin tocar tus otras integraciones.
La autenticación se hace con un token Bearer, algo que la especificación MCP permite (en ella la autorización es opcional). Los clientes que permiten definir una cabecera (Claude Code, Cursor, n8n) se conectan directamente. Puede que los hosts que exigen una pantalla de consentimiento de OAuth no lo consigan.
Account
GET/v1/sites
Listar los sitios sobre los que puede actuar esta clave
Empieza por aquí. Todos los demás endpoints reciben el siteId que devuelve esta llamada. Si lo omites, recurren al primer sitio conectado: no pasa nada en las cuentas con un solo sitio, pero en todas las demás es un error latente.
Respuesta200
Campo
Tipo
Descripción
success
enum
Valores: true
data
SiteList
└sites
array<Site>
└siteId
string
└domain
string
└gscProperty
string
La propiedad de Search Console, tal cual: sc-domain:example.com o https://example.com/.
└syncStatus
enum
Valores: pendingsyncingdonefailed
└syncedThroughadmite null
string
Los datos de Search Console llevan entre 2 y 3 días de retraso. Todas las métricas de este sitio están actualizadas a esta fecha: indícalo si muestras estas cifras en cualquier parte.
Errores posibles
401Clave ausente, mal formada, revocada o caducada
Precios actuales, generaciones gratuitas, saldo de créditos y límites diarios
Consúltalo antes de generar nada. Es la misma fuente de verdad que usa la interfaz web para decidir qué muestra cada botón: la disponibilidad se decide en el servidor, no a base de probar y fallar.
Respuesta200
Campo
Tipo
Descripción
success
enum
Valores: true
data
Usage
└scopes
array<enum>
Lo que puede hacer esta clave. Consúltalo una vez al arrancar, en lugar de descubrir tus permisos topándote con un 403.Valores: readpublishspend
└credits
object
└balance
integer
└outline
StepUsage
└available
boolean
Es false cuando el motor de generación no está configurado. En ese caso, no llames al endpoint POST correspondiente.
└pricePerOutline
integer
Créditos por esquema (solo presente en outline).
└pricePerArticle
integer
Créditos por borrador (solo presente en article).
└pricePerTask
integer
Créditos por cada reescritura para un canal (solo presente en materials).
└freeRemaining
integer
Generaciones gratuitas que le quedan a esta cuenta, contadas por tema distinto (esquemas, borradores) o por tarea distinta (contenidos), no por cada vez que se pulsa un botón. Las generaciones gratuitas también requieren confirmSpend.
└daily
DailyLimit
Protección contra un script desbocado, contabilizada en la base de datos en todos los puntos de entrada (las acciones en la interfaz web también cuentan). Se reinicia a medianoche, hora local, no en una ventana deslizante.
└used
integer
└limit
integer
└remaining
integer
└resetAt
string
└article
StepUsage
└available
boolean
Es false cuando el motor de generación no está configurado. En ese caso, no llames al endpoint POST correspondiente.
└pricePerOutline
integer
Créditos por esquema (solo presente en outline).
└pricePerArticle
integer
Créditos por borrador (solo presente en article).
└pricePerTask
integer
Créditos por cada reescritura para un canal (solo presente en materials).
└freeRemaining
integer
Generaciones gratuitas que le quedan a esta cuenta, contadas por tema distinto (esquemas, borradores) o por tarea distinta (contenidos), no por cada vez que se pulsa un botón. Las generaciones gratuitas también requieren confirmSpend.
└daily
DailyLimit
Protección contra un script desbocado, contabilizada en la base de datos en todos los puntos de entrada (las acciones en la interfaz web también cuentan). Se reinicia a medianoche, hora local, no en una ventana deslizante.
└used
integer
└limit
integer
└remaining
integer
└resetAt
string
└materials
StepUsage
└available
boolean
Es false cuando el motor de generación no está configurado. En ese caso, no llames al endpoint POST correspondiente.
└pricePerOutline
integer
Créditos por esquema (solo presente en outline).
└pricePerArticle
integer
Créditos por borrador (solo presente en article).
└pricePerTask
integer
Créditos por cada reescritura para un canal (solo presente en materials).
└freeRemaining
integer
Generaciones gratuitas que le quedan a esta cuenta, contadas por tema distinto (esquemas, borradores) o por tarea distinta (contenidos), no por cada vez que se pulsa un botón. Las generaciones gratuitas también requieren confirmSpend.
└daily
DailyLimit
Protección contra un script desbocado, contabilizada en la base de datos en todos los puntos de entrada (las acciones en la interfaz web también cuentan). Se reinicia a medianoche, hora local, no en una ventana deslizante.
└used
integer
└limit
integer
└remaining
integer
└resetAt
string
└distribution
DistributionQuota
Los límites de difusión del plan y su consumo actual. Un límite con valor null significa que no hay límite.
└plan
string
└limits
object
└channelsadmite null
integer
Número de canales distintos en los que un producto puede tener tareas, contados en el periodo channelsPeriod.
└channelsPeriod
enum
month (planes de pago): se cuenta por mes natural (UTC), así que cada mes permite un nuevo lote de canales. total (plan gratuito): se cuenta durante toda la vida del producto.Valores: monthtotal
└tasksPerMonthadmite null
integer
Número de tareas que se pueden crear por mes natural (UTC), entre todos los productos.
└activeCampaignsadmite null
integer
Número de campañas que pueden estar activas a la vez.
Búsquedas con impresiones pero sin una página que las cubra
Gratis y sin facturación externa (la API en sí requiere un plan de pago). Se recalcula en cada llamada a partir de tus propios datos de Search Console, sin ninguna base de palabras clave externa, y de eso se trata precisamente: “ya tienes impresiones y ninguna página que las atienda” no es algo que pueda decirte una herramienta de palabras clave.
Los resultados se ordenan por oportunidad. Se excluyen los temas que el usuario ha descartado en la interfaz.
Parámetros de consulta
Campo
Tipo
Descripción
siteId
string
De GET /v1/sites. Por defecto, el primer sitio conectado.
Respuesta200
Campo
Tipo
Descripción
success
enum
Valores: true
data
TopicList
└siteIdadmite null
string
└topics
array<Topic>
└key
string
El identificador del clúster: devuélvelo tal cual como key a todos los demás endpoints de temas. Es el texto normalizado de la búsqueda representativa, así que puede contener espacios, barras y caracteres no latinos. Envíalo siempre como parámetro de consulta o en el cuerpo, nunca en la ruta de la URL.
└title
string
La búsqueda del clúster con más impresiones, tal cual. No es un título generado: ese llega con el esquema.
└shape
enum
comparison significa que este clúster coincide con tu lista de competidores. El artículo tiene que contrastar, no explicar al competidor: de lo contrario, estarás escribiendo contenido para él.Valores: comparisonroundupguide
└intent
string
└members
array<TopicMember>
└text
string
La búsqueda, tal como se escribió.
└impressions
integer
└clicks
integer
└positionadmite null
number
└landingUrladmite null
string
La página que Search Console asocia actualmente a esta búsqueda, si la hay.
└impressions
integer
Valor medido, procedente de Search Console.
└clicks
integer
Valor medido, procedente de Search Console.
└positionadmite null
number
Valor medido: posición media en el clúster, ponderada por impresiones.
└competitor
boolean
└score
number
└rank
integer
└upsideClicks
integer
Es una estimación, no una medición: clics adicionales al mes si una página dedicada alcanzara la posición 3. Es a propósito un campo separado de clicks e impressions, y debe seguir visualmente separado allí donde lo muestres. Presentar una proyección como si fuera un dato medido es el error típico de esta categoría de productos.
└status
enum
Valores: newdismissedplannedpublished
└outlineAtadmite null
string
└articleAtadmite null
string
No lo deduzcas de outlineAt. Tener un esquema no significa que exista un borrador: son dos pasos de pago distintos.
└totalQueries
integer
Número total de búsquedas distintas que cubren estos temas.
Errores posibles
401Error de autenticación
404site_not_found — este siteId no pertenece a esta cuenta
Nunca lanza una generación y nunca cuesta nada. article es null mientras no exista ningún borrador.
Parámetros de consulta
Campo
Tipo
Descripción
keyobligatorio
string
El identificador del clúster, de GET /v1/topics.
siteId
string
De GET /v1/sites. Por defecto, el primer sitio conectado.
Respuesta200
Campo
Tipo
Descripción
success
enum
Valores: true
data
ArticleResult
└articleadmite null
Article
└title
string
└description
string
Metadescripción.
└markdown
string
El cuerpo que se publica.
└jsonLd
string
Los datos estructurados de este artículo, ya rellenados. JSON válido: colócalo dentro de una etiqueta script de tipo application/ld+json en la página publicada.
└wordCount
integer
└warnings
array<ArticleWarning>
Frases que suenan a escritas por una IA. El borrador sigue siendo utilizable: se señalan en lugar de reescribirse sin avisar. Regístralas en tus logs. En un flujo automatizado, este es el único momento en que alguien podría darse cuenta.
Convertir el esquema en un borrador listo para publicar (consume créditos)
La llamada más cara del producto. Síncrona: puede tardar entre uno y dos minutos.
Antes tiene que existir un esquema: sin él, obtienes failure: "no_outline". El esquema es lo que aporta las pruebas (las búsquedas reales detrás del clúster, las páginas que la IA cita hoy, la deduplicación frente a tus páginas existentes). Prescindir de él reduciría esta llamada a una simple herramienta de redacción con IA, sin nada detrás.
article.markdown es el cuerpo que se publica. article.jsonLd contiene los datos estructurados, ya rellenados con el contenido de este artículo. **article.warnings debe registrarse en tus logs, no descartarse**: cada aviso señala una frase concreta que suena a escrita por una IA, y en un flujo automatizado nadie vuelve a leer el borrador antes de que se publique.
Los borradores que no pasan la validación estructural (secciones que faltan, preguntas obligatorias sin responder, enlaces inventados, JSON-LD no válido) se descartan y no se cobran.
Cuerpo de la petición
Campo
Tipo
Descripción
keyobligatorio
string
El identificador del clúster, de GET /v1/topics.
siteId
string
Por defecto, el primer sitio conectado.
confirmSpendobligatorio
integer
Un tope de autorización en créditos, no un importe exacto. Envía un valor mayor o igual que el precio actual que indica GET /v1/usage; solo se cobra lo que cueste realmente, que a menudo es cero si el resultado está en caché. Si algún día el precio supera tu tope, la llamada se rechaza en lugar de cobrarte más sin avisar. Es obligatorio aunque te queden generaciones gratuitas: se acabarán, y ese no debería ser el momento en que tu script descubra que este endpoint cuesta dinero. (min 0)
Respuesta200
Campo
Tipo
Descripción
success
enum
Valores: true
data
ArticleOutcome
└ok
boolean
└failure
enum
Solo presente cuando ok es false. El código HTTP sigue siendo 200.Valores: topic_not_foundno_outlineengine_unavailableengine_failedno_valid_article
└articleadmite null
Article
└title
string
└description
string
Metadescripción.
└markdown
string
El cuerpo que se publica.
└jsonLd
string
Los datos estructurados de este artículo, ya rellenados. JSON válido: colócalo dentro de una etiqueta script de tipo application/ld+json en la página publicada.
└wordCount
integer
└warnings
array<ArticleWarning>
Frases que suenan a escritas por una IA. El borrador sigue siendo utilizable: se señalan en lugar de reescribirse sin avisar. Regístralas en tus logs. En un flujo automatizado, este es el único momento en que alguien podría darse cuenta.
Es false cuando se ha devuelto un resultado en caché: no se ha cobrado nada.
└creditsSpent
integer
└freeUsed
boolean
└rejected
array<string>
Defectos estructurales por los que se ha descartado el borrador (sin cobrarlo): missing_sections, missing_faq, invented_link, invalid_json_ld, comparison_without_contrast, body_too_short.
Errores posibles
400key_required, confirm_spend_required o confirm_spend_too_low (el cuerpo incluye el price actual)
401Error de autenticación
402insufficient_credits — el cuerpo incluye requiredCredits, currentBalance, shortfall
403missing_scope_spend — esta clave no tiene el permiso spend
429rate_limited o daily_limit_reached (el cuerpo incluye resetAt)
Llamada síncrona: tarda entre 10 y 20 segundos aproximadamente.
Con entradas idénticas se devuelve el esquema en caché sin volver a cobrar: la huella cubre el clúster de temas y su clasificación frente a tus competidores, así que puedes reintentar sin riesgo una solicitud HTTP que haya fallado.
Los resultados de negocio (motor no disponible, salida que no pasa la validación) devuelven HTTP 200 con ok: false y un código failure. La falta de créditos, en cambio, sí es un error 402 real.
Cuerpo de la petición
Campo
Tipo
Descripción
keyobligatorio
string
El identificador del clúster, de GET /v1/topics.
siteId
string
Por defecto, el primer sitio conectado.
confirmSpendobligatorio
integer
Un tope de autorización en créditos, no un importe exacto. Envía un valor mayor o igual que el precio actual que indica GET /v1/usage; solo se cobra lo que cueste realmente, que a menudo es cero si el resultado está en caché. Si algún día el precio supera tu tope, la llamada se rechaza en lugar de cobrarte más sin avisar. Es obligatorio aunque te queden generaciones gratuitas: se acabarán, y ese no debería ser el momento en que tu script descubra que este endpoint cuesta dinero. (min 0)
Respuesta200
Campo
Tipo
Descripción
success
enum
Valores: true
data
OutlineOutcome
└ok
boolean
└failure
enum
Solo presente cuando ok es false. El código HTTP sigue siendo 200: es un resultado, no un error.Valores: topic_not_foundengine_unavailableengine_failedno_valid_outline
└outlineadmite null
Outline
└title
string
└slug
string
└angle
string
La tesis que debe defender esta página.
└sections
array<object>
└heading
string
└points
array<string>
└faq
array<object>
Las preguntas que debe responder la página. Son los fragmentos que citan las respuestas de IA.
└question
string
└answer
string
└schemaType
string
El tipo de JSON-LD adecuado para esta página.
└internalLinks
array<string>
Páginas de tu propio sitio a las que conviene enlazar. Elegidas entre URL reales, nunca inventadas.
└generated
boolean
Es false cuando se ha devuelto un resultado en caché: no se ha cobrado nada.
└creditsSpent
integer
└freeUsed
boolean
└rejected
array<string>
Reglas de validación que ha incumplido la salida del modelo. Conviene registrarlas como señal de calidad.
Errores posibles
400key_required, confirm_spend_required o confirm_spend_too_low (el cuerpo incluye el price actual)
401Error de autenticación
402insufficient_credits — el cuerpo incluye requiredCredits, currentBalance, shortfall
403missing_scope_spend — esta clave no tiene el permiso spend
429rate_limited o daily_limit_reached (el cuerpo incluye resetAt)
Esta llamada cierra el ciclo: marca el tema como publicado, guarda la URL y la envía a IndexNow en tu nombre.
IndexNow cubre Bing, Yandex, Seznam y Naver, pero no Google. Google no tiene un endpoint equivalente de indexación instantánea: encuentra la página a través de tu sitemap.
El envío a IndexNow nunca hace fallar la llamada: tu artículo ya está publicado, y ese es el hecho que registra esta llamada. Consulta el campo indexnow para saber qué ha pasado realmente. El envío requiere que el fichero de clave de IndexNow esté verificado para el sitio (se configura una sola vez en el panel).
Registrar la URL es también lo que permite a QueryWin volver a medir las búsquedas a las que apunta este artículo, cuando haya tenido tiempo de surtir efecto.
Cuerpo de la petición
Campo
Tipo
Descripción
keyobligatorio
string
siteId
string
urlobligatorio
string
La URL donde lo has publicado. Solo http/https. En este momento no se descarga la página.
Respuesta200
Campo
Tipo
Descripción
success
enum
Valores: true
data
PublishedResult
└clusterKey
string
└status
enum
Valores: published
└publishedUrl
string
└publishedAt
string
└indexnow
object
Bing, Yandex, Seznam y Naver. No incluye Google.
└pushed
boolean
└outcome
string
skipped suele significar que el fichero de clave aún no está verificado.
└engines
string
Errores posibles
400key_required, url_required o invalid_url (solo http/https)
401Error de autenticación
403missing_scope_publish — esta clave no tiene el permiso publish
Las campañas (sin las archivadas, salvo con includeArchived=true), además de los límites de difusión del plan y su consumo actual. Gratis.
Parámetros de consulta
Campo
Tipo
Descripción
productId
string
Solo las campañas de este producto.
includeArchived
boolean
Respuesta200
Campo
Tipo
Descripción
success
enum
Valores: true
data
CampaignList
└campaigns
array<Campaign>
└campaignId
string
└productId
string
└name
string
└status
enum
completed se calcula: todas las tareas están publicadas, verificadas, fallidas u omitidas.Valores: activecompletedarchived
└quota
integer
Número de canales con los que se creó la campaña.
└startsAt
string
└endsAtadmite null
string
└counts
object
└total
integer
└submitted
integer
submitted + published + verified.
└live
integer
published + verified.
└blocked
integer
└done
integer
└byStatus
object
└createdAt
string
└quota
DistributionQuota
Los límites de difusión del plan y su consumo actual. Un límite con valor null significa que no hay límite.
└plan
string
└limits
object
└channelsadmite null
integer
Número de canales distintos en los que un producto puede tener tareas, contados en el periodo channelsPeriod.
└channelsPeriod
enum
month (planes de pago): se cuenta por mes natural (UTC), así que cada mes permite un nuevo lote de canales. total (plan gratuito): se cuenta durante toda la vida del producto.Valores: monthtotal
└tasksPerMonthadmite null
integer
Número de tareas que se pueden crear por mes natural (UTC), entre todos los productos.
└activeCampaignsadmite null
integer
Número de campañas que pueden estar activas a la vez.
Crear una campaña a partir de una lista explícita de canales
Una tarea por cada ID de canal, con sus contenidos de envío preparados al momento a partir del perfil de producto, sin coste. Pasa los canales que se han elegido de verdad: una campaña es el registro de dónde has decidido enviar, no un filtro que el servidor se encarga de ampliar.
Los canales en los que el producto ya tiene una tarea abierta o enviada se omiten y aparecen en skipped con un motivo (already_open, already_submitted, not_found, broken, inactive, other_product, locked). Si no queda ninguno, la llamada devuelve HTTP 200 con ok: false y failure: "no_valid_targets". Superar la cuota de difusión del plan supone un rechazo: **409 quota_exceeded**, con dimension, limit, used y requested. No se crea nada, ni siquiera la parte que habría cabido.
Cuerpo de la petición
Campo
Tipo
Descripción
productIdobligatorio
string
nameobligatorio
string
targetIdsobligatorio
array<string>
Los ID de canal que devuelve GET /v1/channels. Solo los canales elegidos.
endsAt
string
Fecha límite opcional, que se muestra en el panel. Nada se cierra automáticamente.
Respuesta200
Campo
Tipo
Descripción
success
enum
Valores: true
data
CreateCampaignOutcome
└ok
boolean
└failure
enum
Presente cuando ok es false.Valores: no_valid_targets
└campaign
Campaign
└campaignId
string
└productId
string
└name
string
└status
enum
completed se calcula: todas las tareas están publicadas, verificadas, fallidas u omitidas.Valores: activecompletedarchived
└quota
integer
Número de canales con los que se creó la campaña.
└startsAt
string
└endsAtadmite null
string
└counts
object
└total
integer
└submitted
integer
submitted + published + verified.
└live
integer
published + verified.
└blocked
integer
└done
integer
└byStatus
object
└createdAt
string
└tasks
array<Task>
└taskId
string
└campaignId
string
└productId
string
└status
enum
published es lo que tú has declarado. verified es lo que QueryWin ha visto en la página de la ficha (un enlace en los directorios y los directorios de herramientas de IA, una mención en el resto). Mantenlos separados cuando informes de ellos.Valores: plannedpreparedin_progressblockedsubmittedpublishedverifiedfailedskipped
Contenidos obligatorios que faltan en el perfil. Completa el perfil en el panel: la tarea se vuelve a preparar sola.
└listingUrladmite null
string
└markedBy
enum
Quién hizo el último cambio de estado: una persona (o esta API), la extensión del navegador o el propio QueryWin.Valores: userdevicesystem
└hasGenerated
boolean
Existe una versión adaptada a este canal.
└reviewDueAtadmite null
string
Cuándo volver a comprobar después del envío (submittedAt + el plazo de revisión del canal).
└submittedAtadmite null
string
└publishedAtadmite null
string
└verifiedAtadmite null
string
└next
array<string>
Estados que puedes asignar desde el actual mediante POST /v1/tasks/{id}/status.
└target
object
└targetId
string
└name
string
└url
string
└submitUrl
string
└kind
string
└source
enum
Valores: seeduserrivals
└language
string
└requiresBacklink
boolean
└checkadmite null
object
La comprobación que QueryWin hace en la ficha una vez publicada. Es null hasta que la tarea se publica.
└kind
enum
Qué se busca: un enlace al producto (directorios, directorios de herramientas de IA) o una mención de la marca (todos los demás tipos).Valores: link_livemention_seen
└stateadmite null
enum
confirmed = encontrado. unconfirmed = no se encontró en una ronda de comprobaciones (el estado no cambia; comprueba la URL). lost = estaba y ha desaparecido (la tarea pasa a fallida).Valores: confirmedunconfirmedlostnull
└checkedAtadmite null
string
└dueAtadmite null
string
└updatedAt
string
└skipped
array<object>
└targetId
string
└reason
enum
other_product = un sitio candidato citado por la IA que pertenece a otro producto; inactive = un canal desactivado o ignorado; locked = fuera de la ventana de la biblioteca de canales del plan gratuito (los primeros window canales por relevancia, tal como los devuelve GET /v1/channels; tus propios canales, tus favoritos y los sitios citados por la IA no tienen límite).Valores: not_foundbrokeninactiveother_productalready_openalready_submittedlocked
403missing_scope_publish — esta clave no tiene el permiso publish
404product_not_found — este productId no pertenece a esta cuenta
409quota_exceeded — el cuerpo incluye dimension (active_campaigns / tasks_per_month / channels), limit, used, requested; para channels, también period (month / total, igual que DistributionQuota.limits.channelsPeriod)
completed se calcula: todas las tareas están publicadas, verificadas, fallidas u omitidas.Valores: activecompletedarchived
└quota
integer
Número de canales con los que se creó la campaña.
└startsAt
string
└endsAtadmite null
string
└counts
object
└total
integer
└submitted
integer
submitted + published + verified.
└live
integer
published + verified.
└blocked
integer
└done
integer
└byStatus
object
└createdAt
string
└tasks
array<Task>
└taskId
string
└campaignId
string
└productId
string
└status
enum
published es lo que tú has declarado. verified es lo que QueryWin ha visto en la página de la ficha (un enlace en los directorios y los directorios de herramientas de IA, una mención en el resto). Mantenlos separados cuando informes de ellos.Valores: plannedpreparedin_progressblockedsubmittedpublishedverifiedfailedskipped
Contenidos obligatorios que faltan en el perfil. Completa el perfil en el panel: la tarea se vuelve a preparar sola.
└listingUrladmite null
string
└markedBy
enum
Quién hizo el último cambio de estado: una persona (o esta API), la extensión del navegador o el propio QueryWin.Valores: userdevicesystem
└hasGenerated
boolean
Existe una versión adaptada a este canal.
└reviewDueAtadmite null
string
Cuándo volver a comprobar después del envío (submittedAt + el plazo de revisión del canal).
└submittedAtadmite null
string
└publishedAtadmite null
string
└verifiedAtadmite null
string
└next
array<string>
Estados que puedes asignar desde el actual mediante POST /v1/tasks/{id}/status.
└target
object
└targetId
string
└name
string
└url
string
└submitUrl
string
└kind
string
└source
enum
Valores: seeduserrivals
└language
string
└requiresBacklink
boolean
└checkadmite null
object
La comprobación que QueryWin hace en la ficha una vez publicada. Es null hasta que la tarea se publica.
└kind
enum
Qué se busca: un enlace al producto (directorios, directorios de herramientas de IA) o una mención de la marca (todos los demás tipos).Valores: link_livemention_seen
└stateadmite null
enum
confirmed = encontrado. unconfirmed = no se encontró en una ronda de comprobaciones (el estado no cambia; comprueba la URL). lost = estaba y ha desaparecido (la tarea pasa a fallida).Valores: confirmedunconfirmedlostnull
Dónde se puede enviar un producto, por orden de relevancia
La biblioteca de canales (directorios, plataformas de lanzamiento, directorios de herramientas de IA, comunidades y plataformas de publicación), los canales que has añadido tú y, si se indica productId, los sitios que las respuestas de IA ya citan en las búsquedas de ese producto (source: "rivals"). Con productId, la lista se ordena por relevancia y cada canal incluye taskStatus (no nulo cuando el producto ya tiene una tarea en ese canal). Gratis.
**citedByAi significa que las respuestas de IA han citado ese sitio en tus búsquedas. No significa que ese sitio vaya a incluir tu producto**: la tarea existe precisamente para pedírselo.
Parámetros de consulta
Campo
Tipo
Descripción
productId
string
Ordena por relevancia para este producto, añade taskStatus e incluye sus sitios candidatos citados por la IA.
kind
string
Tipo de canal.Valores: directorylaunchai_directorycommunitycontentother
source
string
seed = la biblioteca, user = añadido por ti, rivals = sitios citados por la IA para este producto.Valores: seeduserrivals
pricing
string
Coste del envío.Valores: freeconditionalpaidunknown
submitMethod
string
Cómo se envía: rellenar un formulario, publicar en una comunidad o mandar un correo de presentación.Valores: formpostemail
q
string
Busca en el nombre, el dominio y las temáticas.
hideSubmitted
boolean
Excluye los canales en los que este producto ya tiene una tarea abierta o enviada. Requiere productId.
page
integer
Por defecto: 1.
pageSize
integer
Por defecto: 30.
Respuesta200
Campo
Tipo
Descripción
success
enum
Valores: true
data
ChannelList
└productIdadmite null
string
└items
array<Channel>
└targetId
string
Pásalos como targetIds a POST /v1/campaigns.
└name
string
└url
string
└submitUrl
string
El formulario de envío o la página de publicación; en los sitios citados por la IA, la página que más citan las respuestas de IA.
form = rellenar su formulario de envío, post = publicar por tu cuenta en la comunidad, email = mandar un correo de presentación a los editores (la dirección se lee de la página cuando la abres; no se guarda).Valores: formpostemail
└source
enum
seed = la biblioteca, user = añadido por ti, rivals = un sitio que las respuestas de IA citan en las búsquedas de este producto.Valores: seeduserrivals
└pricingType
enum
Valores: freeconditionalpaidunknown
└priceNoteadmite null
string
└language
string
en, zh, multi o, en los sitios citados por la IA, un código de idioma detectado a partir de las búsquedas.
└topics
array<string>
└requiresAccount
boolean
└requiresBacklink
boolean
└reviewDaysadmite null
integer
Plazo de revisión habitual. La tarea te avisa para que vuelvas a comprobarla cuando haya pasado.
└siteRankadmite null
integer
Posición mundial en la lista pública Tranco (cuanto más baja, más visitado es el sitio). null = fuera del primer millón. No es el Domain Rating.
└hasFormSpec
boolean
Los campos del formulario de este canal están registrados, así que los contenidos se recortan a sus límites exactos.
└relevanceadmite null
integer
Puntuación de relevancia para el producto indicado en la solicitud. Solo sirve para ordenar.
└taskStatusadmite null
string
La tarea abierta o completada del producto en este canal, si la hay. null = aún no hay ninguna.
└citedByAiadmite null
object
Solo para source: "rivals". Las respuestas de IA han citado este sitio en las búsquedas indicadas. No es una promesa de que el sitio vaya a incluir tu producto: la tarea existe precisamente para pedírselo.
└queries
integer
Número de búsquedas distintas en las que se ha citado.
└samples
integer
Número de muestras de respuestas de IA que lo han citado.
└searches
array<string>
└pages
array<string>
Las páginas citadas, de más a menos citada. Queda vacío en las muestras más antiguas, que solo registraban el dominio.
└total
integer
└page
integer
└pageSize
integer
└limited
boolean
Plan gratuito: solo se devuelven los primeros window canales en el orden por defecto (relevancia para productId), y los parámetros de filtro, búsqueda y ordenación se rechazan con 403 library_locked. total sigue siendo el tamaño real de la biblioteca.
└windowadmite null
integer
Tamaño de la ventana del plan gratuito: 20 canales, más 20 por cada persona que se registre con tu enlace de invitación (y 20 más si tú te registraste con uno). null cuando la lista no está limitada.
Punto de partida del flujo de difusión: todos los demás endpoints de difusión reciben un productId. completeness y missing salen del perfil de producto guardado: un campo vacío en el perfil es un campo vacío en cada envío, y si falta un campo obligatorio, la tarea se queda en blocked / missing_material hasta que se complete el perfil. Consúltalo con GET /v1/products/{id} y rellénalo con PATCH /v1/products/{id}. Gratis.
Respuesta200
Campo
Tipo
Descripción
success
enum
Valores: true
data
ProductList
└products
array<Product>
└productId
string
└name
string
└url
string
└domain
string
└primaryLanguage
enum
Valores: enzhjakodefresptitrunlpltrarthviid
└topics
array<string>
└completeness
integer
Grado de completitud del perfil, de 0 a 100. Completa los campos que faltan en el panel o con PATCH /v1/products/{id}.
└missing
array<string>
Campos del perfil que están vacíos. Cada uno queda vacío en todos los envíos.
Requiere el permiso publish y un plan de pago. Crea un producto a partir de la URL pública de su página de inicio y de un nombre opcional; ocupa una plaza de tu cuota de productos y no consume créditos. Devuelve el perfil completo tal como se ha guardado, que después puedes rellenar con PATCH /v1/products/{id}. No rastrea el sitio ni usa IA. Un dominio ya registrado devuelve 409 product_exists con el productId existente; reutilízalo si se ha perdido la respuesta. Los valores por defecto del producto son editables: no son datos comprobados del sitio web.
Cuerpo de la petición
Campo
Tipo
Descripción
urlobligatorio
string
name
string
Respuesta201
Campo
Tipo
Descripción
success
boolean
data
ProductDetail
└name
string
└url
string
└primaryLanguage
enum
Valores: enzhjakodefresptitrunlpltrarthviid
└businessType
enum
Valores: saastoolecommercecontentserviceother
└launchStatus
enum
Valores: livebeta
└pricingModel
enum
Valores: freefreemiumpaidtrial
└taglineadmite null
object
└shortDescadmite null
object
└longDescadmite null
object
└firstCommentadmite null
object
└topics
array<string>
└promoCodeadmite null
string
└videoUrladmite null
string
└demoUrladmite null
string
└linksadmite null
object
└webApp
string
└appStore
string
└playStore
string
└chromeExtension
string
└macos
string
└windows
string
└socialsadmite null
object
└x
string
└linkedin
string
└github
string
└instagram
string
└youtube
string
└facebook
string
└contactNameadmite null
string
└contactEmailadmite null
string
└gallery
array<string>
└productId
string
└domain
string
└thumbnailUrladmite null
string
└completeness
integer
(0–100)
└missing
array<string>
└createdAt
string
└updatedAt
string
└sites
array<object>
└siteId
string
└domain
string
└syncedThroughadmite null
string
Errores posibles
400invalid_product_input, invalid_url o url_not_public
401Error de autenticación
403plan_required, o missing_scope_publish en las operaciones de escritura
409product_exists (con el productId existente) o product_limit_reached
429rate_limited — 120 solicitudes por minuto y por clave
Requiere el permiso publish. Guarda al instante solo los campos enviados; los objetos (incluidos los textos localizados) y los arrays sustituyen el campo entero. Consulta antes el perfil para conservar los demás idiomas. No consume créditos ni genera nada con IA. Los contenidos de envío pendientes se actualizan de forma asíncrona. Usa solo datos conocidos: no inventes la información del producto que falte.
Cuerpo de la petición
Campo
Tipo
Descripción
name
string
url
string
primaryLanguage
enum
Valores: enzhjakodefresptitrunlpltrarthviid
businessType
enum
Valores: saastoolecommercecontentserviceother
launchStatus
enum
Valores: livebeta
pricingModel
enum
Valores: freefreemiumpaidtrial
tagline
object
shortDesc
object
longDesc
object
firstComment
object
topics
array<string>
promoCode
string
videoUrl
string
demoUrl
string
links
object
└webApp
string
└appStore
string
└playStore
string
└chromeExtension
string
└macos
string
└windows
string
socials
object
└x
string
└linkedin
string
└github
string
└instagram
string
└youtube
string
└facebook
string
contactName
string
contactEmail
string
gallery
array<string>
Respuesta200
Campo
Tipo
Descripción
success
boolean
data
ProductDetail
└name
string
└url
string
└primaryLanguage
enum
Valores: enzhjakodefresptitrunlpltrarthviid
└businessType
enum
Valores: saastoolecommercecontentserviceother
└launchStatus
enum
Valores: livebeta
└pricingModel
enum
Valores: freefreemiumpaidtrial
└taglineadmite null
object
└shortDescadmite null
object
└longDescadmite null
object
└firstCommentadmite null
object
└topics
array<string>
└promoCodeadmite null
string
└videoUrladmite null
string
└demoUrladmite null
string
└linksadmite null
object
└webApp
string
└appStore
string
└playStore
string
└chromeExtension
string
└macos
string
└windows
string
└socialsadmite null
object
└x
string
└linkedin
string
└github
string
└instagram
string
└youtube
string
└facebook
string
└contactNameadmite null
string
└contactEmailadmite null
string
└gallery
array<string>
└productId
string
└domain
string
└thumbnailUrladmite null
string
└completeness
integer
(0–100)
└missing
array<string>
└createdAt
string
└updatedAt
string
└sites
array<object>
└siteId
string
└domain
string
└syncedThroughadmite null
string
Errores posibles
400invalid_product_input, invalid_url, url_not_public, invalid_email o invalid_gallery
401Error de autenticación
403plan_required, o missing_scope_publish en las operaciones de escritura
404product_not_found
409product_exists (con el productId existente)
429rate_limited — 120 solicitudes por minuto y por clave
Devuelve los textos localizados guardados, los enlaces, los datos de contacto, las imágenes, el grado de completitud y los campos que faltan. Permiso read; no consume créditos. Un producto que no pertenece a este espacio de trabajo también devuelve product_not_found.
Respuesta200
Campo
Tipo
Descripción
success
boolean
data
ProductDetail
└name
string
└url
string
└primaryLanguage
enum
Valores: enzhjakodefresptitrunlpltrarthviid
└businessType
enum
Valores: saastoolecommercecontentserviceother
└launchStatus
enum
Valores: livebeta
└pricingModel
enum
Valores: freefreemiumpaidtrial
└taglineadmite null
object
└shortDescadmite null
object
└longDescadmite null
object
└firstCommentadmite null
object
└topics
array<string>
└promoCodeadmite null
string
└videoUrladmite null
string
└demoUrladmite null
string
└linksadmite null
object
└webApp
string
└appStore
string
└playStore
string
└chromeExtension
string
└macos
string
└windows
string
└socialsadmite null
object
└x
string
└linkedin
string
└github
string
└instagram
string
└youtube
string
└facebook
string
└contactNameadmite null
string
└contactEmailadmite null
string
└gallery
array<string>
└productId
string
└domain
string
└thumbnailUrladmite null
string
└completeness
integer
(0–100)
└missing
array<string>
└createdAt
string
└updatedAt
string
└sites
array<object>
└siteId
string
└domain
string
└syncedThroughadmite null
string
Errores posibles
401Error de autenticación
403plan_required, o missing_scope_publish en las operaciones de escritura
404product_not_found
429rate_limited — 120 solicitudes por minuto y por clave
Requiere el permiso publish. Descarga una imagen pública por HTTP(S) y guarda una copia como miniatura (sustituye la actual) o en la galería (se añade al final, seis como máximo). JPEG, PNG, WebP y SVG, 4 MB como máximo; los SVG se convierten a PNG. El módulo de descarga de imágenes existente bloquea las redes privadas y las redirecciones no seguras. No consume créditos. Importar varias veces a la galería puede crear duplicados: si se ha perdido la respuesta, consulta el producto con GET antes de reintentar.
Cuerpo de la petición
Campo
Tipo
Descripción
urlobligatorio
string
kind
enum
Valores: thumbnailgalleryPor defecto gallery
Respuesta200
Campo
Tipo
Descripción
success
boolean
data
ProductDetail
└name
string
└url
string
└primaryLanguage
enum
Valores: enzhjakodefresptitrunlpltrarthviid
└businessType
enum
Valores: saastoolecommercecontentserviceother
└launchStatus
enum
Valores: livebeta
└pricingModel
enum
Valores: freefreemiumpaidtrial
└taglineadmite null
object
└shortDescadmite null
object
└longDescadmite null
object
└firstCommentadmite null
object
└topics
array<string>
└promoCodeadmite null
string
└videoUrladmite null
string
└demoUrladmite null
string
└linksadmite null
object
└webApp
string
└appStore
string
└playStore
string
└chromeExtension
string
└macos
string
└windows
string
└socialsadmite null
object
└x
string
└linkedin
string
└github
string
└instagram
string
└youtube
string
└facebook
string
└contactNameadmite null
string
└contactEmailadmite null
string
└gallery
array<string>
└productId
string
└domain
string
└thumbnailUrladmite null
string
└completeness
integer
(0–100)
└missing
array<string>
└createdAt
string
└updatedAt
string
└sites
array<object>
└siteId
string
└domain
string
└syncedThroughadmite null
string
Errores posibles
400invalid_product_input o invalid_url
401Error de autenticación
403plan_required, o missing_scope_publish en las operaciones de escritura
404product_not_found
409gallery_full
413image_too_large
415image_type
429rate_limited — 120 solicitudes por minuto y por clave
El historial de envíos, con la actividad más reciente primero. Filtra por producto, por campaña o por una lista de estados separados por comas. byStatus cuenta todas las tareas incluidas en la consulta antes de aplicar el filtro de estado. Gratis.
Parámetros de consulta
Campo
Tipo
Descripción
productId
string
Solo las tareas de este producto.
campaignId
string
status
string
Separados por comas; por ejemplo, prepared,in_progress.
page
integer
Por defecto: 1.
pageSize
integer
Por defecto: 30.
Respuesta200
Campo
Tipo
Descripción
success
enum
Valores: true
data
TaskList
└items
array<Task>
└taskId
string
└campaignId
string
└productId
string
└status
enum
published es lo que tú has declarado. verified es lo que QueryWin ha visto en la página de la ficha (un enlace en los directorios y los directorios de herramientas de IA, una mención en el resto). Mantenlos separados cuando informes de ellos.Valores: plannedpreparedin_progressblockedsubmittedpublishedverifiedfailedskipped
Contenidos obligatorios que faltan en el perfil. Completa el perfil en el panel: la tarea se vuelve a preparar sola.
└listingUrladmite null
string
└markedBy
enum
Quién hizo el último cambio de estado: una persona (o esta API), la extensión del navegador o el propio QueryWin.Valores: userdevicesystem
└hasGenerated
boolean
Existe una versión adaptada a este canal.
└reviewDueAtadmite null
string
Cuándo volver a comprobar después del envío (submittedAt + el plazo de revisión del canal).
└submittedAtadmite null
string
└publishedAtadmite null
string
└verifiedAtadmite null
string
└next
array<string>
Estados que puedes asignar desde el actual mediante POST /v1/tasks/{id}/status.
└target
object
└targetId
string
└name
string
└url
string
└submitUrl
string
└kind
string
└source
enum
Valores: seeduserrivals
└language
string
└requiresBacklink
boolean
└checkadmite null
object
La comprobación que QueryWin hace en la ficha una vez publicada. Es null hasta que la tarea se publica.
└kind
enum
Qué se busca: un enlace al producto (directorios, directorios de herramientas de IA) o una mención de la marca (todos los demás tipos).Valores: link_livemention_seen
└stateadmite null
enum
confirmed = encontrado. unconfirmed = no se encontró en una ronda de comprobaciones (el estado no cambia; comprueba la URL). lost = estaba y ha desaparecido (la tarea pasa a fallida).Valores: confirmedunconfirmedlostnull
Cada campo que pide el formulario del canal, tomado del perfil de producto y recortado a los límites del canal (source: "profile"), más la versión adaptada a ese canal si existe (source: "ai") y las modificaciones hechas en el panel (source: "override"). source: "none" significa que el perfil no tiene nada para ese campo: no lo inventes. Nunca lanza una reescritura y nunca cuesta nada.
Reescribir los contenidos para este canal (consume créditos)
Una pasada de IA que adapta el perfil a este canal concreto: una descripción de directorio más ajustada, el primer comentario del creador, una publicación para una comunidad, un correo de presentación para un editor o, en los sitios citados por la IA, un correo de presentación junto con un párrafo que el responsable de la página podría añadir. Síncrona, unos segundos. Solo usa datos que estén en el perfil; cualquier parte que contenga un enlace que no figure en el perfil se descarta y no se cobra.
Con entradas idénticas se devuelve la versión anterior sin cobrar (cached: true); force: true reescribe igualmente y se cobra. Los contenidos del perfil que devuelve GET /v1/tasks/{id} suelen bastar para los directorios; reescribe cuando el canal pida otro tono.
Devuelve HTTP 200 con ok: false y failure: "engine_failed" cuando nada pasa la validación. La falta de créditos, en cambio, sí es un error 402 real.
Cuerpo de la petición
Campo
Tipo
Descripción
confirmSpendobligatorio
integer
Tope de autorización en créditos, con la misma semántica que en los esquemas y los borradores. Consulta el precio en GET /v1/usage (materials.pricePerTask). Obligatorio aunque te queden generaciones gratuitas. (min 0)
force
boolean
Reescribe aunque no haya cambiado nada desde la última versión. Se cobra.
Respuesta200
Campo
Tipo
Descripción
success
enum
Valores: true
data
WriteMaterialsOutcome
└ok
boolean
└failure
enum
Presente cuando ok es false. No se cobra nada.Valores: engine_failedengine_unavailable
└cached
boolean
Las entradas no han cambiado: se ha devuelto la versión anterior y no se ha cobrado nada.
└freeUsed
boolean
└creditsSpent
integer
└task
TaskDetail
Errores posibles
400confirm_spend_required o confirm_spend_too_low (el cuerpo incluye el price actual)
401Error de autenticación
402insufficient_credits — el cuerpo incluye requiredCredits, currentBalance, shortfall
403missing_scope_spend — esta clave no tiene el permiso spend
404task_not_found
429rate_limited o daily_limit_reached (el cuerpo incluye resetAt)
Registra el resultado de un envío que has hecho con tus propias cuentas. QueryWin nunca envía nada por su cuenta. Marca submitted cuando hayas enviado el formulario y, después, published con la URL de la ficha (la ficha o la publicación en sí, no la página de inicio del sitio) cuando ya esté publicada; unas 72 horas después, QueryWin vuelve a comprobar esa página en busca de un enlace a tu producto (directorios, directorios de herramientas de IA) o de una mención (todos los demás tipos) y marca verified por su cuenta. Tú no puedes asignar ese estado.
blocked significa “necesita a una persona”: indica reason (login, captcha, payment, missing_material, other). failed / skipped cierran la tarea; prepared la vuelve a dejar pendiente. Las transiciones que la máquina de estados no permite devuelven **409 transition_not_allowed**; el campo next de la tarea indica qué estados se permiten desde el actual.
Cuerpo de la petición
Campo
Tipo
Descripción
statusobligatorio
enum
verified no se puede asignar: lo asigna QueryWin tras volver a comprobar la ficha.Valores: preparedin_progressblockedsubmittedpublishedfailedskipped
listingUrl
string
Obligatorio para published: la ficha o la publicación tal como está en línea, no la página de inicio del sitio. Solo http/https. Opcional con submitted si ya la conoces.
note
string
reason
enum
Obligatorio para blocked.Valores: logincaptchapaymentmissing_materialother