Desarrolladores/Primeros pasos
Convenciones
Reglas que se aplican a los dieciséis endpoints.
Ver también: Autenticación · Catálogo y pedidos · README
#Solicitudes
- URL base:
https://b2b.cardv.net/api/v1(Live) ohttps://sandbox.cardv.net/api/v1(Sandbox). - Las rutas no llevan barra al final. Usa
/api/v1/orders, no/api/v1/orders/. - Envía los cuerpos JSON en UTF-8 con
Content-Type: application/json. - Envía los montos como texto, por ejemplo
"9.25". No hace falta rellenar con ceros:"25","25.5"y"25.50"son el mismo monto. Se aceptan hasta 4 decimales. - Usa un
User-Agentclaro, por ejemploAcmeShop-CardV/1.4.
#Montos y fechas
- Precios, totales y saldos tienen 2 decimales, por ejemplo
"merchant_price": "9.25". Solo aparecen más decimales si el monto realmente los tiene. - Los valores nominales se escriben como en la tarjeta, por ejemplo
"denomination_value": "10"o"12.50". - Léelos con un tipo decimal, nunca con un número de punto flotante.
- Pagas en la moneda de tu billetera (
default_currencyenGET/account, hoy USD). face_currencyes la moneda impresa en la tarjeta. Puede ser distinta a la de tu billetera.- Para tus costos, usa siempre
merchant_price. Campos comoprice_labelson solo para mostrar. En un SKUrange, elmerchant_pricede la lista es solo el precio del monto mínimo: pide una cotización del monto exacto para conocer tu costo. - Todas las fechas y horas están en UTC, en formato ISO 8601, por ejemplo
2026-09-29T08:15:30.123456Z. - Usa un parser de ISO 8601 de verdad. La cantidad de decimales en los segundos puede variar.
X-Timestamp, que se usa para firmar, es la hora Unix en segundos.
#Identificadores
| Qué es | Ejemplo | Notas |
|---|---|---|
| Merchant ID | M00000001 | Nunca cambia. |
| ID de SKU | S000456 | Lo usas para cotizar y pedir. |
| ID de producto | P000123 | El producto al que pertenece un SKU. |
| ID de pedido de CardV | O-00001234 | Lo usas para consultar un pedido. |
| Tu número de pedido | SHOP-10001 | external_order_id, de 1 a 120 caracteres, único. |
- Guarda los IDs como texto. No intentes interpretarlos. Pueden volverse más largos.
- Los pedidos también tienen un
idnumérico. No lo uses. Usaorder_id. - En tu número de pedido, usa solo
A–Z a–z 0–9 - _ ..
#Paginación
GET/skus está paginado. Envía limit y offset:
GET /api/v1/skus?limit=100&offset=200{"count": 1234, "limit": 100, "results": ["..."], "filter_options": {}}limitvale 100 por defecto. El máximo es 500. Los valores mayores se reducen a 500.countes el total de resultados. Sigue pidiendo páginas hasta queoffsetllegue acount.- Un
limituoffsetnegativo o que no sea un número devuelve HTTP 400. - Un valor de filtro desconocido devuelve una lista vacía, no un error.
GET/recharge/orderstambién está paginado, con límites más pequeños. Ver Recargas de celular.
#Límite de solicitudes
El límite por defecto es de 60 solicitudes por minuto para toda tu cuenta. Lo comparten todas tus claves y los usuarios del Portal. Tu cuenta puede tener otro límite.
El minuto empieza en
:00del reloj. Las solicitudes rechazadas también cuentan.Si te pasas del límite, recibes HTTP 429 y un encabezado
Retry-After(segundos que debes esperar):{"detail": "Merchant API rate limit exceeded. Expected available in 23 seconds."}Los pedidos nuevos tienen un límite propio y más bajo: por defecto 20 pedidos nuevos por minuto. Los pedidos de tarjetas regalo (
POST/orders) y de recargas (POST/recharge/orders) lo comparten. Su cuenta puede tener otro valor. Cada solicitud de pedido cuenta para ambos límites.Enviar un
external_order_idque ya existe devuelve el pedido original. Esa repetición no consume el límite de pedidos, así que un reintento seguro no queda bloqueado por él.Si supera el límite de pedidos, también recibe HTTP 429 y
Retry-After:{"detail": "Merchant order rate limit exceeded. Expected available in 23 seconds."}Para no pasarte: guarda en caché la lista de SKUs, usa webhooks en vez de consultar a cada rato y espera un poco más después de cada 429.
#Errores
Revisa siempre primero el código HTTP. Después lee el cuerpo JSON. La clave del cuerpo te dice qué salió mal. No dependas del texto del mensaje.
Los errores de autenticación, permisos, recurso no encontrado y límite de solicitudes usan detail:
{"detail": "Order not found."}Los errores de pedidos y cotizaciones indican el campo:
{"balance": "Insufficient available balance."}Si una línea del pedido está mal formada, el error se indica por línea, en la misma posición que en tu items:
{"items": [{}, {"quantity": ["Ensure this value is greater than or equal to 1."]}]}| Clave | Dónde | Qué hacer |
|---|---|---|
detail | Cualquiera | Mira el código de estado más abajo. |
items | POST/orders | Corrige la línea. Si cambió el precio, vuelve a cotizar. |
balance | POST/orders | Agrega fondos en el Portal. |
risk | POST/orders | Llegaste a un límite de pedidos. Contacta a CardV. |
external_order_id | POST/orders | Falta tu número de pedido, es demasiado largo o ya se usó en otro pedido. |
wallet | POST/orders | No hay una billetera activa. Contacta a CardV. |
quantity, amount | Cotización | Fuera de rango o no es un número. |
limit, offset | GET/skus | No es un número válido. |
Algunos errores no vienen en JSON:
- Un HTTP 403 con texto plano como
error code: 1010viene de la red perimetral de CardV. Tu solicitud nunca llegó a CardV. Envía a CardV la IP de tu servidor y tuUser-Agent. - Una ruta desconocida (404) o un error de proxy (5xx) pueden devolver HTML.
Cuando registres errores en tus logs, nunca incluyas secretos de firma, firmas ni códigos.
#Códigos de estado HTTP
| Código | Significado | ¿Reintentar? |
|---|---|---|
| 200 | Éxito. En POST/orders: el pedido ya existía. | No hace falta |
| 201 | Se creó un pedido nuevo. | No hace falta |
| 400 | La solicitud fue rechazada. No se cobró nada. | Después de corregirla |
| 403 | Credenciales, firma, IP o un endpoint exclusivo del Portal. | Después de corregirlo |
| 404 | No existe o no está disponible para tu cuenta. | No |
| 405 | Método incorrecto para esta ruta. | No |
| 429 | Demasiadas solicitudes. | Después de Retry-After |
| 5xx o tiempo agotado | Problema del servidor o de la red. El pedido puede existir. | Sí, ver abajo |
En POST/orders, reintenta solo con el mismo cuerpo y el mismo número de pedido.
Consulta cómo reintentar sin riesgo.
#Respuestas
brand_logo_urlyimage_urlson URLs completas de imágenes alojadas por CardV, o"". Son públicas y se pueden guardar en caché.- Los campos del pedido
invoice_urlydelivery_file_urlson rutas como/orders/O-00001234/invoice, o""si todavía no hay nada. Solo funcionan en el Portal: con una clave de API devuelven HTTP 403. Abre las facturas y los archivos CSV de códigos en el Portal.
#Compatibilidad
- Ignora los campos que no conozcas. CardV agrega campos sin publicar una nueva versión de la API.
- Pueden aparecer nuevos valores de estado. Trata un estado desconocido como "todavía no terminado".
- No dependas del orden de las claves JSON ni del texto de los mensajes.
¿Dudas sobre tu integración? Escribe a [email protected] con tu Merchant ID y el ID del pedido o de la solicitud.