Crear link de pago
/v1/partner/payment-linkspayment-links:writeCrea un link de pago asociado a una wallet del partner. Devuelve la URL para compartir. Exige Idempotency-Key.
Propósito
Genera un link de pago que puedes compartir por WhatsApp, correo o QR. Cuando alguien abre el link, ve un checkout donde puede pagar con tarjeta o desde su cuenta SLAN.
Flujo recomendado
- Crea el usuario →
POST /users - Crea su wallet →
POST /wallets - Genera el link de pago → este endpoint
- Comparte
shareUrlcon el pagador - Consulta los pagos →
GET /payment-links/:id/payments
Campos del request
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
walletPublicId | string (ULID) | ✅ | El publicId de la wallet destino (devuelto por POST /wallets). El pago llega a esta wallet. |
amount | string | ✅ | Monto a cobrar en MXN, con dos decimales. Ejemplo: "500.00". Mínimo "1.00". |
concept | string | ❌ | Concepto o descripción del pago. Aparece en el recibo del pagador. Máximo 255 caracteres. |
expiresInHours | number | ❌ | Horas de vigencia del link. Default: 24. Máximo: 720 (30 días). Después de este tiempo, el link expira automáticamente. |
maxUses | number | ❌ | Número máximo de veces que se puede pagar este link. Default: 1. Máximo: 100. |
Quién puede pagar
- Pagador externo: abre la URL y paga con tarjeta en un checkout hosted
- Pagador SLAN: abre la URL en la app y paga desde su saldo
Errores comunes
| Código | Error | Causa | Solución |
|---|---|---|---|
400 | VALIDATION_ERROR | Campo inválido (ej: amount negativo) | Revisa errors[] |
404 | WALLET_NOT_FOUND | La wallet no existe o no es tuya | Verifica walletPublicId |
422 | LINK_EXPIRY_TOO_LONG | expiresInHours supera 720 | Reduce la vigencia |
422 | LINK_USES_INVALID | maxUses fuera de rango | Usa un valor entre 1 y 100 |
500 | INTERNAL_SERVER_ERROR | Error inesperado | Reintenta. Reporta requestId si persiste |
Cabeceras
Idempotency-Keyrequerida- Clave única de la intención, 8-128 caracteres (un UUID v4 sirve). Se genera UNA vez por intención del usuario y se reutiliza en cada reintento: mismo cuerpo ⇒ misma respuesta con `Idempotent-Replayed: true`, sin repetir el efecto. La respuesta se guarda 24 h.
Cuerpo de la petición
Importe del cobro, string decimal de dos decimales. Siempre MXN.
Ejemplo:
"500.00"Concepto que verá el pagador.
máx. 210 caracteres
Ejemplo:
"Pago de servicio fotográfico"Vigencia en horas. Un link de partner puede durar hasta el máximo permitido.
de 1 a 720 · por omisión 24
Ejemplo:
72Cuántas veces se puede usar el link. Por omisión 1 (un solo pago).
de 1 a 100 · por omisión 1
Ejemplo:
1ULID de la wallet del usuario al que se le va a pagar. Debe ser una wallet tuya.
Ejemplo:
"01JKX7MNDR0000000000000037"
Respuesta 201
Comparte shareUrl por WhatsApp, correo o genera un QR con ella.
amountobjetoadmite null
admite null
Ejemplo:
"Pago de servicio fotográfico"createdAtstringEjemplo:
"2026-09-04T15:04:05.000Z"admite null
Ejemplo:
"2026-09-07T15:04:05.000Z"maxUsesnumberEjemplo:
1ownerUserPublicIdstringDueño de la wallet.
Ejemplo:
"01JKX7PEND0000000000000036"publicIdstringEjemplo:
"01JKX7CBRP0000000000000024"statusenumEstado derivado del reloj: un link vencido nunca dice ACTIVE.
ACTIVEEXHAUSTEDEXPIREDCANCELLEDEjemplo:
"ACTIVE"usesCountnumberEjemplo:
0walletPublicIdstringWallet asociada al link.
Ejemplo:
"01JKX7MNDR0000000000000037"
Errores
| Estado | Códigos | Cuándo |
|---|---|---|
400 | IDEMPOTENCY_KEY_REQUIREDVALIDATION_ERROR | Error con code: VALIDATION_ERROR Falta la cabecera `Idempotency-Key` o no mide entre 8 y 128 caracteres |
401 | sin code | Sin x-api-key válida |
403 | sin code | La llave no tiene el scope payment-links:write |
404 | WALLET_NOT_FOUND | La wallet no existe o no es de este partner |
409 | IDEMPOTENCY_IN_FLIGHT | Hay una petición en curso con esa misma clave: espera y reintenta |
422 | IDEMPOTENCY_PAYLOAD_MISMATCHIDEMPOTENCY_ROUTE_MISMATCHLINK_EXPIRY_TOO_LONGLINK_USES_INVALID | Error con code: LINK_EXPIRY_TOO_LONG | LINK_USES_INVALID La clave ya se usó con OTRO cuerpo o en OTRA ruta: genera una nueva |
429 | RATE_LIMITED | Limite de uso: 120 por minuto por credencial. Respeta la cabecera `Retry-After`. |
500 | sin code | Error interno inesperado. Reintenta la petición. Si persiste, reporta el `requestId` al equipo de soporte. |