Métodos de pago
API externa /external/v1/payment-methods: guardar tarjetas, listarlas, marcar la predeterminada y desvincularlas, con el plan y los permisos que exige cada endpoint.
Actualizado el . 7 min de lectura
Incluido en los planes Profesional y Avanzado. Ver precios
Con estos endpoints tu aplicación gestiona las tarjetas guardadas de
sus usuarios finales. Todos están bajo /external/v1/payment-methods,
exigen que la facturación de la aplicación esté encendida y tienen un
límite de 60 peticiones por minuto por clave.
Ni tu aplicación ni UTILIA OS ven nunca el número completo, el CVC ni la fecha de caducidad completa de la tarjeta: esos datos viven en Stripe, cifrados según PCI DSS. Estos endpoints solo manejan identificadores.
Guardar una tarjeta
Participan: Tu servidor, Navegador, UTILIA OS, Stripe.
De Tu servidor a UTILIA OS:
GET /api/external/v1/payment-methods/readiness
¿Puede cobrar la organización ahora mismo?De UTILIA OS a Tu servidor:
reason: READY (respuesta)
Con otro motivo, no enseñes el formulario.De Tu servidor a UTILIA OS:
POST /api/external/v1/payment-methods/setup-intent
Con el usuario: externalId, correo y nombre.De UTILIA OS a Tu servidor:
clientSecret, publishableKey y stripeAccountId (respuesta)
El clientSecret se usa una vez y no se guarda.De Tu servidor a Navegador:
Monta Stripe Elements
Con esas tres credenciales.De Navegador a Stripe:
El usuario confirma su tarjeta
De Stripe a UTILIA OS:
setup_intent.succeeded
Stripe confirma que la tarjeta ha quedado guardada.De UTILIA OS a Tu servidor:
Aviso PAYMENT_METHOD_ADDED
La tarjeta ya sale en GET /payment-methods.
Plan y permisos
Antes que el permiso de la aplicación se comprueba el plan de tu
organización. Sin los aplicativos Finanzas y Pagos con tarjeta
(Stripe), la respuesta es 403 con errorCode: 'MODULE_NOT_ENABLED'.
| Endpoint | Aplicativos del plan | Permiso de la API (scope) |
|---|---|---|
GET /external/v1/payment-methods/readiness | Finanzas y Pagos con tarjeta (Stripe) | billing:payment-methods:read |
GET /external/v1/payment-methods | Finanzas y Pagos con tarjeta (Stripe) | billing:payment-methods:read |
POST /external/v1/payment-methods/setup-intent | Finanzas y Pagos con tarjeta (Stripe) | billing:payment-methods:write |
POST /external/v1/payment-methods/:pmId/set-default | Finanzas y Pagos con tarjeta (Stripe) | billing:payment-methods:write |
DELETE /external/v1/payment-methods/:pmId | Finanzas y Pagos con tarjeta (Stripe) | billing:payment-methods:write |
Sin el permiso adecuado, los endpoints responden 403 INSUFFICIENT_SCOPE
con un mensaje genérico que no dice cuál falta, desde la primera
llamada y sin periodo de gracia. El catálogo completo está en
Permisos de la API.
Guardar la tarjeta no autoriza cobros futuros
Un método de pago guardado permite cobrar con el usuario delante.
Para cobrarle sin que esté (una renovación mensual, un cobro
programado) hace falta además su autorización de cobro, que es un
consentimiento firmado con prueba legal. Se recoge en
/external/v1/payment-authorizations.
Saber si la organización puede cobrar
/api/external/v1/payment-methods/readinessResponde si la organización puede cobrar con tarjeta ahora mismo, y por qué no si no puede.
Es la comprobación previa a cualquier flujo de pago. Sin ella, te enteras de que no se puede cobrar por un error, después de haber montado el formulario y pedido la tarjeta al usuario. Con ella, tu aplicación decide antes de enseñar nada.
Respuesta (200)
{
"platformAvailable": true,
"organizationCanCharge": false,
"reason": "ONBOARDING_INCOMPLETE",
"livemode": true
}- platformAvailablebooleanobligatorio
- Si la pasarela de pagos con tarjeta está encendida en esta instalación de UTILIA OS. Es una condición de plataforma: ninguna organización cobra si viene en falso.
- organizationCanChargebooleanobligatorio
- Si la organización puede cobrar ahora mismo. Solo es cierto cuando la plataforma está disponible Y la cuenta de la organización está activa con los cobros habilitados.
- reasonenumobligatorio
- Primer motivo que impide cobrar, evaluado de la causa más externa a la más interna: PLATFORM_DISABLED, NO_ACCOUNT, ACCOUNT_DEAUTHORIZED, ONBOARDING_INCOMPLETE, CHARGES_DISABLED o READY.
- livemodebooleanobligatorio
- Si la pasarela opera en modo real o en modo de prueba. Lo decide la plataforma, no la organización.
Los seis motivos
- PLATFORM_DISABLEDplataforma
- La pasarela está apagada en la plataforma. No lo resuelve tu organización ni tu aplicación: hay que hablar con el equipo de UTILIA OS. Mientras dure, todos los endpoints de cobro responden 503 STRIPE_NOT_CONFIGURED.
- NO_ACCOUNTorganización
- Tu organización no ha conectado todavía su cuenta de Stripe. Se hace desde Finanzas › Ajustes › Pagos con tarjeta (Stripe); no hay forma de hacerlo desde la API.
- ACCOUNT_DEAUTHORIZEDorganización
- La conexión se retiró, desde UTILIA OS o desde el panel de Stripe. Hay que volver a conectar la cuenta.
- ONBOARDING_INCOMPLETEorganización
- El alta se empezó y Stripe aún no la ha dado por terminada. Es pasajero: cuando termine, el valor pasa a READY sin que tu aplicación haga nada.
- CHARGES_DISABLEDorganización
- La cuenta existe pero Stripe no deja cobrar, normalmente por documentación pendiente. Lo resuelve el titular de la cuenta en su panel de Stripe.
- READYorganización
- Todo listo. organizationCanCharge viene en verdadero.
Este endpoint lleva la misma puerta de plan que los demás: sin los
aplicativos Finanzas y Pagos con tarjeta (Stripe) responde
403 con errorCode: 'MODULE_NOT_ENABLED' en lugar de 200. Trátalo
como un séptimo motivo: tu organización no tiene contratado el cobro
con tarjeta, y eso no se arregla conectando una cuenta ni concediendo
un permiso.
Este estado cambia poco (con un despliegue de la plataforma o cuando tu organización toca su cuenta de Stripe). Consúltalo al entrar en la pantalla de pago y cuando recibas un error de cobro, no cada vez que pintas la pantalla.
Crear un SetupIntent para guardar una tarjeta
/api/external/v1/payment-methods/setup-intentDevuelve las credenciales para que tu interfaz monte Stripe Elements y guarde una tarjeta del usuario.
Cuerpo
- userobjetoobligatorio
- Datos del usuario externo, con el mismo formato que en POST /external/v1/invoices.
- user.externalIdstringobligatorio
- Identificador del usuario. Si no existe, se crea; si existe, se actualiza.
- user.emailstringobligatorio
- Correo del usuario.
- user.namestring
- Nombre o razón social.
- user.taxIdstring
- NIF o CIF.
- user.billingAddressobjeto
- Dirección de facturación.
- user.metadataobjeto
- Metadatos libres.
Ejemplo
curl -X POST https://os.utilia.ai/api/external/v1/payment-methods/setup-intent \
-H "X-Api-Key: utl_live_..." \
-H "Content-Type: application/json" \
-d '{
"user": {
"externalId": "user_01HXYZ",
"email": "cliente@empresa.com",
"name": "Empresa de Canarias SL"
}
}'Respuesta (201)
{
"clientSecret": "seti_..._secret_...",
"publishableKey": "pk_live_...",
"stripeAccountId": "acct_...",
"customerId": "cus_...",
"externalUserId": "user_01HXYZ",
"livemode": true
}Tu interfaz monta Stripe Elements con esas credenciales:
import { Elements, PaymentElement } from '@stripe/react-stripe-js';
import { loadStripe } from '@stripe/stripe-js';
const stripe = await loadStripe(response.publishableKey, {
stripeAccount: response.stripeAccountId,
});
<Elements stripe={stripe} options={{ clientSecret: response.clientSecret }}>
<PaymentElement />
</Elements>No guardes nunca el clientSecret en tu base de datos: se usa una sola vez para confirmar el SetupIntent y luego se descarta. Si tu usuario abandona sin terminar, pide otro SetupIntent para volver a intentarlo.
Listar métodos de pago
/api/external/v1/payment-methodsLista las tarjetas activas de un usuario: primero la predeterminada y después de la más reciente a la más antigua.
Parámetros de consulta
- userIdstringobligatorio
- externalId del usuario.
Respuesta (200)
[
{
"id": "pm-uuid-1",
"externalUserId": "user_01HXYZ",
"type": "CARD",
"brand": "visa",
"last4": "4242",
"expMonth": 12,
"expYear": 2028,
"isDefault": true,
"status": "ACTIVE",
"addedVia": "EXTERNAL_APP",
"createdAt": "2026-03-10T08:00:00.000Z"
},
{
"id": "pm-uuid-2",
"externalUserId": "user_01HXYZ",
"type": "CARD",
"brand": "mastercard",
"last4": "4444",
"expMonth": 6,
"expYear": 2027,
"isDefault": false,
"status": "ACTIVE",
"addedVia": "EXTERNAL_APP",
"createdAt": "2026-02-01T10:15:00.000Z"
}
]Los campos:
- idstringobligatorio
- Identificador en UTILIA OS. Se usa en set-default, en la desvinculación y en pay.
- typeenumobligatorio
- CARD, SEPA_DEBIT o LINK. Hoy solo se guardan CARD.
- brandstring
- visa, mastercard, amex, discover…
- last4string
- Últimos cuatro dígitos de la tarjeta.
- expMonth / expYearnumber
- Mes y año de caducidad.
- isDefaultbooleanobligatorio
- Si es la predeterminada del usuario.
- statusenumobligatorio
- ACTIVE, EXPIRED o DETACHED.
- addedViaenumobligatorio
- INTERNAL_DASHBOARD, PORTAL o EXTERNAL_APP.
Marcar como predeterminada
/api/external/v1/payment-methods/:pmId/set-defaultMarca un método como predeterminado. El anterior predeterminado deja de serlo automáticamente.
Parámetros
- pmIdpathobligatorio
- Identificador del método en UTILIA OS.
- userIdbodyobligatorio
- externalId del usuario propietario.
Cuerpo
{ "userId": "user_01HXYZ" }Respuesta (200)
Devuelve el método actualizado con isDefault: true.
Errores
404 EXTERNAL_USER_NOT_FOUND: eluserIdindicado no está registrado en la aplicación.404 PAYMENT_METHOD_NOT_FOUND: el método no existe o es de otro usuario o de otra aplicación.403 BILLING_NOT_ENABLED: la aplicación no tiene la facturación encendida.
Desvincular un método
/api/external/v1/payment-methods/:pmIdDesvincula la tarjeta del cliente en Stripe y la marca como DETACHED en UTILIA OS.
Parámetros
- pmIdpathobligatorio
- Identificador del método.
- userIdqueryobligatorio
- externalId del usuario propietario.
Respuesta (200)
Devuelve el método con status: "DETACHED".
Al desvincular:
- Stripe quita la tarjeta del cliente.
- UTILIA OS la marca como
DETACHED, pero la conserva para el historial de cobros. - Si era la predeterminada, el usuario se queda sin predeterminada hasta que marque otra.
Los cobros automáticos que dependan de esa tarjeta fallarán
Las autorizaciones de cobro que se apoyaban en esa tarjeta dejan de servir, así que las suscripciones con cobro automático y los cobros programados que dependan de ella fallarán en la próxima ejecución. Recoge una tarjeta y una autorización nuevas antes del siguiente cobro.
Errores
404 PAYMENT_METHOD_NOT_FOUND: el método no existe o es de otro usuario o de otra aplicación.
Cabeceras y límite de uso
Las cabeceras son las mismas que en Facturas. El límite es de 60 peticiones por minuto por clave.