Convenciones de la API
La dirección base, el encabezado de versión, el formato de solicitud y respuesta, cómo se representan dinero, fechas e IDs, la tabla de errores, idempotencia, paginación, límites de solicitudes, el encabezado Request-Id y qué cambia respecto a Stripe.
La API de Vipter sigue las convenciones de la API de Stripe siempre que existe un equivalente: nombres de campos, formato de error, paginación por cursor, idempotencia y versión por fecha. Quien ya integró Stripe reconoce todo. Esta página reúne lo que vale para todos los endpoints; cada endpoint está en la referencia.
Dirección base
https://api.vipter.com/v1El mismo servicio responde en https://app.vipter.com/api/v1, con las mismas rutas. Usa api.vipter.com en las integraciones nuevas; la otra dirección existe para redes donde solo el dominio del panel está permitido.
Toda llamada es HTTPS. Una URL fuera de /v1 o una ruta que no existe recibe 404 resource_missing, en el mismo formato que los demás errores.
Versión
La API tiene versiones por fecha. La versión actual es 2026-11-01, la única que existe hoy.
Cada clave de API nace fijada a la versión actual del día en que fue creada, y las solicitudes con ella usan esa versión sin necesidad de indicar nada. Para pedir otra versión en una llamada, envía el encabezado:
Vipter-Version: 2026-11-01Una versión desconocida recibe 400 invalid_api_version, con la lista de versiones aceptadas en el mensaje. Toda respuesta autenticada trae el encabezado Vipter-Version con la versión usada.
Dentro de una versión, la API solo cambia de forma compatible: pueden aparecer campos nuevos en cualquier objeto en cualquier momento, y valores nuevos en campos de texto como status y payment_method. Escribe tu código para ignorar los campos que no conoce. Un cambio incompatible, como renombrar o quitar un campo, se convierte en una versión nueva, y las claves existentes siguen en la versión anterior.
Formato de la solicitud
Los parámetros de consulta van en la query string. Los cuerpos de solicitud, en los endpoints que aceptan cuerpo, pueden ir en JSON o en formulario:
Content-Type | Ejemplo |
|---|---|
application/json | {"metadata": {"plan": "pro"}, "tags": ["a", "b"]} |
application/x-www-form-urlencoded | metadata[plan]=pro&tags[]=a&tags[]=b |
El formato de formulario usa la notación de corchetes de Stripe: a[b]=1 se convierte en un objeto, a[0]=x&a[1]=y o a[]=x&a[]=y se convierten en una lista. Un curl copiado de la documentación de Stripe funciona tal cual. En formulario todo valor llega como texto; la API convierte números y booleanos donde los espera.
La query string acepta la misma notación de corchetes. Un cuerpo con otro Content-Type, o un JSON que no es un objeto, recibe 400 parameter_invalid.
Formato de la respuesta
Toda respuesta es JSON en UTF-8, con Cache-Control: no-store. Consultar un objeto devuelve el objeto; un listado devuelve un objeto list (consulta Paginación); un error devuelve un objeto error (consulta Errores).
Encabezados presentes en toda respuesta:
| Encabezado | Contenido |
|---|---|
Request-Id | Identificador único de la solicitud, req_ seguido de 20 caracteres hexadecimales. Consulta Request-Id. |
Vipter-Version | La versión de la API usada. Solo en respuestas autenticadas. |
X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset | El estado de tu límite de solicitudes. |
Retry-After | Solo en 429: segundos hasta poder intentar de nuevo. |
Idempotent-Replayed | Solo cuando la respuesta es la repetición de una solicitud anterior con la misma Idempotency-Key. Consulta Idempotencia. |
Tipos de dato
| Qué | Cómo viene | Ejemplo |
|---|---|---|
| Dinero | Entero en la unidad mínima de la moneda. Nunca decimal. | 9900 es R$ 99,00; 1250 es US$ 12,50. |
| Moneda | Código ISO 4217 en minúsculas. | "brl", "usd" |
| Fecha y hora | Entero en segundos Unix, en UTC. null cuando no aplica. | 1790790000 |
| IDs | Texto con prefijo por tipo de objeto. Trátalo como opaco: no dependas del tamaño ni del formato. | cust_…, sub_…, ord_…, ofr_…, prd_…, cs_…, bps_…, ak_…, req_… |
object | En todo objeto: el nombre del tipo. | "customer", "subscription", "order", "offer", "product", "checkout.session", "billing_portal.session", "account", "list" |
livemode | En todo objeto. En los pedidos, false cuando el pago pasó por una conexión de prueba del proveedor. En los demás objetos, true en producción. | true |
created | En todo objeto: cuándo fue creado, en segundos Unix. | 1790790000 |
| Ausencia | Campo presente con null, y no campo omitido. Las listas vacías vienen como [], los mapas vacíos como {}. | "phone": null |
| País | Código ISO 3166-1 alfa-2 en mayúsculas. | "BR" |
| Documentos | Solo el tipo y los últimos cuatro dígitos. La API nunca devuelve un CPF o CNPJ (identificadores fiscales de Brasil) completo. | {"type": "cpf", "number_masked": "*******1234"} |
Los campos metadata, client_reference_id y checkout_session de los pedidos y las suscripciones vienen completados cuando la venta nació de una sesión de checkout creada por la API; en las demás ventas, vienen {} o null.
Errores
Un error es una respuesta con código HTTP 4xx o 5xx y este cuerpo:
{
"error": {
"type": "invalid_request_error",
"code": "parameter_invalid",
"message": "Invalid query parameter 'limit': Number must be less than or equal to 100",
"param": "limit",
"doc_url": "https://docs.vipter.com/pt-br/developers/api-conventions#erros"
}
}| Campo | Contenido |
|---|---|
type | La familia del error. Decide cómo debe reaccionar tu código. |
code | El motivo exacto, estable entre versiones. Úsalo para tratar casos específicos. |
message | Texto en inglés para quien está depurando. Puede cambiar; no lo compares. |
param | El parámetro o encabezado que causó el error, cuando hay uno. En cuerpos anidados usa puntos y corchetes: lines[0].amount. |
doc_url | Esta sección. |
Tipos de error
| HTTP | type | Cuándo |
|---|---|---|
| 400 | invalid_request_error | Parámetro faltante o inválido, cuerpo malformado, versión desconocida. |
| 401 | authentication_error | Clave ausente, inválida, revocada o vencida. |
| 403 | permission_error | Clave sin el alcance necesario, API desactivada para la tienda, tienda inactiva. |
| 404 | invalid_request_error | El objeto o la ruta no existe. code es resource_missing. |
| 400 o 409 | idempotency_error | Problema con la Idempotency-Key. |
| 429 | rate_limit_error | Límite de solicitudes alcanzado. |
| 402 | card_error | Reservado para rechazos de cobro en los endpoints de pago, próximamente. |
| 500 | api_error | Fallo del lado de Vipter. Guarda el Request-Id e intenta de nuevo. |
Códigos
code | HTTP | Significado |
|---|---|---|
parameter_missing | 400 | Un parámetro obligatorio no vino. param dice cuál. |
parameter_invalid | 400 | Un parámetro vino con valor, tipo o formato incorrecto. param dice cuál. |
invalid_api_version | 400 | El encabezado Vipter-Version tiene una versión desconocida. |
api_key_missing, invalid_api_key, api_key_revoked, api_key_expired | 401 | Consulta Errores de autenticación. |
api_not_enabled, project_inactive, insufficient_scope | 403 | Consulta Errores de autenticación. |
resource_missing | 404 | No hay objeto con ese ID en la tienda, o la ruta no existe. param es id, o starting_after/ending_before cuando el cursor no existe. |
idempotency_key_too_long | 400 | La Idempotency-Key tiene más de 255 caracteres. |
idempotency_key_reused | 400 | La misma Idempotency-Key se usó con otro método, ruta o cuerpo. |
idempotency_key_in_use | 409 | La primera solicitud con esa Idempotency-Key todavía se está procesando. |
rate_limit | 429 | Consulta Límites de solicitudes. |
internal_error | 500 | Fallo del lado de Vipter. |
Un objeto que existe pero pertenece a otra tienda es un 404, igual que un ID inexistente. Los códigos propios de un endpoint, como offer_unavailable o portal_disabled, están en la referencia, junto al endpoint.
Idempotencia
Repetir una solicitud por un timeout de red no puede cobrar dos veces. Para eso, todo POST y DELETE acepta el encabezado Idempotency-Key, con un valor único que tú generas, como un UUID v4:
curl -X POST https://api.vipter.com/v1/… \
-H "Authorization: Bearer vk_live_…" \
-H "Idempotency-Key: 5f0b2c8e-3a1d-4e7f-9b6c-2d4a8e1f0c3b" \
…Las reglas, las mismas de Stripe:
- La clave vale por 24 horas dentro de la tienda. Hasta 255 caracteres.
- La misma clave con el mismo método, ruta y cuerpo devuelve la respuesta guardada de la primera vez, con el mismo código HTTP, sin ejecutar nada de nuevo. La respuesta repetida trae
Idempotent-Replayed: trueyOriginal-Request-Idcon elRequest-Idde la primera. - La misma clave con un cuerpo distinto recibe
400 idempotency_key_reused. - Mientras la primera solicitud todavía se ejecuta, una segunda con la misma clave recibe
409 idempotency_key_in_use. Espera un momento y repite con la misma clave. - Las respuestas
4xxtambién se guardan y se repiten. Las5xxno: puedes reintentar con la misma clave.
Los endpoints GET son idempotentes por naturaleza e ignoran el encabezado. En los POST de hoy (sesiones de checkout, clientes, sesiones del portal) la clave es opcional y recomendada; en los endpoints de cobro que vienen después, será obligatoria.
Paginación
Todo listado devuelve un objeto list:
{
"object": "list",
"url": "https://api.vipter.com/v1/orders",
"has_more": true,
"data": [
{ "id": "ord_7b3e9f1c2a8d4e6f", "object": "order", "created": 1790790412 },
{ "id": "ord_5c1e8a2b9d4f4e7a", "object": "order", "created": 1790704011 }
]
}Los elementos vienen del más nuevo al más antiguo. Parámetros, los mismos de Stripe:
| Parámetro | Contenido |
|---|---|
limit | Cuántos elementos por página, de 1 a 100. Predeterminado 10. |
starting_after | El id del último elemento de la página actual. Devuelve los elementos más antiguos que él: la página siguiente. |
ending_before | El id del primer elemento de la página actual. Devuelve los elementos más nuevos que él: la página anterior. |
No envíes los dos cursores en la misma llamada (400 parameter_invalid). Un cursor que no existe en la tienda recibe 404 resource_missing, con param indicando cuál. Los filtros del endpoint, como customer o status, siguen valiendo con el cursor.
Para recorrer todo, repite mientras has_more sea true, pasando el id del último elemento en starting_after:
curl "https://api.vipter.com/v1/orders?limit=100" \
-H "Authorization: Bearer vk_live_…"
# has_more: true, último id: ord_5c1e8a2b9d4f4e7a
curl "https://api.vipter.com/v1/orders?limit=100&starting_after=ord_5c1e8a2b9d4f4e7a" \
-H "Authorization: Bearer vk_live_…"Las ofertas vienen en orden alfabético por nombre, y no por fecha, porque son un catálogo pequeño. Los cursores funcionan de la misma manera.
Límites de solicitudes
Cada clave de API puede hacer 100 solicitudes cada 2 segundos, lo que da 50 por segundo con margen para ráfagas. Toda respuesta dice dónde estás:
| Encabezado | Contenido |
|---|---|
X-RateLimit-Limit | El tamaño de la ventana: 100. |
X-RateLimit-Remaining | Cuántas solicitudes caben todavía en la ventana actual. |
X-RateLimit-Reset | Cuándo se reabre la ventana, en segundos Unix. |
Pasado el límite, la respuesta es 429 rate_limit con Retry-After en segundos. Espera ese tiempo y repite. En una integración que recorre muchos datos, usa limit=100 y una pequeña pausa entre páginas en vez de paralelizar llamadas.
Las solicitudes sin clave válida tienen un límite aparte, por dirección IP: 10 por minuto.
Request-Id
Toda respuesta, incluidos los errores y los 429, trae un Request-Id único:
Request-Id: req_8c2f4e6a1b3d5f7e9a0cRegistra ese valor en tus logs junto con la llamada. Al hablar con el soporte de Vipter sobre una solicitud, indica el Request-Id: con él, el soporte localiza la llamada exacta, con el estado, la duración y el error. El mismo valor aparece en los registros de solicitudes del panel, que se guardan por 30 días.
Diferencias respecto a Stripe
La API no es un clon: el objetivo es que una integración con Stripe se adapte por mapeo, no que el SDK de Stripe funcione apuntando a Vipter. Lo que cambia:
| Tema | Stripe | Vipter |
|---|---|---|
| Clave | sk_live_… y sk_test_… | Solo vk_live_…. No hay modo de prueba; prueba con una conexión de prueba y usa livemode por objeto. |
| Versión | Stripe-Version | Vipter-Version, en el mismo formato de fecha. |
| Cuerpo de la solicitud | Solo formulario | Formulario o JSON. |
| Factura | invoice | order, con billing_reason para decir si es compra suelta, primer cobro, renovación, cobro manual o uso. |
| Precio | price, uno por producto y moneda | offer, con una lista prices[], una por moneda, y un checkout_url listo. |
| Suscripción | items[] con varios precios | Una oferta por suscripción: offer y product son un objeto cada uno. |
| Sesión de checkout | line_items[] con varios precios | Una oferta por sesión: offer (o line_items[0][price]), con pack para la cantidad. Los cupones van en discounts[0][coupon], como en Stripe. |
| Estado de suscripción | incomplete, unpaid | No existen. past_due es la suscripción en recuperación de pago; los detalles vienen en past_due_details. |
| Pedido con estado manual | No existe | status_source dice si el estado vino del proveedor o se definió en el panel. |
expand[] | Expande objetos relacionados | No existe. Los objetos relacionados vienen como id, o como {id, name} cuando el nombre ayuda. |
| Webhooks | Stripe-Signature | Vipter-Signature, con el mismo algoritmo. Consulta Verificar la firma. |
Qué hacer después
- Consulta cada endpoint y cada objeto en la referencia de la API.
- Crea y protege las claves en Autenticación y claves de API.
Autenticación y claves de API
Cómo crear una clave de API en el panel, el formato vk_live_…, los alcances de lectura y escritura, cómo enviar la clave en cada solicitud, cómo revocarla, cómo probar sin modo de prueba y qué significa cada error 401 y 403.
Referencia de la API (v1)
Cada endpoint de la API de Vipter con sus parámetros, un ejemplo de llamada y de respuesta, y la tabla de campos de cada objeto: cuenta, cliente, suscripción y sus acciones, cobro en la suscripción, uso medido (medidores, eventos de uso, ítems y períodos), pedido, oferta, producto, sesión de checkout, sesión del portal del cliente, eventos y endpoints de webhook.