Para empezar
La API habla JSON y todas sus rutas cuelgan de esta dirección. Si es la primera vez que conectas una caja, empieza por la
guía paso a paso.
https://www.simplepuntos.com/api/v1
Cada petición lleva una llave de API en el encabezado Authorization. Las llaves se crean en
Configuración › Conexiones; usa una por caja para poder revocar una sin afectar a las demás.
Authorization: Bearer pts_…
Para programar y probar, crea una llave de prueba (empieza con pts_test_). Trabaja con una copia de las reglas
de Café Brisa: no ve a sus clientes reales, el código de canje siempre es 000000 y no manda WhatsApp ni correos.
Cuando la caja esté lista, cámbiala por una llave normal.
- Los sellos viajan como texto decimal con 0 decimales (
"120"); los pesos siempre con dos ("60.25"). Al mandarlos puedes usar texto o número, sin más decimales de esos.
- Las fechas van en ISO 8601 con zona horaria y los ids son UUID.
- Hasta 300 peticiones por minuto por llave; arriba de eso responde
429.
- Manda el cuerpo como JSON con
Content-Type: application/json. Los errores siempre responden JSON, también un cuerpo mal formado o una ruta que no existe (mira errores).
- Los ejemplos usan variables de la terminal:
$LLAVE para tu llave y $CLIENTE, $CANJE y $MOVIMIENTO para los ids que te devuelve la API.
- Si prefieres importarla en Postman o generar tu cliente, la misma API está descrita en OpenAPI.
Leer las reglas del programa
GET/program
Lo que tu caja necesita para calcular y mostrar antes de cobrar, tal como está hoy en la configuración de Café Brisa.
Léelo al arrancar la caja en vez de copiar las reglas a mano: si el dueño las cambia, la caja se entera sola.
Lo que no aplica a la tarjeta de sellos viene en null.
stamps_per_card: los sellos de una tarjeta; stamp_rewards: en qué sello se gana cada premio.
points_expire_after_months: los meses sin compras tras los que vence el saldo; null si no vence.
identifier: con qué se identifica al cliente (phone, email o text) y, si hay, el patrón que debe cumplir.
sandbox: true mientras la caja use una llave de prueba; muéstralo en pantalla para que nadie cobre con ella.
curl https://www.simplepuntos.com/api/v1/program \
-H "Authorization: Bearer $LLAVE"
{
"business": "Café Brisa",
"sandbox": false,
"program": "sellos",
"points_label": "sellos",
"points_precision": 0,
"points_per_100": null,
"point_value": null,
"otp": null,
"points_expire_after_months": null,
"stamps_per_card": 10,
"stamp_rewards": [
{
"stamps": 5,
"reward": "Bebida al 50%"
},
{
"stamps": 10,
"reward": "Bebida gratis"
}
],
"identifier": {
"kind": "phone",
"label": "Celular",
"pattern": null
},
"portal_url": "https://www.simplepuntos.com/c/tu-negocio"
}
Escanear la tarjeta
En Café Brisa cada cliente se identifica por su celular
(teléfono celular). Es único por cliente: con él se busca, se acumula y se canjea.
- El lector de código de barras o QR funciona como un teclado: escribe el identificador y manda Enter.
- Deja el cursor en un campo de búsqueda; al recibir el Enter, el punto de venta llama
POST /members/lookup con lo que leyó.
- La respuesta trae el
id del cliente: con él van todas las demás rutas (/members/{id}/earnings, /members/{id}/redemptions…).
- Si responde
404, el cliente no está registrado: ofrécele registrarse con POST /members.
El celular viaja en el cuerpo de la petición y nunca en la dirección, para que no quede escrito en los registros
de servidores y proxies.
El teléfono se acepta tal como lo teclea el cajero: 229 123 4567 encuentra a +522291234567.
Clientes
Buscar un cliente
POST/members/lookup
Devuelve sus datos, su metadata y los sellos que lleva en su tarjeta (balance); balance_amount viene vacío porque los sellos no valen pesos.
curl -X POST https://www.simplepuntos.com/api/v1/members/lookup \
-H "Authorization: Bearer $LLAVE" \
-H "Content-Type: application/json" \
-d '{
"identifier": "229 123 4567"
}'
{
"id": "0199a1b2-3c4d-7e5f-8a9b-0c1d2e3f4a5b",
"identifier": "+522291234567",
"name": "María López",
"email": "maria@correo.mx",
"phone": "+522291234567",
"metadata": {
"mascota": "Firulais",
"sucursal": "Riviera"
},
"balance": "4",
"balance_amount": null,
"created_at": "2026-09-14T11:32:08.120-06:00",
"updated_at": "2026-10-01T18:05:44.310-06:00"
}
Registrar un cliente
POST/members
Responde 201 con el cliente nuevo. Si el identificador ya existía, actualiza el nombre, fusiona la metadata y responde
200; su teléfono y su correo se quedan como estaban. En la metadata guarda lo que te ayude a reconocerlo: su mascota, su sucursal, su número de cliente.
curl -X POST https://www.simplepuntos.com/api/v1/members \
-H "Authorization: Bearer $LLAVE" \
-H "Content-Type: application/json" \
-d '{
"identifier": "+522291234567",
"name": "María López",
"email": "maria@correo.mx",
"metadata": {
"mascota": "Firulais",
"sucursal": "Riviera"
}
}'
Consultar un cliente
GET/members/{id}
Lo mismo que la búsqueda, con el id que ya tienes; sirve para refrescar el saldo antes de cobrar.
curl https://www.simplepuntos.com/api/v1/members/$CLIENTE \
-H "Authorization: Bearer $LLAVE"
Actualizar un cliente
PATCH/members/{id}
Cambia el nombre y la metadata, que se fusiona con la que ya tenía; una llave con null se borra.
El identifier, el teléfono y el correo no cambian por la API porque deciden a quién le llega el código de cada canje:
si mandas uno distinto responde 422 contact_locked y no guarda nada. Esos cambios se hacen en el panel y quedan marcados en la bitácora.
curl -X PATCH https://www.simplepuntos.com/api/v1/members/$CLIENTE \
-H "Authorization: Bearer $LLAVE" \
-H "Content-Type: application/json" \
-d '{
"name": "María López Ruiz",
"metadata": {
"sucursal": null,
"especie": "Perro"
}
}'
Movimientos de un cliente
GET/members/{id}/entries
Del más nuevo al más viejo. limit da el tamaño de página (25 por omisión, máximo 100); para la siguiente,
manda en before el next_before de la respuesta. Cuando next_before viene vacío ya no hay más.
curl https://www.simplepuntos.com/api/v1/members/$CLIENTE/entries?limit=10 \
-H "Authorization: Bearer $LLAVE"
Acumular
Acumular
POST/members/{id}/earnings
Manda el monto de la compra en amount, o points: 1 si tu caja no lo tiene: cada acumulación sella una visita
en la tarjeta del cliente, sin importar el monto.
Si con ese sello gana un premio, llega en rewards para imprimirlo en el ticket.
Si con él llena la tarjeta, card_completed viene en true: balance_after dice el sello que la llenó
y balance el saldo que quedó, 0, porque empieza una tarjeta nueva. Imprime balance.
Uno de los dos es obligatorio. reference es el folio del ticket (mira
reintentos seguros); description y metadata son opcionales y quedan
guardados en el movimiento. Responde 201 con el movimiento, el saldo que dejó (balance_after) y el saldo
actual del cliente (balance).
curl -X POST https://www.simplepuntos.com/api/v1/members/$CLIENTE/earnings \
-H "Authorization: Bearer $LLAVE" \
-H "Content-Type: application/json" \
-d '{
"amount": "850.00",
"reference": "riviera-3001",
"description": "Venta 3001"
}'
{
"id": "0199a1b5-77e0-7c21-b0f4-5d6e7f8a9b0c",
"member_id": "0199a1b2-3c4d-7e5f-8a9b-0c1d2e3f4a5b",
"member_identifier": "+522291234567",
"kind": "earn",
"points": "1",
"balance_after": "5",
"source": "api",
"reference": "riviera-3001",
"description": "Venta 3001",
"metadata": {},
"reversed_entry_id": null,
"redemption_id": null,
"created_at": "2026-10-02T13:41:09.502-06:00",
"replayed": false,
"rewards": [
{
"id": "0199a1d2-5e6f-7a8b-9c0d-1e2f3a4b5c6d",
"code": "K7QM3XPA",
"title": "Bebida al 50%",
"source": "stamps",
"status": "available",
"member_id": "0199a1b2-3c4d-7e5f-8a9b-0c1d2e3f4a5b",
"member_identifier": "+522291234567",
"expires_on": null,
"used_at": null,
"used_by": null,
"reference": null,
"created_at": "2026-10-02T13:41:09.502-06:00"
}
],
"balance": "5",
"card_completed": false
}
En la tarjeta de sellos no hay ajustes: /adjustments responde 422 not_adjustable. Una visita sellada por error se
corrige revirtiendo su movimiento (mira corregir una visita).
Consultar un movimiento
GET/entries/{id}
curl https://www.simplepuntos.com/api/v1/entries/$MOVIMIENTO \
-H "Authorization: Bearer $LLAVE"
Corregir una visita
Si una visita se selló por error (otro cliente, dos sellos por una visita), revierte su movimiento: el cliente pierde ese sello.
Si con él había ganado un premio que todavía no usa, el premio se cancela y llega en voided_rewards para que la caja lo anule;
si ya lo usó, responde 422 not_reversible con su código y no revierte nada.
La visita que llenó la tarjeta se revierte mientras la tarjeta nueva siga vacía: vuelve a quedar a un sello de llenarse y su premio se cancela.
Si la nueva ya lleva sellos, revierte primero esas visitas.
Buscar movimientos por referencia
GET/entries?reference={folio}
Si tu caja no guardó el id del movimiento, búscalo por el folio con el que lo mandó. Responde la lista como los
movimientos de un cliente, con next_before para paginar; vacía si nadie usó esa referencia.
curl https://www.simplepuntos.com/api/v1/entries?reference=riviera-3001 \
-H "Authorization: Bearer $LLAVE"
{
"entries": [
{
"id": "0199a1b5-77e0-7c21-b0f4-5d6e7f8a9b0c",
"member_id": "0199a1b2-3c4d-7e5f-8a9b-0c1d2e3f4a5b",
"member_identifier": "+522291234567",
"kind": "earn",
"points": "1",
"balance_after": "5",
"source": "api",
"reference": "riviera-3001",
"description": "Venta 3001",
"metadata": {},
"reversed_entry_id": null,
"redemption_id": null,
"created_at": "2026-10-02T13:41:09.502-06:00"
}
],
"next_before": null
}
Revertir un movimiento
POST/entries/{id}/reverse
curl -X POST https://www.simplepuntos.com/api/v1/entries/$MOVIMIENTO/reverse \
-H "Authorization: Bearer $LLAVE" \
-H "Content-Type: application/json" \
-d '{
"reference": "barra-dev-3001",
"description": "Se selló al cliente equivocado"
}'
{
"id": "0199a1e4-2c3d-7e4f-8a5b-6c7d8e9f0a1b",
"member_id": "0199a1b2-3c4d-7e5f-8a9b-0c1d2e3f4a5b",
"member_identifier": "+522291234567",
"kind": "reversal",
"points": "-1",
"balance_after": "4",
"source": "api",
"reference": "barra-dev-3001",
"description": "Se selló al cliente equivocado",
"metadata": {},
"reversed_entry_id": "0199a1b5-77e0-7c21-b0f4-5d6e7f8a9b0c",
"redemption_id": null,
"created_at": "2026-10-02T14:02:51.330-06:00",
"replayed": false,
"requested_points": "1",
"reversed_points": "1",
"voided_rewards": [
{
"id": "0199a1d2-5e6f-7a8b-9c0d-1e2f3a4b5c6d",
"code": "K7QM3XPA",
"title": "Bebida al 50%",
"source": "stamps",
"status": "cancelled",
"member_id": "0199a1b2-3c4d-7e5f-8a9b-0c1d2e3f4a5b",
"member_identifier": "+522291234567",
"expires_on": null,
"used_at": null,
"used_by": null,
"reference": null,
"created_at": "2026-10-02T13:41:09.502-06:00"
}
]
}
Premios y cupones
En Café Brisa cada acumulación sella una visita en una tarjeta de 10 sellos:
en el sello 5 el cliente gana «Bebida al 50%» y en el sello 10 el cliente gana «Bebida gratis»; al llenarla empieza otra.
Lo que gana con una visita llega en rewards de esa misma respuesta, para imprimirlo en el ticket.
Cada premio de la tarjeta de sellos y cada cupón de una campaña trae un código de 8 caracteres, único en el negocio, que el cliente muestra o dicta en caja.
- Al escanear la tarjeta,
GET /members/{id}/rewards da los premios y cupones que puede usar.
- Para usar uno, manda su código a
POST /rewards/{código}/use y aplica el premio en la venta.
Premios y cupones disponibles
GET/members/{id}/rewards
Solo los que todavía se pueden usar, del más nuevo al más viejo.
curl https://www.simplepuntos.com/api/v1/members/$CLIENTE/rewards \
-H "Authorization: Bearer $LLAVE"
{
"member_id": "0199a1b2-3c4d-7e5f-8a9b-0c1d2e3f4a5b",
"member_identifier": "+522291234567",
"rewards": [
{
"id": "0199a1d2-5e6f-7a8b-9c0d-1e2f3a4b5c6d",
"code": "K7QM3XPA",
"title": "Bebida al 50%",
"source": "stamps",
"status": "available",
"member_id": "0199a1b2-3c4d-7e5f-8a9b-0c1d2e3f4a5b",
"member_identifier": "+522291234567",
"expires_on": null,
"used_at": null,
"used_by": null,
"reference": null,
"created_at": "2026-10-02T13:41:09.502-06:00"
}
]
}
Usar un premio o cupón
POST/rewards/{código}/use
El código se acepta con o sin guion y en minúsculas: k7qm-3xpa encuentra a K7QM3XPA. Cada uno se usa una sola vez.
Repetir con la misma reference responde 200 con replayed: true; si ya se había usado de otra forma responde
409 already_used, y si venció, 422 expired.
curl -X POST https://www.simplepuntos.com/api/v1/rewards/K7QM3XPA/use \
-H "Authorization: Bearer $LLAVE" \
-H "Content-Type: application/json" \
-d '{
"reference": "riviera-3002"
}'
{
"id": "0199a1d2-5e6f-7a8b-9c0d-1e2f3a4b5c6d",
"code": "K7QM3XPA",
"title": "Bebida al 50%",
"source": "stamps",
"status": "used",
"member_id": "0199a1b2-3c4d-7e5f-8a9b-0c1d2e3f4a5b",
"member_identifier": "+522291234567",
"expires_on": null,
"used_at": "2026-10-02T13:52:40.118-06:00",
"used_by": "Llave «Caja Riviera»",
"reference": "riviera-3002",
"created_at": "2026-10-02T13:41:09.502-06:00",
"replayed": false
}
Reintentos seguros
Las redes fallan. Si una petición se cortó y no sabes si llegó, repítela igual, con la misma reference: si ya existía, la API responde
lo mismo que la primera vez con replayed: true (200, o 202 si es un canje que sigue pendiente), sin acumular dos veces.
Vale para acumulaciones y reversos; manda siempre reference.
La referencia es única por tipo de movimiento. Usa el folio con un prefijo por sucursal (riviera-3001, coyol-3001) y no lo reinicies:
si tu caja reinicia folios por día o por terminal, agrégale la fecha o la caja (riviera-20261002-3001).
Si repites una referencia con otro movimiento u otro cliente, responde
409 reference_taken con cuándo y con cuánto se usó, y no mueve nada.
Como cada visita suma un sello, un folio repetido para el mismo cliente siempre se toma como reintento.
Errores
Todo error responde JSON con la misma forma, también un cuerpo que no es JSON válido o una ruta que la API no tiene:
un code estable para tu programa y un message en español para mostrarle al cajero.
{
"error": {
"code": "reference_taken",
"message": "La referencia «riviera-3001» ya se usó el 02/10/2026 a las 13:41 con 1 sellos"
}
}