Clientes y tarjeta guardada
Un cliente es una persona a la que le cobras más de una vez. Si registra su tarjeta una sola vez, después puedes cobrarle desde tu sistema sin que él tenga que hacer nada.
El celular es la identidad
Cada cliente se identifica por su celular, único dentro de tu cuenta. El correo es opcional. Si intentas crear un cliente con un celular que ya existe, recibes 409 customer_exists con el cliente existente en details — así puedes reutilizarlo en vez de duplicarlo.
Crear un cliente
/v1/customersCuerpo
| Campo | Tipo | Descripción |
|---|---|---|
nameobligatorio | string | Nombre del cliente. |
phoneobligatorio | string | Celular. Lo normalizamos a solo dígitos, así que puedes mandarlo con formato. |
email | string | Correo, opcional. |
notes | string | Notas internas (máx. 500). |
curl -X POST https://go.paytiptap.com/api/v1/customers \
-H "Authorization: Bearer tiptap_sk_TU_LLAVE" \
-H "Content-Type: application/json" \
-d '{ "name": "María Pérez", "phone": "+507 6000-0000", "email": "maria@ejemplo.com" }'{
"object": "customer",
"id": "cmqbcazfu000hjy7yb6bctj7v",
"name": "María Pérez",
"phone": "60000000",
"email": "maria@ejemplo.com",
"status": "ACTIVE",
"source": "MERCHANT",
"card": null,
"created_at": "2026-07-26T00:31:00.000Z"
}Cómo se guarda la tarjeta
Tu servidor nunca ve el número de tarjeta, así que no puedes mandarlo por API. La tarjeta se guarda de dos maneras, ambas del lado del cliente:
- Link de afiliación:
https://go.paytiptap.com/join/TU-SLUG. El cliente pone su nombre, su celular y su tarjeta en un solo formulario. Se hace una verificación de $0 (no un cobro) y la tarjeta queda tokenizada. Si el celular ya existía, se le agrega la tarjeta al cliente que ya tenías. El link está en el panel, en Clientes → Link de afiliación. - Al pagar un cobro suyo: si el link de pago está asociado a un cliente (porque lo creaste con
POST /v1/customers/{id}/charges), al pagarlo la tarjeta queda guardada automáticamente.
Cuando el cliente tiene tarjeta, el objeto trae el bloque card con marca, últimos 4 y vencimiento:
"card": { "brand": "visa", "last4": "1111", "expiry": "10/2028" }¿Cómo sé si puedo cobrarle directo?
card no es null, puedes usar use_saved_card: true. Si es null, mándale el link de afiliación para que registre una.Mandar a tu usuario al link (sin que reescriba nada)
El link de afiliación acepta parámetros para que tu usuario no vuelva a teclear lo que tu sistema ya sabe, y para que sepas exactamente quién se afilió:
https://go.paytiptap.com/join/TU-SLUG?ref=usuario_42&name=María%20Pérez&email=maria@correo.com&return_url=https://tu-sitio.com/graciasref— el id del usuario en tu sistema. Queda en el cliente comoexternal_refy lo puedes buscar conGET /v1/customers?external_ref=usuario_42. Sin esto tendrías que casar por celular, y un dígito mal tecleado rompe el vínculo.name,email,phone— prellenan el formulario.return_url— al terminar, se le pinta un botón para volver a tu sitio. Solo aceptamoshttps, y nunca redirigimos solos: el usuario ve a dónde va antes de hacer clic.
El ref es público: úsalo como identificador, no como contraseña
ref que quiera. Usa refs no adivinables (un UUID, no 42) y cruza el email o el celular antes de activarle algo valioso a alguien por el webhook.Entérate sin preguntarle al usuario
customer.card_saved con el cliente completo (incluido external_ref). Así activas el servicio en el momento, sin pedirle que regrese y confirme a mano.Cobrarle a un cliente
/v1/customers/{id}/chargesCuerpo
| Campo | Tipo | Descripción |
|---|---|---|
amountobligatorio | number | Monto a cobrar. |
description | string | Lo que ve el cliente. Por defecto, “Cobro a {nombre}”. |
use_saved_card | boolean | true: cobra al instante la tarjeta guardada. false o ausente: solo genera el link para que el cliente pague. |
Cobro inmediato a la tarjeta guardada
curl -X POST https://go.paytiptap.com/api/v1/customers/cmqbcazfu000hjy7yb6bctj7v/charges \
-H "Authorization: Bearer tiptap_sk_TU_LLAVE" \
-H "Content-Type: application/json" \
-d '{ "amount": 18.00, "description": "Mensualidad julio", "use_saved_card": true }'{
"object": "charge",
"customer_id": "cmqbcazfu000hjy7yb6bctj7v",
"amount": 18,
"currency": "USD",
"paid": true,
"payment_id": "cmqbbfsbd000fjy7yy29qmahh",
"payment_url": "https://go.paytiptap.com/pay/odpDAk0FERxq",
"payment_link": { "object": "payment_link", "status": "COMPLETED", "…": "…" }
}Con paid: true el dinero ya está cobrado y entra a tu próxima liquidación. Si el banco rechaza la tarjeta, recibes 402 charge_declined — y el link igual queda creado en details.payment_link, para que puedas mandárselo al cliente y que pague con otra tarjeta.
Cobro por link
curl -X POST https://go.paytiptap.com/api/v1/customers/cmqbcazfu000hjy7yb6bctj7v/charges \
-H "Authorization: Bearer tiptap_sk_TU_LLAVE" \
-H "Content-Type: application/json" \
-d '{ "amount": 18.00, "description": "Mensualidad julio" }'Devuelve paid: false y payment_url. Mándasela al cliente por el canal que uses. Cuando pague, además del cobro, su tarjeta queda guardada para la próxima.
No es idempotente
GET /v1/payments?customer_id=… para ver si el cobro ya existe.Listar, consultar y actualizar
/v1/customersFiltros: phone (busca por celular, con o sin formato) y status (ACTIVE | ARCHIVED).
curl "https://go.paytiptap.com/api/v1/customers?phone=6000-0000" \
-H "Authorization: Bearer tiptap_sk_TU_LLAVE"/v1/customers/{id}Actualiza solo los campos que mandes. Para dar de baja a un cliente sin borrar su historial, mándale { "status": "ARCHIVED" }; un cliente archivado no admite cobros nuevos.
curl -X PATCH https://go.paytiptap.com/api/v1/customers/cmqbcazfu000hjy7yb6bctj7v \
-H "Authorization: Bearer tiptap_sk_TU_LLAVE" \
-H "Content-Type: application/json" \
-d '{ "email": "maria.perez@ejemplo.com" }'Clientes que se registran solos
Los que llegan por el link de afiliación traen source: "SELF"; los que creas tú, source: "MERCHANT". Cada vez que alguien se registra por ese link te mandamos el webhook customer.created.