Ir al contenido

Referencia de la API

Pro

Base: https://reviews.leadit.tech/api/v1. Todas las peticiones van firmadas. La columna Permiso es el alcance mínimo de la llave.

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

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.

POST /review-requests es el corazón de la API: le das un pedido y te devuelve su enlace.

Petición
{
"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.

POST /review-requests/{id}/dispatched, sin body. La solicitud sale de la agenda y empiezan a correr los recordatorios. Repetirla no cambia nada.

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.

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.

POST /reviews, por ejemplo con una reseña que tu cliente dejó en otro canal.

Petición
{
"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.handle y, si la orden tiene un solo producto, la orden.
  • verified_purchase no 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_exists con el id de la primera.
  • author.name es obligatorio cuando no hay orden.
  • Acepta Idempotency-Key.

Respuesta: 201 con la reseña. Para agregarle fotos o videos, sigue con /uploads.

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.

GET /reviews/{id} devuelve la reseña con sus marcas, su respuesta y sus fotos y videos.

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.

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).

Respuesta
{
"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.

Se suben directo a nuestro almacenamiento, en tres pasos:

  1. POST /uploads con { "review_id": "cm2k…", "content_type": "image/jpeg", "bytes": 2483123 }. Responde 201 con media_id y upload: el método (PUT), la URL firmada y las cabeceras.
  2. Sube el archivo con un PUT a upload.url, con esas cabeceras.
  3. 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

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 }
}

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.

GET /locations devuelve las sucursales activas, con sus reseñas internas y si la pregunta de sucursal está encendida.

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.