Desarrolladores
La API de Kambak
Sumá sellos desde tu caja, creá clientes desde tu tienda y recibí webhooks. REST, JSON y OpenAPI 3.1.
Desde el plan Inicial (API para tu caja). Completa y con webhooks desde Pro.
Guía rápida
- Creá una clave en Panel › Integraciones. Arrancá con una de prueba (
kbk_test_…). Probala con
GET /me:curl https://api.kambak.app/api/v1/me \ -H "Authorization: Bearer $KAMBAK_API_KEY"Sumá un sello. Toda escritura lleva una
Idempotency-Key:curl -X POST https://api.kambak.app/api/v1/cards/CARD_ID/actions \ -H "Authorization: Bearer $KAMBAK_API_KEY" \ -H "Idempotency-Key: venta-1042" \ -H "Content-Type: application/json" \ -d '{"action": "stamp", "count": 1}'
Base: https://api.kambak.app/api/v1
Qué incluye cada plan
| Plan | API | Pedidos/min |
|---|---|---|
| Gratis | Sin API | — |
| Inicial | API para tu caja: clientes, tarjetas, emitir y acciones | 60 |
| Pro | API completa: también campañas, estadísticas y webhooks | 120 |
| Multisede | Todo, claves por sucursal y servidor MCP | 600 |
Si bajás de plan, lo que ya no incluye responde 403 plan_upgrade_required. La operación dice su plan mínimo en x-kambak-plan.
Autenticación
Mandá la clave en el header Authorization: Bearer kbk_live_….
La clave se muestra una sola vez. Guardala en tu servidor, nunca en el navegador ni en una app.
Actúa con los permisos del dueño que la creó. Si deja de ser dueño, deja de andar.
Revocarla la corta al instante.
Permisos (scopes)
- customers:read
- Ver clientes
- customers:write
- Crear y editar clientes
- cards:read
- Ver tarjetas e historial
- cards:write
- Sumar, restar y canjear; emitir tarjetas
- programs:read
- Ver tus programas
- campaigns:read
- Ver campañas y cupo
- campaigns:write
- Crear y mandar avisos (con el cupo del plan)
- stats:read
- Ver estadísticas
- webhooks:read
- Ver webhooks y entregas
- webhooks:write
- Crear y borrar webhooks
Modo test
Las claves kbk_test_… leen los datos reales de tu comercio.
Las escrituras se validan y simulan: te devuelven lo que pasaría, pero no se guarda nada.
No se actualiza Wallet, no sale ningún aviso y no se disparan webhooks.
Cada respuesta trae Kambak-Mode: test; /me devuelve livemode: false.
Idempotencia
Toda escritura (POST, PATCH, DELETE) exige Idempotency-Key: un valor único por operación.
Si tu caja reintenta con la misma key, recibe la misma respuesta y no se suma dos veces (Idempotent-Replayed: true).
La misma key con otro cuerpo devuelve 422 idempotency_key_reused.
Se recuerda 24 h. Si la operación falló, podés reintentar con la misma key.
Errores
Siempre el mismo formato. Usá code en tu código; message está en español.
{
"error": {
"code": "insufficient_scope",
"message": "Esta clave no tiene el permiso cards:write",
"details": { "required": "cards:write" }
}
}- validation_error
- 400 · datos inválidos (en details, campo por campo)
- idempotency_key_required
- 400 · falta la Idempotency-Key
- invalid_api_key
- 401 · clave inválida, revocada o inactiva
- insufficient_scope
- 403 · la clave no tiene ese permiso
- plan_upgrade_required
- 403 · tu plan no incluye esa operación (details.requiredPlan)
- merchant_inactive
- 403 · el comercio está suspendido o cerrado
- not_found
- 404 · no existe en tu comercio
- recent_action
- 409 · la misma acción hace menos de 2 min: confirmá con confirmRepeat
- rate_limited
- 429 · pasaste el límite por minuto
Paginación
Las listas devuelven data y nextCursor. Pasalo como ?cursor= hasta que venga null.
limit va de 1 a 100 (default 20).
Límites
Por clave: 60 pedidos por minuto en Inicial, 120 en Pro y 600 en Multisede. También hay un tope por comercio.
Cada respuesta trae RateLimit-Limit, RateLimit-Remaining y RateLimit-Reset.
Con 429, esperá lo que dice Retry-After.
Los avisos respetan el cupo de campañas del plan y el tope de 3 por pase cada 24 h de Google.
Webhooks
Registrá una URL y elegí eventos. Te mandamos un POST con JSON firmado.
Creá webhooks en Integraciones o con POST /webhook-endpoints (ideal para Zapier).
Respondé 2xx en menos de 5 s. Si no, reintentamos 8 veces con esperas crecientes (~4 h).
Tras 10 entregas fallidas seguidas, o muchos timeouts seguidos, pausamos el webhook y te avisamos por mail.
Por API, cada evento pide su permiso de lectura: customer.* → customers:read; el resto → cards:read.
Solo URLs https de servidores públicos.
Llegan en segundos; algunos (como Wallet) hasta 1 minuto después.
Eventos
- customer.created
- Cliente nuevo
- card.created
- Tarjeta nueva
- card.stamped
- Sumó sellos
- card.points_changed
- Sumó puntos
- card.balance_changed
- Usó saldo de gift card
- card.adjusted
- Ajuste manual
- card.action_undone
- Acción deshecha
- reward.redeemed
- Canjeó un premio o cupón
- membership.checked
- Validó la membresía
- membership.payment_received
- Pagó la membresía
- membership.payment_reverted
- Pago de membresía revertido
- membership.cancelled
- Canceló el débito
- pass.saved
- Guardó el pase en Wallet
- pass.removed
- Eliminó el pase de Wallet
Así llega cada evento:
{
"id": "evt_3f9c1b2a7d4e5f60a1b2c3d4",
"type": "card.stamped",
"createdAt": "2026-10-13T15:04:05.000Z",
"livemode": true,
"merchantId": "6c0f…",
"data": {
"card": { "id": "…", "programId": "…", "programType": "stamps", "customerId": "…", "memberNumber": "3F2A91BC" },
"event": { "id": "…", "kind": "stamp", "delta": "1", "before": 6, "after": 7, "origin": "api" }
}
}Verificar la firma
El header Kambak-Signature trae t=…,v1=….
- Calculá HMAC-SHA256 de
t + "." + cuerpo crudocon tu secretowhsec_…. - Compará con
v1en tiempo constante. - Rechazá si
ttiene más de 5 minutos (anti-replay).
Usá id del evento para ignorar duplicados.
import crypto from 'node:crypto';
import express from 'express';
const app = express();
const SECRET = process.env.KAMBAK_WEBHOOK_SECRET; // whsec_…
// El cuerpo CRUDO: la firma es sobre los bytes tal cual llegaron
app.post('/webhooks/kambak', express.raw({ type: 'application/json' }), (req, res) => {
const parts = Object.fromEntries(
(req.get('Kambak-Signature') ?? '').split(',').map((p) => p.split('=')),
);
const expected = crypto
.createHmac('sha256', SECRET)
.update(`${parts.t}.${req.body}`)
.digest('hex');
const fresh = Math.abs(Date.now() / 1000 - Number(parts.t)) < 300;
const valid =
fresh &&
typeof parts.v1 === 'string' &&
parts.v1.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(parts.v1), Buffer.from(expected));
if (!valid) return res.status(400).send('invalid signature');
const event = JSON.parse(req.body);
// Guardá event.id para ignorar duplicados
if (event.type === 'reward.redeemed') {
// …
}
res.sendStatus(200);
});Referencia
Generada del mismo OpenAPI que valida la API.
openapi.jsonCuenta
get/meComercio y clave actuales
Ideal para la primera llamada: confirma que la clave anda.
Respuesta 200 · Me
merchantobjectobligatorioapiKeyobjectobligatorioaccessobjectobligatorio- Qué incluye el plan:
pos(Inicial: lo de la caja) ofull(Pro y Multisede). livemodebooleanobligatorio
Clientes
get/customersListar o buscar clientes
customers:readParámetros
limit (query)integer- Tamaño de página (1–100).
cursor (query)string- El
nextCursorde la página anterior. q (query)string- Buscar por nombre, email o teléfono.
email (query)string (email)- Email exacto (sin distinguir mayúsculas).
Respuesta 200 · CustomerList
dataCustomer[]obligatorionextCursorstring | nullobligatorio- Pasalo como
cursorpara seguir.
post/customersCrear un cliente
Promociones solo con consentimiento real: mandá consentSource. Email repetido → 409 customer_exists.
Errores: customer_exists.
customers:writeIdempotency-KeyCuerpo CreateCustomerInput
namestringemailstring (email)phonestring- Teléfono (WhatsApp), con código de país.
birthDatestring (date)- AAAA-MM-DD.
consentMarketingboolean- Solo
truesi el cliente aceptó recibir promociones. consentSourcestring- Cómo aceptó el cliente (p. ej. "Casilla en el checkout web"). Obligatorio para dar el consentimiento.
Respuesta 201 · Customer
idstring (uuid)obligatorionamestring | nullobligatorioemailstring | nullobligatoriophonestring | nullobligatoriobirthDatestring (date) | nullobligatorio- AAAA-MM-DD.
consentMarketingbooleanobligatorio- Aceptó recibir promociones.
consentMarketingAtstring (date-time) | nullobligatorio- Cuándo aceptó.
createdVia"qr" | "nfc" | "link" | "panel" | "import" | "api" | …obligatoriocreatedAtstring (date-time)obligatorioupdatedAtstring (date-time)obligatorio
get/customers/{id}Obtener un cliente
customers:readParámetros
id (path)string (uuid)obligatorio- Id del recurso.
Respuesta 200 · Customer
idstring (uuid)obligatorionamestring | nullobligatorioemailstring | nullobligatoriophonestring | nullobligatoriobirthDatestring (date) | nullobligatorio- AAAA-MM-DD.
consentMarketingbooleanobligatorio- Aceptó recibir promociones.
consentMarketingAtstring (date-time) | nullobligatorio- Cuándo aceptó.
createdVia"qr" | "nfc" | "link" | "panel" | "import" | "api" | …obligatoriocreatedAtstring (date-time)obligatorioupdatedAtstring (date-time)obligatorio
patch/customers/{id}Actualizar un cliente
null borra un dato. Dar el consentimiento exige consentSource; retirarlo, no.
Errores: email_taken.
customers:writeIdempotency-KeyParámetros
id (path)string (uuid)obligatorio- Id del recurso.
Cuerpo UpdateCustomerInput
namestring | nullemailstring (email) | nullphonestring | nullbirthDatestring (date) | nullconsentMarketingbooleanfalseretira el consentimiento.consentSourcestring- Cómo aceptó el cliente (p. ej. "Casilla en el checkout web"). Obligatorio para dar el consentimiento.
Respuesta 200 · Customer
idstring (uuid)obligatorionamestring | nullobligatorioemailstring | nullobligatoriophonestring | nullobligatoriobirthDatestring (date) | nullobligatorio- AAAA-MM-DD.
consentMarketingbooleanobligatorio- Aceptó recibir promociones.
consentMarketingAtstring (date-time) | nullobligatorio- Cuándo aceptó.
createdVia"qr" | "nfc" | "link" | "panel" | "import" | "api" | …obligatoriocreatedAtstring (date-time)obligatorioupdatedAtstring (date-time)obligatorio
get/customers/{id}/cardsTarjetas de un cliente
cards:readParámetros
id (path)string (uuid)obligatorio- Id del recurso.
Respuesta 200 · CardList
dataCard[]obligatorionextCursorstring | nullobligatorio- Pasalo como
cursorpara seguir.
Tarjetas
get/cardsListar tarjetas
cards:readParámetros
limit (query)integer- Tamaño de página (1–100).
cursor (query)string- El
nextCursorde la página anterior. customerId (query)string (uuid)programId (query)string (uuid)
Respuesta 200 · CardList
dataCard[]obligatorionextCursorstring | nullobligatorio- Pasalo como
cursorpara seguir.
post/cardsEmitir una tarjeta
Crea la tarjeta del cliente en un programa activo y devuelve los links de Wallet. Si ya existía, la devuelve (200).
Errores: program_not_active, customer_not_found.
cards:writeIdempotency-KeyCuerpo IssueCardInput
customerIdstring (uuid)obligatorioprogramIdstring (uuid)obligatorio- Un programa activo.
Respuesta 201 · IssueCardResult
cardCardobligatoriocreatedbooleanobligatoriofalsesi ya existía.walletWalletLinksobligatorio
get/cards/{id}Obtener una tarjeta
Errores: card_not_found.
cards:readParámetros
id (path)string (uuid)obligatorio- Id del recurso.
Respuesta 200 · Card
idstring (uuid)obligatorioprogramIdstring (uuid)obligatoriocustomerIdstring (uuid)obligatorioprogramType"stamps" | "points" | "membership" | "coupon" | "giftcard"obligatorioprogramNamestringobligatoriostatus"active" | "suspended" | "expired" | "revoked"obligatoriomemberNumberstringobligatorio- N° de socio del pase.
summarystringobligatorio- Lo que muestra el pase ("7 de 10").
stateCardStateobligatoriowalletobjectobligatoriocanEarnbooleanobligatorioblockedReasonstring | nullobligatoriocreatedAtstring (date-time)obligatoriolastUsedAtstring (date-time) | nullobligatorio
get/cards/by-code/{code}Buscar por el QR del pase
Pasá lo que leyó el lector (URL-encoded).
Errores: card_not_found.
cards:readParámetros
code (path)stringobligatorio- Lo que lee el QR del pase.
Respuesta 200 · Card
idstring (uuid)obligatorioprogramIdstring (uuid)obligatoriocustomerIdstring (uuid)obligatorioprogramType"stamps" | "points" | "membership" | "coupon" | "giftcard"obligatorioprogramNamestringobligatoriostatus"active" | "suspended" | "expired" | "revoked"obligatoriomemberNumberstringobligatorio- N° de socio del pase.
summarystringobligatorio- Lo que muestra el pase ("7 de 10").
stateCardStateobligatoriowalletobjectobligatoriocanEarnbooleanobligatorioblockedReasonstring | nullobligatoriocreatedAtstring (date-time)obligatoriolastUsedAtstring (date-time) | nullobligatorio
get/cards/{id}/eventsHistorial de la tarjeta
cards:readParámetros
id (path)string (uuid)obligatorio- Id del recurso.
limit (query)integer
Respuesta 200 · CardEventList
dataCardEvent[]obligatorio
get/cards/{id}/wallet-linksLinks para agregar a Wallet
cards:readParámetros
id (path)string (uuid)obligatorio- Id del recurso.
Respuesta 200 · WalletLinks
applestring | nullobligatorio- Link al .pkpass de Apple.
googlestring | nullobligatorio- Link de Google Wallet.
errorsobjectobligatorio
post/cards/{id}/actionsSumar, restar o canjear
Mismas reglas que el escáner: historial, Wallet y deshacer. Restar = adjust con delta negativo.
Errores: recent_action, card_inactive, reward_pending, reward_not_available, not_enough_points, insufficient_balance, coupon_used, max_stamps_per_visit.
cards:writeIdempotency-KeyParámetros
id (path)string (uuid)obligatorio- Id del recurso.
Cuerpo CardActionInput
Una de estas formas:
action: "stamp"
countintegerconfirmRepeatboolean- Confirma que no es un doble escaneo (409
recent_action). locationIdstring (uuid) | null
action: "redeem_stamps"
confirmRepeatboolean- Confirma que no es un doble escaneo (409
recent_action). locationIdstring (uuid) | null
action: "add_points"
amountnumberobligatorio- Importe de la compra.
confirmRepeatboolean- Confirma que no es un doble escaneo (409
recent_action). locationIdstring (uuid) | null
action: "redeem_points"
rewardPointsintegerobligatorio- Costo del premio.
confirmRepeatboolean- Confirma que no es un doble escaneo (409
recent_action). locationIdstring (uuid) | null
action: "giftcard_debit"
amountnumberobligatorio- Monto en unidades, hasta 2 decimales.
confirmRepeatboolean- Confirma que no es un doble escaneo (409
recent_action). locationIdstring (uuid) | null
action: "membership_check"
confirmRepeatboolean- Confirma que no es un doble escaneo (409
recent_action). locationIdstring (uuid) | null
action: "coupon_use"
purchaseAmountnumber- Monto en unidades, hasta 2 decimales.
confirmRepeatboolean- Confirma que no es un doble escaneo (409
recent_action). locationIdstring (uuid) | null
action: "adjust"
field"stamps" | "points" | "balance" | "uses"obligatoriodeltanumberobligatorio- Con signo: negativo resta.
reasonstringobligatorioconfirmRepeatboolean- Confirma que no es un doble escaneo (409
recent_action). locationIdstring (uuid) | null
Respuesta 200 · CardActionResult
cardCardobligatorioeventCardEventobligatoriomessagestringobligatoriorewardAvailablebooleanobligatorioreplayedbooleanobligatorio
post/cards/{id}/events/{eventId}/undoDeshacer la última acción
Dentro de los 5 minutos.
Errores: undo_expired, not_last_action, already_undone.
cards:writeIdempotency-KeyParámetros
id (path)string (uuid)obligatorioeventId (path)string (uuid)obligatorio
Respuesta 200 · CardActionResult
cardCardobligatorioeventCardEventobligatoriomessagestringobligatoriorewardAvailablebooleanobligatorioreplayedbooleanobligatorio
Programas
get/programsListar programas
programs:readRespuesta 200 · ProgramList
dataProgram[]obligatorio
get/programs/{id}Obtener un programa
programs:readParámetros
id (path)string (uuid)obligatorio- Id del recurso.
Respuesta 200 · Program
idstring (uuid)obligatoriotype"stamps" | "points" | "membership" | "coupon" | "giftcard"obligatorionamestringobligatoriodescriptionstring | nullobligatoriotermsstring | nullobligatoriostatus"draft" | "active" | "paused" | "archived"obligatoriobenefitstringobligatorio- Frase corta del beneficio.
rulesobjectobligatoriocreatedAtstring (date-time)obligatorioupdatedAtstring (date-time)obligatorio
Campañas y avisos
get/campaignsListar campañas
campaigns:readParámetros
limit (query)integer- Tamaño de página (1–100).
cursor (query)string- El
nextCursorde la página anterior.
Respuesta 200 · CampaignList
dataCampaign[]obligatorionextCursorstring | nullobligatorio- Pasalo como
cursorpara seguir.
post/campaignsCrear un aviso (borrador)
campaigns:writeIdempotency-KeyCuerpo CreateCampaignInput
titlestringobligatorio- Hasta 40 caracteres.
textstringobligatorio- Hasta 300 caracteres.
programIdstring (uuid)obligatoriosegmentIdstring (uuid)- Un segmento guardado.
segmentPreset"inactive_30" | "one_stamp_left" | "birthday_month" | "new_this_week" | "vip_10" | "wallet_removed_30"customerIdsstring (uuid)[]- Aviso directo a estos clientes (1–500). Cuenta como una campaña.
Respuesta 201 · Campaign
idstring (uuid)obligatorioprogramIdstring (uuid) | nullobligatoriosegmentIdstring (uuid) | nullobligatoriosegmentPresetstring | nullobligatoriocustomerIdsstring (uuid)[] | nullobligatorio- Aviso directo a estos clientes.
titlestring | nullobligatoriotextstringobligatoriostatus"draft" | "scheduled" | "sending" | "sent" | "cancelled" | "failed"obligatorioorigin"manual" | "automation" | "ai" | "mcp" | "api"obligatorioscheduledAtstring (date-time) | nullobligatoriosentAtstring (date-time) | nullobligatoriocreatedAtstring (date-time)obligatorioupdatedAtstring (date-time)obligatorio
get/campaigns/quotaCupo del mes
campaigns:readRespuesta 200 · CampaignQuota
planstringobligatoriomonthstringobligatoriomaxinteger | nullobligatoriousedintegerobligatorioremaininginteger | nullobligatoriotimezonestringobligatorio
get/segmentsSegmentos disponibles
campaigns:readRespuesta 200 · SegmentList
segmentsobject[]obligatoriopresetsobject[]obligatorio
get/campaigns/{id}Campaña y reporte
campaigns:readParámetros
id (path)string (uuid)obligatorio- Id del recurso.
Respuesta 200 · CampaignDetail
idstring (uuid)obligatorioprogramIdstring (uuid) | nullobligatoriosegmentIdstring (uuid) | nullobligatoriosegmentPresetstring | nullobligatoriocustomerIdsstring (uuid)[] | nullobligatorio- Aviso directo a estos clientes.
titlestring | nullobligatoriotextstringobligatoriostatus"draft" | "scheduled" | "sending" | "sent" | "cancelled" | "failed"obligatorioorigin"manual" | "automation" | "ai" | "mcp" | "api"obligatorioscheduledAtstring (date-time) | nullobligatoriosentAtstring (date-time) | nullobligatoriocreatedAtstring (date-time)obligatorioupdatedAtstring (date-time)obligatorioreportobjectobligatorio
post/campaigns/{id}/sendMandar ahora
Pasa por el revisor, el consentimiento, el cupo del plan y el tope de 3 avisos por pase cada 24 h.
Errores: campaign_review_failed, campaign_no_recipients, campaign_limit_reached.
campaigns:writeIdempotency-KeyParámetros
id (path)string (uuid)obligatorio- Id del recurso.
Respuesta 200 · Campaign
idstring (uuid)obligatorioprogramIdstring (uuid) | nullobligatoriosegmentIdstring (uuid) | nullobligatoriosegmentPresetstring | nullobligatoriocustomerIdsstring (uuid)[] | nullobligatorio- Aviso directo a estos clientes.
titlestring | nullobligatoriotextstringobligatoriostatus"draft" | "scheduled" | "sending" | "sent" | "cancelled" | "failed"obligatorioorigin"manual" | "automation" | "ai" | "mcp" | "api"obligatorioscheduledAtstring (date-time) | nullobligatoriosentAtstring (date-time) | nullobligatoriocreatedAtstring (date-time)obligatorioupdatedAtstring (date-time)obligatorio
post/campaigns/{id}/scheduleProgramar
Errores: invalid_schedule, campaign_limit_reached.
campaigns:writeIdempotency-KeyParámetros
id (path)string (uuid)obligatorio- Id del recurso.
Cuerpo ScheduleCampaignInput
sendAtstringobligatorio- Hora local del comercio.
Respuesta 200 · Campaign
idstring (uuid)obligatorioprogramIdstring (uuid) | nullobligatoriosegmentIdstring (uuid) | nullobligatoriosegmentPresetstring | nullobligatoriocustomerIdsstring (uuid)[] | nullobligatorio- Aviso directo a estos clientes.
titlestring | nullobligatoriotextstringobligatoriostatus"draft" | "scheduled" | "sending" | "sent" | "cancelled" | "failed"obligatorioorigin"manual" | "automation" | "ai" | "mcp" | "api"obligatorioscheduledAtstring (date-time) | nullobligatoriosentAtstring (date-time) | nullobligatoriocreatedAtstring (date-time)obligatorioupdatedAtstring (date-time)obligatorio
post/campaigns/{id}/cancelCancelar una programada
Errores: campaign_not_cancellable.
campaigns:writeIdempotency-KeyParámetros
id (path)string (uuid)obligatorio- Id del recurso.
Respuesta 200 · Campaign
idstring (uuid)obligatorioprogramIdstring (uuid) | nullobligatoriosegmentIdstring (uuid) | nullobligatoriosegmentPresetstring | nullobligatoriocustomerIdsstring (uuid)[] | nullobligatorio- Aviso directo a estos clientes.
titlestring | nullobligatoriotextstringobligatoriostatus"draft" | "scheduled" | "sending" | "sent" | "cancelled" | "failed"obligatorioorigin"manual" | "automation" | "ai" | "mcp" | "api"obligatorioscheduledAtstring (date-time) | nullobligatoriosentAtstring (date-time) | nullobligatoriocreatedAtstring (date-time)obligatorioupdatedAtstring (date-time)obligatorio
Estadísticas
get/statsResumen del período
stats:readParámetros
days (query)number- 7, 30 o 90.
Respuesta 200 · Stats
periodobjectobligatoriokpisobjectobligatoriovisitsByDayobject[]obligatorio
Webhooks
get/webhook-endpointsListar webhooks
webhooks:readRespuesta 200 · WebhookEndpointList
dataWebhookEndpoint[]obligatorio
post/webhook-endpointsCrear un webhook
Devuelve el secret para verificar la firma (una sola vez). Cada evento pide su scope de lectura: customer.* → customers:read; el resto → cards:read.
Errores: webhook_url_not_allowed, webhook_limit_reached.
webhooks:writeIdempotency-KeyCuerpo CreateWebhookEndpointInput
urlstring (uri)obligatorio- URL HTTPS de un host público.
events"customer.created" | "card.created" | "card.stamped" | "card.points_changed" | "card.balance_changed" | "card.adjusted" | …[]obligatoriodescriptionstring
Respuesta 201 · WebhookEndpointWithSecret
idstring (uuid)obligatoriourlstringobligatoriodescriptionstring | nullobligatorioevents"customer.created" | "card.created" | "card.stamped" | "card.points_changed" | "card.balance_changed" | "card.adjusted" | …[]obligatorioenabledbooleanobligatoriodisabledReason"manual" | "failures" | "key_revoked" | "plan" | nullobligatoriomanual,failures,key_revoked(revocaron su clave o su dueño ya no lo es) oplan(pausado hasta que el plan vuelva a incluir webhooks).consecutiveFailuresintegerobligatoriolastSuccessAtstring (date-time) | nullobligatoriolastFailureAtstring (date-time) | nullobligatoriocreatedAtstring (date-time)obligatorioupdatedAtstring (date-time)obligatoriosecretstring | nullobligatorio- Secreto para firmar. Se muestra una sola vez:
nullen una respuesta repetida (rotalo desde el panel). noticestring
get/webhook-endpoints/{id}Obtener un webhook
webhooks:readParámetros
id (path)string (uuid)obligatorio- Id del recurso.
Respuesta 200 · WebhookEndpoint
idstring (uuid)obligatoriourlstringobligatoriodescriptionstring | nullobligatorioevents"customer.created" | "card.created" | "card.stamped" | "card.points_changed" | "card.balance_changed" | "card.adjusted" | …[]obligatorioenabledbooleanobligatoriodisabledReason"manual" | "failures" | "key_revoked" | "plan" | nullobligatoriomanual,failures,key_revoked(revocaron su clave o su dueño ya no lo es) oplan(pausado hasta que el plan vuelva a incluir webhooks).consecutiveFailuresintegerobligatoriolastSuccessAtstring (date-time) | nullobligatoriolastFailureAtstring (date-time) | nullobligatoriocreatedAtstring (date-time)obligatorioupdatedAtstring (date-time)obligatorio
patch/webhook-endpoints/{id}Editar o reactivar un webhook
Los eventos piden el mismo scope de lectura que al crear.
Errores: webhook_url_not_allowed.
webhooks:writeIdempotency-KeyParámetros
id (path)string (uuid)obligatorio- Id del recurso.
Cuerpo UpdateWebhookEndpointInput
urlstring (uri)- URL HTTPS de un host público.
events"customer.created" | "card.created" | "card.stamped" | "card.points_changed" | "card.balance_changed" | "card.adjusted" | …[]descriptionstring | nullenabledboolean
Respuesta 200 · WebhookEndpoint
idstring (uuid)obligatoriourlstringobligatoriodescriptionstring | nullobligatorioevents"customer.created" | "card.created" | "card.stamped" | "card.points_changed" | "card.balance_changed" | "card.adjusted" | …[]obligatorioenabledbooleanobligatoriodisabledReason"manual" | "failures" | "key_revoked" | "plan" | nullobligatoriomanual,failures,key_revoked(revocaron su clave o su dueño ya no lo es) oplan(pausado hasta que el plan vuelva a incluir webhooks).consecutiveFailuresintegerobligatoriolastSuccessAtstring (date-time) | nullobligatoriolastFailureAtstring (date-time) | nullobligatoriocreatedAtstring (date-time)obligatorioupdatedAtstring (date-time)obligatorio
delete/webhook-endpoints/{id}Borrar un webhook
webhooks:writeIdempotency-KeyParámetros
id (path)string (uuid)obligatorio- Id del recurso.
Respuesta 204
post/webhook-endpoints/{id}/testMandar un evento de prueba
webhooks:writeIdempotency-KeyParámetros
id (path)string (uuid)obligatorio- Id del recurso.
Respuesta 201 · WebhookDelivery
idstring (uuid)obligatorioendpointIdstring (uuid)obligatorioeventIdstringobligatorioeventTypestringobligatoriostatus"pending" | "succeeded" | "failed"obligatorioattemptsintegerobligatorioresponseStatusinteger | nullobligatorioerrorstring | nullobligatoriolivemodebooleanobligatoriocreatedAtstring (date-time)obligatoriolastAttemptAtstring (date-time) | nullobligatoriodeliveredAtstring (date-time) | nullobligatorio
get/webhook-endpoints/{id}/deliveriesEntregas recientes
webhooks:readParámetros
id (path)string (uuid)obligatorio- Id del recurso.
limit (query)integer- Tamaño de página (1–100).
cursor (query)string- El
nextCursorde la página anterior.
Respuesta 200 · WebhookDeliveryList
dataWebhookDelivery[]obligatorionextCursorstring | nullobligatorio- Pasalo como
cursorpara seguir.
post/webhook-deliveries/{id}/retryReenviar una entrega
webhooks:writeIdempotency-KeyParámetros
id (path)string (uuid)obligatorio- Id del recurso.
Respuesta 200 · WebhookDelivery
idstring (uuid)obligatorioendpointIdstring (uuid)obligatorioeventIdstringobligatorioeventTypestringobligatoriostatus"pending" | "succeeded" | "failed"obligatorioattemptsintegerobligatorioresponseStatusinteger | nullobligatorioerrorstring | nullobligatoriolivemodebooleanobligatoriocreatedAtstring (date-time)obligatoriolastAttemptAtstring (date-time) | nullobligatoriodeliveredAtstring (date-time) | nullobligatorio