Referencia de API
Referencia general de la API de vexorpay: base URL, autenticación, formato, paginación, idempotencia, rate limit y errores.
Base URL
https://api.vexorpay.com/api/v1 # producción (claves vxp_live_)
https://api.sandbox.vexorpay.com/api/v1 # sandbox (claves vxp_test_)Autenticación
Todos los endpoints requieren tu clave de API, enviada en el header Authorization:
Authorization: Bearer vxp_live_tu_claveAprende más en Autenticación.
Conexiones OAuth: las apps conectadas pueden autenticarse con un token OAuth (
vxo_at_…) en vez de una API key. En ese caso la conexión fija el modo (sandbox o producción) y cada endpoint exige un scope: si la conexión no lo tiene, la API responde403 insufficient_scope. Ver vexorpay MCP.
Formato de respuesta
- Los recursos (links, ventas, suscripciones) se devuelven como objeto plano (p. ej.
GET /api/v1/payment-links/{id}oGET /api/v1/orders/{id}). - Los listados se devuelven en un envoltorio con paginación:
{
"data": [ { "...": "recurso" } ],
"has_more": false,
"total_count": 12,
"url": "/v1/orders?limit=10"
}Paginación
Los listados usan paginación por cursor:
| Parámetro | Descripción |
|---|---|
limit | Cantidad por página (default 10, mínimo 1, máximo 100). |
starting_after | ID del último elemento de la página anterior; devuelve los siguientes. |
ending_before | ID del primer elemento de la página anterior; devuelve los anteriores. |
limit tiene que ser un entero entre 1 y 100: con 0, -5, 101, 2.5 o un
valor no numérico la API responde 400 validation_error. En la respuesta, la
url de paginación refleja el limit efectivo de esa página.
Producción y sandbox
Hay dos entornos, cada uno con su host y su familia de claves. El modo lo define la API key, no el request:
| Entorno | Base URL | Claves |
|---|---|---|
| Producción | https://api.vexorpay.com/api/v1 | vxp_live_... |
| Sandbox (pruebas) | https://api.sandbox.vexorpay.com/api/v1 | vxp_test_... |
Sandbox es un entorno aparte, con sus propios usuarios y datos: las claves de prueba se
crean desde dashboard.sandbox.vexorpay.com. No existe un parámetro sandbox en los
requests. Una clave en el host equivocado responde 403 livemode_mismatch. Ver
Modo sandbox.
Cobros y comisiones
- Los precios son siempre en USD, con un mínimo de USD 4 por cobro y por plan. No hay planes gratis ni precios por asiento.
- Sin suscripción: cada venta paga una sola comisión de vexorpay, desde 2,7 % + USD 1
con el procesamiento incluido. Cada venta trae el desglose en
feeCentsynetCents. - En los pagos únicos el comprador puede pagar en su moneda local; las suscripciones se cobran en USD. Las ventas se informan siempre en USD.
- Para cobrar hace falta la cuenta de cobro activada desde el dashboard (si no,
409 payment_account_not_ready). Ver Cómo funcionan los cobros.
Idempotencia
Los POST que crean recursos aceptan el header Idempotency-Key. Si repites la misma clave con el mismo body, no se crea nada nuevo: se devuelve el recurso original (replay 200). Con la misma clave y un body distinto, recibes un error idempotency_conflict (409).
Lo aceptan la creación de links (POST /api/v1/payment-links) y los reembolsos (POST /api/v1/orders/{id}/refund). Recomendado: usar una clave por operación (p. ej. el UUID del pedido) para no duplicar un reembolso si el request se repite. El checkout (POST /api/v1/payment-links/{id}/checkout) no es idempotente: cada llamada crea una sesión de checkout nueva.
Cada clave se conserva 24 horas: pasado ese plazo se descarta y una clave repetida vuelve a ejecutar la operación (se crea un recurso nuevo).
Si el recurso original ya no existe (p. ej. fue eliminado dentro de esas 24 horas), el replay responde 404 not_found.
Rate limit
La API tiene un límite de 100 requests por minuto por clave. Cada respuesta incluye los headers X-RateLimit-Limit, X-RateLimit-Remaining y X-RateLimit-Reset (también en los errores 401 y 429). Al superarlo recibes 429 Too Many Requests con Retry-After y X-RateLimit-Remaining: 0. Todas las respuestas traen además X-Request-Id (id único para cruzar con soporte) y Cache-Control: no-store.
Errores
Los errores usan el formato:
{
"error": "invalid_amount",
"message": "The minimum amount per charge is USD 4.",
"detail": { "resetInSeconds": 42 }
}detail es opcional y siempre un objeto (p. ej. resetInSeconds en un 429 o required_scope en un 403 insufficient_scope). Nunca contiene mensajes crudos de errores internos: esos se registran del lado del servidor.
Compatibilidad: los campos desconocidos que mandes en un body se ignoran (no validan) y no se devuelven en la respuesta. La única excepción son las keys desconocidas dentro de un plan de un link recurrente (prices[]): ahí responden 400 validation_error para que un typo no pase en silencio. Del otro lado, la API puede agregar campos nuevos a las respuestas en cualquier momento: trata los campos que no conozcas como opcionales.
error | HTTP | Causa |
|---|---|---|
unauthorized | 401 | Falta el header Authorization. |
invalid_key | 401 | La API key es inválida o fue revocada. |
insufficient_scope | 403 | La conexión (token de una app conectada) no tiene el permiso que exige este endpoint. detail.required_scope indica cuál hace falta. |
livemode_mismatch | 403 | La clave y el host no coinciden en modo: diste una clave de prueba contra api.vexorpay.com (o una live contra api.sandbox.vexorpay.com). |
invalid_connected_account | 403 | El header Vexor-Account apunta a una cuenta sin conexión activa de la app, o la credencial no es de una app de marketplace. |
validation_error | 400 | Algún parámetro tiene un valor inválido. |
invalid_request | 400 | El body es inválido o falta un dato requerido. |
invalid_amount | 400 | El monto no es válido o es menor a USD 4. |
minimum_amount | 400 | El precio de un plan recurrente es menor a USD 4. |
prices_required | 400 | Un link recurring necesita al menos un precio. |
too_many_prices | 400 | Se superó el máximo de 5 planes por link. |
invalid_interval | 400 | El interval del precio no es day, week, month o year. |
invalid_interval_count | 400 | El interval_count está fuera de rango. |
invalid_trial | 400 | El trial_period_days está fuera de rango (1–90). |
unsupported_plan | 400 | El plan no se puede cobrar: plan gratis (USD 0), precio por asiento, o un cambio de planes en un link recurrente existente (precio, intervalo, prueba o cantidad de planes: hace falta un link nuevo). |
payment_link_inactive | 400 | El link de pago no está activo. |
dispute_not_respondable | 400 | La disputa ya está cerrada o no se puede aceptar. |
link_not_found | 404 | No existe ese link de pago. |
subscription_not_found | 404 | No existe esa suscripción. |
dispute_not_found | 404 | No existe esa disputa. |
order_not_found | 404 | No existe esa venta. |
customer_not_found | 404 | No existe ese cliente. |
price_not_found | 404 | El price_id no es un plan de ese link. |
not_found | 404 | El recurso no existe (p. ej. una conexión de marketplace), o la Idempotency-Key apunta a un recurso que ya no existe. |
payment_account_not_ready | 409 | La cuenta de cobro no está lista: todavía no se activó, fue rechazada o (para retirar) falta verificar la identidad. Se resuelve desde el dashboard. |
idempotency_conflict | 409 | La Idempotency-Key ya se usó con un body distinto. |
already_processed | 409 | El recurso ya fue eliminado o archivado (p. ej. un link archivado). |
rate_limited | 429 | Superaste el límite de 100 requests por minuto. |
unexpected_error | 500 | Error interno inesperado. |
payment_link_failed | 502 | El procesador de pagos rechazó o no respondió la creación o la edición del link. No se cambió nada: reintenta en unos minutos. |
upstream_error | 502 | El procesador de pagos falló o no respondió (checkout, reembolso, cancelación, disputa, saldo o retiro). No se cambió nada: reintenta más tarde. |
Endpoints
- Crear link de pago único —
POST /api/v1/payment-links - Crear link de pago recurrente —
POST /api/v1/payment-linkscontype: "recurring" - Listar y gestionar links —
GET /api/v1/payment-links,GET/PATCH/DELETE /api/v1/payment-links/{id},GET /api/v1/payment-links/{id}/stats - Checkout por compra —
POST /api/v1/payment-links/{id}/checkout - Ventas —
GET /api/v1/orders,GET /api/v1/orders/{id},POST /api/v1/orders/{id}/refund - Clientes —
GET /api/v1/customers,GET /api/v1/customers/{id} - Disputas —
GET /api/v1/disputes,GET /api/v1/disputes/{id},POST /api/v1/disputes/{id}/accept - Suscripciones —
GET /api/v1/subscriptions,GET /api/v1/subscriptions/{id},POST /api/v1/subscriptions/{id}/cancel,POST /api/v1/subscriptions/{id}/portal - Saldo —
GET /api/v1/balance - Retiros —
GET /api/v1/payouts(sólo lectura: los retiros se piden en el portal de retiros) - Eventos de reconciliación —
GET /api/v1/events - Cuentas conectadas (marketplace) —
Vexor-Account,GET /api/v1/connected-accounts,GET/DELETE /api/v1/connected-accounts/{id} - Webhooks salientes — configurar y verificar notificaciones
- Autenticación — claves, rotación y seguridad
- Modo sandbox — prueba tu integración sin mover dinero real
Cómo funcionan los cobros
Quién es el vendedor en cada venta, qué comisión se descuenta (una sola, desde 2,7 % + USD 1 con el procesamiento incluido), en qué moneda paga el comprador y cómo se configuran los impuestos.
Crear link de pago único
Crea un link de pago único en dólares con la API de vexorpay.