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/v1Autenticació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.
Modo sandbox
El modo lo define la API key, no el request: las claves vxp_live_... operan
sobre producción y las vxp_test_... sobre datos de prueba. No existe un
parámetro sandbox en los requests. Cada host solo acepta claves de su modo y una
clave en el host equivocado responde 403 livemode_mismatch. Ver
Modo sandbox.
Suscripción a vexorpay
Usar vexorpay en producción requiere la suscripción a vexorpay (USD 9 por mes con
impuestos incluidos, con 30 días de prueba gratis al empezar). Si la suscripción de tu cuenta no está
en prueba ni al día, todas las operaciones de la API y del MCP responden
402 subscription_required. Empieza la prueba o
renueva la suscripción desde el dashboard. En el modo
sandbox no se exige.
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), los reembolsos (POST /api/v1/orders/{id}/refund) y los retiros (POST /api/v1/payouts). Recomendado: usar una clave por operación (p. ej. el UUID del pedido) para no duplicar un reembolso o un retiro 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 reason en un 409 polar_not_ready). 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_seats | 400 | seats fuera de los límites del plan, o seats en un plan de precio fijo. |
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 precios 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_pricing_type | 400 | pricing_type de un plan no es flat ni per_seat. |
invalid_seat_tiers | 400 | La matriz seat_tiers de un plan es inválida. |
invalid_tiers_mode | 400 | tiers_mode no es graduated ni volume, o viene sin seat_tiers. |
invalid_trial | 400 | El trial_period_days está fuera de rango (1–90). |
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 de Polar. |
customer_not_found | 404 | No existe ese cliente de Polar. |
price_not_found | 404 | El price_id no es un plan de ese link (o de esa suscripción). |
not_found | 404 | La Idempotency-Key apunta a un recurso que ya no existe. |
dispute_not_respondable | 400 | La disputa ya está cerrada o no se puede aceptar. |
account_not_connected | 400 | El creador no conectó Polar: no se pueden crear links de pago. |
payment_link_inactive | 400 | El link de pago no está activo. |
polar_test_key_not_supported | 400 | Una clave de prueba (vxp_test_) no puede crear links en producción. |
whop_link_failed | 502 | El procesador de pagos no creó el link. Reintenta en unos minutos. |
whop_reconnect_required | 409 | El procesador de pagos rechazó la operación por permisos de la cuenta de cobro: escríbenos desde soporte. |
idempotency_conflict | 409 | La Idempotency-Key ya se usó con un body distinto. |
polar_not_ready | 409 | La organización de Polar del creador todavía no puede cobrar (falta verificación en Polar). detail.reason explica el motivo. |
polar_link_not_editable_yet | 409 | El link de Polar todavía se está creando (o su creación falló): reintenta en unos segundos. |
polar_reconnect_required | 409 | La conexión con Polar es anterior al checkout por API: el creador tiene que volver a conectar Polar desde el dashboard. |
polar_link_structure_change | 400 | En un link de Polar se cambian título, descripción, imagen, monto y nombre/monto/prueba de cada plan fijo. Agregar o quitar planes, cambiar intervalo o asientos exige un link nuevo. |
polar_field_not_supported | 400 | El valor no aplica a un link de Polar (p. ej. status: "canceled": en Polar un link está activo o archivado). |
polar_not_connected | 409 | El creador no tiene Polar conectado. |
payout_account_not_ready | 409 | La cuenta de cobro de Polar del creador no está lista: hay que terminar de configurarla en Polar. |
insufficient_balance | 400 | El saldo disponible de Polar no alcanza para un retiro (Polar descuenta sus comisiones de retiro). |
payout_in_progress | 409 | Ya hay un retiro de Polar creándose para esa cuenta: reintenta en unos minutos. |
polar_payout_failed | 502 | Polar no procesó el retiro o no respondió. |
already_processed | 409 | El recurso ya fue eliminado o archivado (p. ej. un link archivado). |
unsupported_plan | 400 | Un plan recurrente no se puede expresar en Polar (p. ej. una combinación de precio por asiento no soportada). |
subscription_required | 402 | La suscripción a vexorpay de tu cuenta no está en prueba ni al día (solo en producción). |
rate_limited | 429 | Superaste el límite de 100 requests por minuto. |
polar_provisioning_failed | 500 | Polar rechazó la creación del link. No quedó nada publicado: reintentá. |
polar_update_failed | 502 | Polar rechazó o no respondió la edición (link o suscripción). No se cambió nada: reintenta. |
polar_archive_failed | 502 | Polar no archivó el link. Sigue activo en los dos lados: reintenta. |
polar_checkout_failed | 502 | Polar no creó el checkout. Reintenta en unos minutos. |
upstream_error | 500 | La operación falló de forma inesperada en Polar u otro proveedor externo. Reintenta más tarde. |
unexpected_error | 500 | Error interno inesperado. |
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},PATCH /api/v1/subscriptions/{id},POST /api/v1/subscriptions/{id}/cancel,POST /api/v1/subscriptions/{id}/portal - Saldo —
GET /api/v1/balance - Retiros —
GET/POST /api/v1/payouts,GET /api/v1/payouts/estimate - 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
Impuestos y Merchant of Record
Qué es un Merchant of Record (MoR), en qué se diferencia de un procesador de pagos (PSP) y cómo Polar, el MoR de las ventas de vexorpay, calcula, recauda y remite el sales tax / VAT / GST. Con ejemplos con USD 100.
Crear link de pago único
Crea un link de pago único en dólares con la API de vexorpay.