News

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

  1. En el admin de Shopify, abrir Panza y navegar a Integraciones > Acceso por API.
  2. Crear una clave con un nombre que identifique el servicio conectado (por ejemplo, "Klaviyo" o "Zapier").
  3. 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 Puntos a otorgar. Mínimo 1, máximo 1.000.000.
description string 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:

  1. Cliente existente en la tienda con ese correo.
  2. Cliente existente en Shopify que aún no está sincronizado.
  3. 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.
Importante: enviar "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 de source como tipo de transacción (por ejemplo, "klaviyo").
  • Sin source: se muestra una etiqueta genérica traducida según el idioma del cliente.
  • description se 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 cuerpo200 OK con la transacción original y "idempotent_replay": true. No se otorgan puntos nuevos.
  • Mismo idempotency_key + cuerpo diferente422 con motivo idempotency_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 429 con el encabezado Retry-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

  1. Crear una clave en Integraciones > Acceso por API con el nombre del servicio.
  2. Guardar la clave en un gestor de secretos.
  3. Enviar idempotency_key en toda solicitud generada por eventos.
  4. Manejar 200 con idempotent_replay: true como éxito (no como duplicado).
  5. Reintentar 429 y 5xx con backoff y el mismo idempotency_key; no reintentar 4xx sin corregir.
  6. Enviar email_marketing_consent: "subscribed" solo cuando exista consentimiento real del cliente.
  7. Usar source para que el comerciante y el cliente identifiquen el origen de los puntos.