Toda lista tiene la misma forma que el resto de la API: un arreglo
data, un
booleano has_more y un cursor opaco, de más reciente a más antiguo, hasta 50
filas por página.
Registro de solicitudes
Cada llamada que tus llaves hacen a/v1/ queda registrada: el método y la ruta,
el estatus con que respondimos, el error.code cuando falló, cuánto tardó, qué
llave la hizo (sus primeros caracteres, nunca el secreto) y si fue una llamada de
prueba. Cada fila trae un request_id, el valor del encabezado X-Request-Id de la
respuesta que recibiste, así que es lo que debes citar si alguna vez le escribes
a soporte.
Ese id es de Listo: toda respuesta lo trae en X-Request-Id, y todo
error lo repite en el cuerpo como error.request_id, junto a un
doc_url que lleva a la página que explica el error. Si mandas tu propio
X-Request-Id, regresa en la respuesta (Listo limpia los caracteres que no acepta)
y es el id que se guarda, así que puedes cruzarlo con tus propios registros. El id
de un balanceador u otro servicio delante del nuestro no es este. Para encontrar
una llamada a partir de un id que copiaste de un error o de un registro, filtra la
lista con request_id (coincidencia exacta) o pégalo en el buscador de la página
Registro de solicitudes del panel.
Una llamada a una herramienta del servidor MCP escribe las mismas filas, y cada una
trae el X-Request-Id de la respuesta de /mcp que recibiste. Una herramienta de dos
pasos son dos peticiones a /mcp con dos ids. Una vista previa que llama a la API para leer tus datos
escribe una fila GET con el id de la vista previa; una que no llama a ningún endpoint
no escribe fila. La confirmación escribe la fila de la llamada que hizo el trabajo, y
confirmar el mismo token otra vez devuelve el primer resultado y no escribe fila.
status (failed es toda respuesta de 400 en adelante,
succeeded es el resto), endpoint (el valor exacto que muestra una fila, como
api/v1/deliveries#create), request_id (una sola llamada, por su id exacto), y
created_after y created_before, ambos instantes ISO-8601. Un status que no sea ninguno de los dos valores no coincide
con nada, y una fecha que no se pueda leer es un 422 validation_failed que
nombra el parámetro.
GET /v1/request_logs/{id} agrega
los dos cuerpos, request_body y response_body, exactamente como se guardaron.
Esa es la respuesta a “por qué se rechazó esto”: el cuerpo de la respuesta es el
sobre de error que recibiste, y el cuerpo de la solicitud es lo que realmente
enviaste, que muchas veces no es lo que querías enviar.
Qué se registra y qué no:
- Las llamadas que identificaron una llave. Una llamada sin llave, o con una equivocada o revocada, no pertenece a nadie y no está en tu registro, y tampoco una llamada rechazada por límite de frecuencia. Si estás seguro de haber hecho una llamada y no aparece, la razón es una de esas.
- Las llaves y los enlaces de un solo uso se enmascaran. Una llave de API en
cualquier cuerpo aparece como sus primeros caracteres seguidos de
[key masked], y el enlace de la respuesta dePOST /v1/connect_requestso de una llamada de onboarding de Stripe aparece como[redacted: one-time link], porque tener ese enlace es la autoridad para usarlo. Lo que tú recibiste no se toca; solo se enmascara la copia guardada. Los encabezados nunca se guardan. - Un cuerpo se corta a 64 KB. Uno más largo se guarda como un objeto con
_listo_truncated: true, losoriginal_bytesque tenía y los primeros 64 KB de sutext, así que siempre se te avisa que no estás leyendo todo. - Las tres lecturas de depuración no guardan cuerpos. Leer el registro de
solicitudes, los eventos o las entregas de webhook también queda registrado,
pero sin cuerpos: si no, el registro se copiaría a sí mismo cada vez que lo
lees. Su
request_bodyyresponse_bodysonnull. - Las filas se conservan. No hay ventana de retención contra la que correr.
Una fila de antes de que existiera este registro no tiene
pathnirequest_id, ambosnull.
Eventos
GET /v1/events lista lo que Listo
emitió para ti, lo haya recibido o no tu endpoint, y
GET /v1/events/{id} lee uno. Cada
elemento es exactamente el sobre de webhook que recibe tu endpoint (id, type,
created_at, data), así que puedes comparar lo que guardaste con lo que quisimos
decirte.
Se acota con type (un nombre publicado, como delivery.status_changed),
delivery_id (los eventos de un envío; un id que no es tuyo da 404), y
created_after y created_before.
delivery.courier_location queda fuera a menos que lo pidas con type. Se emite
aproximadamente cada veinte segundos por cada viaje en camino y nunca se vuelve a
enviar, así que enterraría todo lo demás en la página.
Entregas de webhook
Un evento es algo que Listo decidió contarte. Una entrega de webhook es un intento de contártelo: la URL a la que hicimosPOST, el estatus con que contestó
tu endpoint, los primeros 500 caracteres de su cuerpo, cuánto tardó y si lo
contamos como exitoso. GET /v1/webhook_deliveries
las lista.
status_code es null cuando nada contestó (un tiempo agotado, una conexión
rechazada, un error de certificado), y error_message dice cuál. attempt cuenta
los intentos del evento desde 1, incluidos los reintentos que Listo hace por su
cuenta cuando tu endpoint falla (ve recibe y verifica webhooks).
Se acota con event_id (un evento que no es tuyo da 404), status (failed o
succeeded) y created_after y created_before.
El orden habitual de preguntas es: encuentra el evento en la lista, mira sus
intentos, y lee status_code y response_body para ver qué dijo tu endpoint. Un
400 de tu propia verificación de firma, un 5xx, un tiempo agotado y un evento
sin ningún intento (no había endpoint configurado para el modo) son cuatro
problemas distintos, y la fila del intento los distingue.
Reenviar un evento
POST /v1/events/{id}/resend envía un
evento a tu endpoint una vez más, sin cuerpo. Responde 202 con el sobre del
evento, y el envío ocurre enseguida: el intento nuevo aparece en
GET /v1/webhook_deliveries con resent: true, numerado después del último del
evento.
- El mismo evento. Tiene el mismo
idy un cuerpo idéntico byte por byte, así que un receptor que deduplica porid, como debe, lo trata como el evento que ya vio. Para ejercitar tu manejador otra vez, borra primero ese registro. - Firmado ahora. La firma lleva la hora actual y el secreto vigente, así que verifica aunque el evento tenga días.
- Enviado a la URL actual. Si cambiaste tu endpoint desde que ocurrió el evento, el reenvío va al nuevo.
- Una sola vez. No hay reintentos detrás. Si tu endpoint falla, ves un intento fallido y tú decides qué sigue.
- Con límite. Un evento se puede reenviar 5 veces por hora. El sexto se
rechaza con
429 resend_limit_reached, que se puede reintentar pasada la hora.Retry-Afterdice cuántos segundos faltan para que puedas enviar de nuevo. - Nunca una posición de repartidor. Un evento
delivery.courier_locationlo reemplaza el siguiente en segundos, así que pedir reenviar uno es409 event_not_resendable. - Necesita un endpoint. Sin URL de webhook configurada para el modo de la
llave, la respuesta es
409 webhook_endpoint_not_configured.
Enviar un webhook de prueba
No necesitas un pedido para ejercitar tu endpoint.POST /v1/test_webhooks envía un
evento sintético de cualquier tipo publicado a la URL de webhook del modo de la
llave.
202 con el evento tal como lo recibe tu endpoint, y el intento aparece
en GET /v1/webhook_deliveries como con cualquier otro evento:
test antes de actuar.
"test": trueva en el sobre. Un evento real no trae ese campo. Revísalo antes de hacer cualquier cosa con consecuencias.- Sus ids no resuelven a nada.
dataes una muestra realista del tipo, pero el envío, la tienda, el retiro o la cotización que nombra no existe, así queGET /v1/deliveries/{id}con ese id responde404. Un manejador que vuelve a leer el objeto, como debe, no encontrará nada, y esa es la prueba de que es de prueba. - Funciona en los dos modos. Una llave de prueba envía a tu endpoint de prueba y una llave de producción envía al de producción, así que puedes verificar un endpoint de producción sin hacer un pedido. Ese endpoint de producción sí recibe el evento de prueba, así que asegúrate de que ahí se ignore.
- Tiene límite. 30 eventos de prueba por hora por modo, y luego
429 test_webhook_limit_reached, yRetry-Afterdice cuántos segundos faltan para que puedas enviar de nuevo. Untypeque no es un nombre publicado es422 validation_failedconparam: "type", y un modo sin URL de webhook es409 webhook_endpoint_not_configured.
GET /v1/events como cualquier otro, con
test: true.
Con qué rechazan estos endpoints
En el panel
Los mismos registros están en el panel de socios, para el modo que tengas seleccionado.- Registro de solicitudes lista tus llamadas con los mismos filtros, y cada llamada se abre para ver sus cuerpos de solicitud y respuesta.
- Webhooks guarda la configuración del endpoint y muestra cada intento. Reenviar está en cada intento de un evento que se puede reenviar, y Enviar webhook de prueba manda un evento sintético al endpoint de arriba.
Depura con tu asistente de IA
Si ya conectaste un asistente de IA, él mismo puede leer los tres registros, así que puedes preguntarle en palabras sencillas: “¿por qué falló mi última reserva?”, “¿Listo envió el evento de entregado de ese pedido?”, “¿qué respondió mi endpoint?”. Usa los mismos registros y los mismos límites que los endpoints de arriba:resend_event y send_test_webhook actúan de inmediato: a diferencia de una
reserva o un retiro no mueven dinero, así que el asistente no te pide
confirmarlos. Conservan los límites descritos arriba, y el intento que provocan
se lee con list_webhook_deliveries. Cuando a un asistente se le indica esperar
por un límite, el error trae retry_after_seconds, los segundos que faltan para
que pueda volver a intentar.
Una forma de trabajar
- Reproduce el problema con una llave de prueba, para que nada real esté en juego.
- Abre la llamada en el registro de solicitudes. El estatus, el
error.codey elmessagedel cuerpo de la respuesta, y tu propio cuerpo de solicitud, contestan la mayoría de las preguntas. - Si era un evento que esperabas, encuéntralo en
GET /v1/events, y luego sus intentos enGET /v1/webhook_deliveries. - Arregla el manejador y luego reenvía ese evento, o envía un webhook de
prueba, hasta que el intento diga
succeeded. - Comprueba lo mismo en el endpoint de producción con un webhook de prueba antes de depender de él.