Referencia de la API
Base: https://reviews.leadit.tech/api/v1. Todas las peticiones van firmadas. La columna Permiso es el alcance mínimo de la llave.
Resumen
Sección titulada «Resumen»| Método | Ruta | Permiso | Para qué |
|---|---|---|---|
POST |
/review-requests |
moderate |
Pedir el enlace de un pedido |
GET |
/review-requests |
read |
Listar solicitudes y lo que cambió |
POST |
/review-requests/{id}/dispatched |
moderate |
Confirmar que lo mandaste |
POST |
/review-requests/{id}/send-now |
moderate |
Enviar ahora |
POST |
/review-requests/{id}/cancel |
moderate |
Cancelar |
POST |
/reviews |
moderate |
Crear una reseña |
GET |
/reviews |
read |
Listar y filtrar reseñas |
GET |
/reviews/{id} |
read |
Una reseña |
PATCH |
/reviews/{id} |
moderate |
Moderar y responder |
DELETE |
/reviews/{id} |
full |
Borrar |
POST |
/reviews/import |
full |
Importar hasta 1,000 reseñas |
POST |
/uploads |
moderate |
Subir una foto o un video |
POST |
/uploads/{id}/complete |
moderate |
Avisar que ya se subió |
GET |
/stats |
read |
Las métricas de Inicio |
GET |
/settings |
read |
Ajustes, flujo y moderación |
PATCH |
/settings |
full |
Cambiarlos |
GET |
/locations |
read |
Sucursales activas |
GET |
/webhook-deliveries |
read |
Entregas del webhook |
POST |
/webhook-deliveries/{id}/retry |
full |
Reintentar una entrega |
Listas y paginación
Sección titulada «Listas y paginación»Las listas (GET /review-requests, GET /reviews, GET /webhook-deliveries) comparten tres parámetros y van ordenadas por la última vez que cambiaron:
| Parámetro | Qué hace |
|---|---|
since |
Fecha ISO 8601: trae lo que cambió desde entonces. Ideal para sincronizar sin perder nada. |
limit |
De 1 a 100. Por defecto, 50. |
cursor |
El next_cursor de la página anterior. |
{ "data": [ … ], "next_cursor": "MjAyNi0xMC0xNlQxNjowMDowMC4wMDBafGNtMms4eDFmMzAwMDE" }Cuando next_cursor es null, ya no hay más.
Solicitudes
Sección titulada «Solicitudes»Pedir el enlace de un pedido
Sección titulada «Pedir el enlace de un pedido»POST /review-requests es el corazón de la API: le das un pedido y te devuelve su enlace.
{ "order": { "shopify_order_id": "gid://shopify/Order/5812345678901" }, "channel": "api", "locale": "es", "expires_in_days": 45}| Campo | Qué es | |
|---|---|---|
order.shopify_order_id |
obligatorio | El gid o el número de la orden. |
channel |
opcional | api (por defecto), leadit_whatsapp o email. |
locale |
opcional | es o en: el idioma del formulario. También cambia el de una solicitud que ya existía. |
expires_in_days |
opcional | De 1 a 365. Solo cuenta al crearla. |
Respuesta: 201 si la creamos, 200 si el pedido ya tenía solicitud (la misma, con el mismo enlace). El body es la solicitud, igual que el data de los eventos de solicitud.
- Pedir el enlace no cambia la agenda. Si nunca confirmas con
/dispatched, la solicitud sale en su fecha por el canal de la tienda. - Si la orden no tenía solicitud, la creamos sin pasar por los filtros de la app: pedirla es una decisión tuya.
- La orden tiene que existir en Shopify y no estar cancelada. Si no la encontramos:
404 order_not_found.
Confirmar que lo mandaste
Sección titulada «Confirmar que lo mandaste»POST /review-requests/{id}/dispatched, sin body. La solicitud sale de la agenda y empiezan a correr los recordatorios. Repetirla no cambia nada.
Enviar ahora
Sección titulada «Enviar ahora»POST /review-requests/{id}/send-now, sin body. Igual que Enviar ahora en Solicitudes: la fecha pasa a este instante. Solo sirve con una solicitud agendada o fallida; si no, 409 invalid_state.
Cancelar
Sección titulada «Cancelar»POST /review-requests/{id}/cancel, sin body. Una solicitud ya contestada o vencida responde 409 request_closed.
GET /review-requests?status=due,dispatched&since=2026-10-01T00:00:00Z
status acepta varios, separados por coma: scheduled, due, paused, dispatched, opened, partial, responded, expired, cancelled, failed. Cada solicitud trae además updated_at.
Reseñas
Sección titulada «Reseñas»Crear una reseña
Sección titulada «Crear una reseña»POST /reviews, por ejemplo con una reseña que tu cliente dejó en otro canal.
{ "order": { "shopify_order_id": "5812345678901" }, "product": { "sku": "SUD-ARENA-M" }, "rating": 5, "title": "Muy cómoda", "body": "La tela es suavecita por dentro.", "author": { "name": "María G.", "email": "maria@correo.com" }, "language": "es"}- El producto se busca en este orden:
product.shopify_product_id,product.sku,product.handley, si la orden tiene un solo producto, la orden. verified_purchaseno se manda: lo calculamos con la orden real de Shopify.- Sin orden verificada, la reseña queda pendiente y espera a que alguien la apruebe, sea de 1 o de 5 estrellas.
- Una reseña por producto por orden: la segunda responde
409 review_existscon el id de la primera. author.namees obligatorio cuando no hay orden.- Acepta
Idempotency-Key.
Respuesta: 201 con la reseña. Para agregarle fotos o videos, sigue con /uploads.
Listar y filtrar
Sección titulada «Listar y filtrar»GET /reviews?status=pending,flagged&rating=1&since=…
| Parámetro | Valores |
|---|---|
status |
pending, published, rejected, spam, private y flagged (pendientes con alguna marca: teléfono, correo, palabra bloqueada…). Varios con coma. |
kind |
product o store. |
product_id |
El gid o el número del producto. |
rating |
De 1 a 5. |
source |
request_link, qr_store, qr_location, manual, import, api o pos. |
Una reseña
Sección titulada «Una reseña»GET /reviews/{id} devuelve la reseña con sus marcas, su respuesta y sus fotos y videos.
Moderar y responder
Sección titulada «Moderar y responder»PATCH /reviews/{id}
{ "status": "rejected", "rejection_reason": "Habla de otro producto." }| Campo | Qué hace |
|---|---|
status |
published, rejected o spam. |
rejection_reason |
Obligatorio al rechazar: de 3 a 500 caracteres. |
merchant_reply |
Tu respuesta pública, hasta 2,000 caracteres. null la quita. |
Un cambio que la moderación no permite responde 409 invalid_state.
DELETE /reviews/{id}. Llave full.
Importar en lote
Sección titulada «Importar en lote»POST /reviews/import con { "reviews": [ … ] }: hasta 1,000 reseñas y 5 MB por llamada. Llave full. Acepta Idempotency-Key.
Cada reseña lleva external_id, product, rating, title, body, author.name, created_at (obligatorio) y, si los tienes, order.shopify_order_id (puede tener más de 60 días), author.email, status, verified_purchase, incentivized, reply.body, reply.replied_at, photos (hasta 5 URLs https) y videos (1).
{ "created": 998, "existing": 1, "rejected": 1, "results": [ { "index": 0, "status": "created", "review_id": "cm2k…" }, { "index": 1, "status": "exists", "review_id": "cm2j…" }, { "index": 2, "status": "rejected", "error": { "code": "product_not_found", "message": "…" } } ]}Una reseña mala no tumba a las demás, y mandar el mismo lote otra vez devuelve todo como exists: reintentar no duplica.
Fotos y videos
Sección titulada «Fotos y videos»Se suben directo a nuestro almacenamiento, en tres pasos:
POST /uploadscon{ "review_id": "cm2k…", "content_type": "image/jpeg", "bytes": 2483123 }. Responde201conmedia_idyupload: el método (PUT), la URL firmada y las cabeceras.- Sube el archivo con un
PUTaupload.url, con esas cabeceras. POST /uploads/{media_id}/complete. Lo procesamos en segundo plano.
| Tipo | Formatos | Máximo |
|---|---|---|
| Foto | image/jpeg, image/png, image/heic, image/heif |
15 MB, hasta 5 por reseña |
| Video | video/mp4, video/quicktime |
100 MB y 90 segundos, 1 por reseña |
Métricas
Sección titulada «Métricas»GET /stats?period=30 (7, 30 o 90 días): lo mismo que se ve en Inicio.
{ "period_days": 30, "since": "2026-09-16T16:00:00.000Z", "metrics": { "requests_sent": 412, "reviews_collected": 131, "response_rate": 31.8, "with_media_rate": 42.7, "average_rating": 4.7 }, "pending_reviews": 6, "alerts": { "failed_requests": 0, "webhook_dlq": 0, "flagged_reviews": 2 }, "setup": { "channel_connected": true, "timing_saved": true, "form_saved": true, "first_request_sent": true }}Ajustes
Sección titulada «Ajustes»GET /settings devuelve los ajustes de la tienda, el flujo (tiempos y recordatorios) y la moderación (umbral y palabras bloqueadas). PATCH /settings cambia solo lo que mandes, con la misma validación que el admin; un campo que no existe responde 422 con su ruta en details. Llave full.
Sucursales
Sección titulada «Sucursales»GET /locations devuelve las sucursales activas, con sus reseñas internas y si la pregunta de sucursal está encendida.
Webhooks
Sección titulada «Webhooks»GET /webhook-deliveries?status=dlq lista las entregas del webhook (pending, delivered, failed, dlq). POST /webhook-deliveries/{id}/retry reintenta una a mano, igual que el botón de Canales. Llave full.