11. API de puntos — Referencia para desarrolladores
API de puntos de Panza
La API de puntos permite que servicios externos (CRMs, herramientas de automatización, o el backend propio de la tienda) otorguen puntos a los clientes del programa de lealtad de una tienda.
-
URL base:
https://app.getpanza.com - Formato: JSON (solicitud y respuesta)
- Alcance: solo otorgar puntos. La API no permite descontar puntos ni consultar saldos.
Autenticación
Todas las solicitudes requieren una clave de API en el encabezado Authorization:
Authorization: Bearer pza_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Obtener una clave
- En el admin de Shopify, abrir Panza y navegar a Integraciones > Acceso por API.
- Crear una clave con un nombre que identifique el servicio conectado (por ejemplo, "Klaviyo" o "Zapier").
- Copiar la clave completa inmediatamente: se muestra una sola vez y no puede recuperarse después. Si se pierde, hay que crear una nueva.
Recomendaciones
- Crear una clave por servicio conectado. Cada clave puede revocarse de forma independiente sin afectar a las demás.
- Guardar la clave en un gestor de secretos; nunca en el código fuente ni en el frontend.
- La página de claves muestra el último uso de cada clave — útil para detectar claves huérfanas o integraciones inactivas.
- Las claves revocadas dejan de funcionar de inmediato. Si la app se desinstala de la tienda, las claves quedan inactivas mientras dure la desinstalación y vuelven a funcionar al reinstalar.
Otorgar puntos
POST /api/v1/points
Cuerpo de la solicitud
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
customer_email |
string | Uno de los dos | Correo del cliente. Si no existe, el cliente se crea automáticamente en Shopify. |
customer_id |
integer | Uno de los dos | ID numérico del cliente en Shopify. Debe existir; la API no crea clientes por ID. |
points |
integer | Sí | Puntos a otorgar. Mínimo 1, máximo 1.000.000. |
description |
string | Sí | Texto que el cliente verá en su historial de transacciones. Máximo 255 caracteres. |
source |
string | No | Etiqueta de la integración (por ejemplo, "klaviyo"). Se muestra como el tipo de transacción en el historial del cliente. Máximo 64 caracteres. |
idempotency_key |
string | No | Clave de reintento segura. Ver Idempotencia. Máximo 255 caracteres. |
email_marketing_consent |
string | No |
"subscribed" o "not_subscribed" (predeterminado). Solo aplica si el cliente se crea en Shopify; nunca modifica clientes existentes. |
Debe enviarse exactamente uno de customer_email o customer_id.
Ejemplo
curl -X POST https://app.getpanza.com/api/v1/points \
-H "Authorization: Bearer pza_..." \
-H "Content-Type: application/json" \
-d '{
"customer_email": "cliente@ejemplo.com",
"points": 100,
"description": "Suscripción al boletín",
"source": "klaviyo",
"idempotency_key": "evt_123",
"email_marketing_consent": "subscribed"
}'
Respuesta exitosa — 201 Created
{
"transaction": {
"id": 4521,
"points": 100,
"description": "Suscripción al boletín",
"source": "klaviyo",
"idempotency_key": "evt_123",
"created_at": "2026-07-01T18:30:00+00:00"
},
"customer": {
"shopify_customer_id": 7412589630,
"email": "cliente@ejemplo.com"
},
"available_points": 350,
"idempotent_replay": false
}
available_points es el saldo total disponible del cliente después de la transacción.
Comportamiento
Resolución del cliente (por correo)
Cuando se identifica al cliente por customer_email, la API resuelve en este orden:
- Cliente existente en la tienda con ese correo.
- Cliente existente en Shopify que aún no está sincronizado.
-
Creación del cliente en Shopify. El nuevo cliente aparece en el admin de Shopify de la tienda; si la solicitud incluyó
email_marketing_consent: "subscribed", se registra como suscrito a email marketing con la fecha de la solicitud como evidencia de consentimiento.
"subscribed" es una afirmación de que el servicio que llama posee el consentimiento del cliente. El valor solo se aplica al crear el cliente; los clientes existentes nunca cambian de estado de marketing.Clientes que aún no se han unido al programa
Los puntos se otorgan aunque el cliente no se haya registrado en el programa de lealtad. Quedan disponibles en su cuenta y aparecen en su historial cuando se registre. El bono de registro del programa no se otorga por API: se entrega cuando el cliente visita el panel de lealtad por primera vez, como en cualquier otro registro.
Etiqueta en el historial del cliente
- Con
source: el historial muestra el valor desourcecomo tipo de transacción (por ejemplo, "klaviyo"). - Sin
source: se muestra una etiqueta genérica traducida según el idioma del cliente. -
descriptionse muestra siempre como el detalle de la transacción.
Límites de otorgamiento
El comerciante puede configurar un límite de cuántas veces un cliente puede recibir puntos por API en un período (ventana móvil). Al alcanzarlo, la API responde 422 con motivo limit_reached.
Idempotencia
Enviar idempotency_key hace que los reintentos sean seguros: si la solicitud se repite (por un timeout, un error de red, o una cola que reintenta), los puntos no se duplican.
-
Mismo
idempotency_key+ mismo cuerpo →200 OKcon la transacción original y"idempotent_replay": true. No se otorgan puntos nuevos. -
Mismo
idempotency_key+ cuerpo diferente →422con motivoidempotency_key_reused. Esto indica un error en el integrador (la clave debe ser única por evento).
La clave es única por tienda. Se recomienda usar el ID del evento del sistema de origen (por ejemplo, el ID del evento de Klaviyo o del job de Zapier).
Patrón recomendado de reintento: ante respuestas 5xx o 429, reintentar la misma solicitud con el mismo idempotency_key usando backoff exponencial.
Errores
Los errores de negocio responden con un cuerpo uniforme:
{
"error": "limit_reached",
"detail": "Transaction limit reached"
}
| HTTP | error |
Cuándo ocurre | Acción sugerida |
|---|---|---|---|
| 400 | — (errores de validación por campo) | Cuerpo inválido: falta un campo, puntos fuera de rango (1–1.000.000), ambos o ningún identificador de cliente. | Corregir la solicitud. No reintentar sin cambios. |
| 401 | — | Clave ausente, inválida o revocada. | Verificar la clave en Integraciones > Acceso por API. |
| 403 | — | La app está desinstalada de la tienda. | La clave vuelve a funcionar al reinstalar la app. |
| 404 | customer_not_found |
customer_id no corresponde a ningún cliente de la tienda. |
Verificar el ID, o usar customer_email para crear el cliente. |
| 422 | idempotency_key_reused |
La clave de idempotencia ya se usó con un cuerpo diferente. | Usar una clave única por evento. |
| 422 | inactive_program |
El programa de lealtad de la tienda está desactivado. | El comerciante debe activar el programa en Panza. |
| 422 | member_excluded |
El cliente está excluido del programa de lealtad. | No reintentar; es una decisión del comerciante. |
| 422 | limit_reached |
El cliente alcanzó el límite configurado de otorgamientos por API. | No reintentar hasta que pase la ventana del límite. |
| 422 | requirements_not_met |
La transacción no cumple otro requisito del programa. | Revisar detail. |
| 429 | — | Más de 60 solicitudes por minuto con la misma clave. | Esperar el valor del encabezado Retry-After y reintentar. |
| 502 | shopify_error |
Shopify rechazó o no respondió la búsqueda/creación del cliente (correo inválido, límite de la API de Shopify, error transitorio). | Reintentar con backoff usando el mismo idempotency_key. Si persiste, revisar detail. |
Límite de velocidad
- 60 solicitudes por minuto por clave de API.
- Al excederlo, la API responde
429con el encabezadoRetry-After(segundos de espera). - El límite es por clave: servicios distintos con claves distintas no compiten entre sí.
Lista de verificación para integrar
- Crear una clave en Integraciones > Acceso por API con el nombre del servicio.
- Guardar la clave en un gestor de secretos.
- Enviar
idempotency_keyen toda solicitud generada por eventos. - Manejar
200conidempotent_replay: truecomo éxito (no como duplicado). - Reintentar
429y5xxcon backoff y el mismoidempotency_key; no reintentar4xxsin corregir. - Enviar
email_marketing_consent: "subscribed"solo cuando exista consentimiento real del cliente. - Usar
sourcepara que el comerciante y el cliente identifiquen el origen de los puntos.