Desarrolladores/Integración
Recargas de celular
Una recarga de celular agrega saldo directamente a un número de teléfono prepago. Tu cliente recibe tiempo aire o datos en su línea. No hay ningún código que entregar. Pagas con tu billetera CardV, igual que en los demás pedidos.
Ver también: Autenticación · Convenciones · Webhooks
#Cómo funciona
GET /recharge/countries países que puedes recargar
GET /recharge/operators?country=US operadores, tipos de recarga y montos
POST /recharge/quote tu precio y un quote_token válido por 300 s
POST /recharge/orders haz el pedido, pagado con tu billetera
GET /recharge/orders/{order_id} consulta el estado o espera un webhook- Todas las rutas empiezan con
/api/v1. Envía los mismos encabezados que en cualquier llamada. - Las dos llamadas
POSTtienen que ir firmadas. Fírmalas igual quePOST/orders, pero con su propia ruta, por ejemplo/api/v1/recharge/quote. - Los pedidos de recarga son independientes de los pedidos de tarjetas de regalo. Para leerlos, usa los endpoints
/recharge. - Solo se ofrecen recargas directas. Los productos con PIN (un código que el cliente escribe) no están disponibles.
#Países
GET/api/v1/recharge/countries muestra los países que puedes recargar ahora.
{
"count": 2,
"results": [
{"code": "MX", "name": "Mexico", "currency_codes": ["MXN"], "operator_count": 4, "offer_count": 37},
{"code": "US", "name": "United States", "currency_codes": ["USD"], "operator_count": 6, "offer_count": 52}
]
}codees el código de país ISO 3166-1 alfa-2. Envíalo comocountryen las siguientes llamadas.currency_codesson las monedas locales en las que venden los operadores de ese país.- La lista cambia cuando se agregan operadores o dejan de estar disponibles. Cárgala cada pocas horas.
#Operadores
GET/api/v1/recharge/operators?country=US muestra los operadores de un país.
Agrega search=att para filtrar por nombre de operador.
{
"count": 1,
"results": [
{
"operator_key": "us-att",
"name": "AT&T",
"country": "US",
"country_name": "United States",
"logo_url": "https://b2b.cardv.net/api/v1/catalog-assets/3f5c...a1.png",
"subtypes": ["airtime", "data"],
"amount_model": "range",
"currency_codes": ["USD"],
"amounts": [
{"min": "5.0000", "max": "100.0000", "currency": "USD", "subtype": "airtime", "label": "5.0000-100.0000 USD"},
{"min": "15.0000", "max": "15.0000", "currency": "USD", "subtype": "data", "label": "15.0000 USD"}
],
"offer_count": 3
}
]
}| Campo | Qué significa |
|---|---|
operator_key | El ID que envías para cotizar y pedir, por ejemplo us-att. Guárdalo como texto. |
subtypes | Qué puedes comprar: airtime (saldo para llamadas), data o bundle (llamadas y datos). |
amount_model | fixed si todos los montos son valores fijos, range si alguno es un rango. |
amounts[] | Cada opción. Si min es igual a max, es un monto fijo. Si no, vale cualquier monto intermedio. |
amounts[].currency | La moneda local de esa opción. Envíala como local_currency. |
logo_url | Imagen alojada por CardV, o "". |
- Los montos son montos locales: lo que recibe la línea telefónica, en la moneda local.
- Un
countrydesconocido o mal formado devuelve HTTP 400.
#Cotización
POST/api/v1/recharge/quote te da tu precio para una recarga. Esta llamada tiene que ir firmada.
{
"country": "US",
"operator_key": "us-att",
"amount": "10.00",
"local_currency": "USD",
"subtype": "airtime"
}| Campo | Obligatorio | Qué significa |
|---|---|---|
country | Sí | Código de país de la lista de países. |
operator_key | Sí | De la lista de operadores. |
amount | Sí | Monto local, como texto. Fijo: uno de los valores de la lista. Rango: entre min y max. |
local_currency | Recomendado | Código ISO 4217 de amount, tomado de amounts[].currency. Envíalo cuando un operador tenga más de una moneda. |
subtype | No | airtime (por defecto), data o bundle. |
La respuesta:
{
"country": "US",
"country_name": "United States",
"operator": {"operator_key": "us-att", "name": "AT&T", "logo_url": ""},
"subtype": "airtime",
"local_amount": "10.0000",
"local_currency": "USD",
"merchant_price": "9.6200",
"merchant_currency": "USD",
"expires_at": "2026-09-30T08:20:30.123456+00:00",
"quote_token": "eyJ2ZXJzaW9uIjox...:1uXyZa:8c1f..."
}merchant_pricees lo que paga tu billetera, enmerchant_currency.quote_tokenfija este precio durante 300 segundos, hastaexpires_at. Envíalo sin cambios con el pedido.- El token está ligado a tu cuenta y a este país, operador, tipo y monto.
- Antes de hacer el pedido, revisa que
local_currencysea la moneda que esperabas. - Una cotización no reserva dinero. Puedes pedir una cotización nueva en cualquier momento.
#Hacer un pedido de recarga
POST/api/v1/recharge/orders recarga el teléfono y lo paga con tu billetera. Esta llamada tiene que ir firmada.
{
"external_order_id": "SHOP-RC-20260930-0001",
"country": "US",
"operator_key": "us-att",
"amount": "10.00",
"local_currency": "USD",
"subtype": "airtime",
"account": "12125550100",
"quote_token": "eyJ2ZXJzaW9uIjox...:1uXyZa:8c1f..."
}| Campo | Obligatorio | Qué significa |
|---|---|---|
external_order_id | Sí | Tu número de pedido. No se puede repetir en ninguno de tus pedidos, incluidos los de tarjetas de regalo. |
country, operator_key, amount, local_currency, subtype | Sí | Los mismos valores que enviaste en la cotización. |
account | Sí | El número de teléfono que se va a recargar: solo dígitos, con el código de país, sin + ni espacios. |
quote_token | Sí | El de la cotización, antes de que venza. |
Ejemplos de números de teléfono: 12125550100 (Estados Unidos), 525512345678 (México).
Revisa que el número pertenezca al operador elegido. Una recarga enviada a un número equivocado no se puede revertir.
CardV revisa la cotización, cobra merchant_price de tu billetera en ese momento y empieza la recarga en segundo plano.
Un pedido nuevo devuelve HTTP 201:
{
"idempotent_replay": false,
"order": {
"order_id": "O-00005678",
"external_order_id": "SHOP-RC-20260930-0001",
"status": "accepted",
"status_title": "Recharge accepted",
"poll_after_seconds": 12,
"account": "12***00",
"local_amount": "10.0000",
"local_currency": "USD",
"merchant_price": "9.6200",
"merchant_currency": "USD",
"...": "more fields"
}
}- Guarda
order.order_id. - El número de teléfono se devuelve enmascarado, nunca completo.
#Reintentar sin riesgo
external_order_id evita que recargues dos veces.
| Si envías | Recibes |
|---|---|
| Un número de pedido nuevo | HTTP 201. Un pedido nuevo. Se cobra de tu billetera. |
| El mismo número de pedido y la misma recarga | HTTP 200 y "idempotent_replay": true. El pedido que ya existía. Sin cobro. |
| El mismo número de pedido pero otra recarga | HTTP 400 en external_order_id. No pasa nada. |
"La misma recarga" significa el mismo país, operador, tipo, monto y número de teléfono.
CardV reconoce una repetición antes de revisar la cotización, así que un quote_token vencido igual devuelve el primer pedido.
- Después de un tiempo agotado, un 5xx o una conexión perdida, envía el mismo cuerpo con el mismo número de pedido. Fírmalo de nuevo con una marca de tiempo y un nonce nuevos.
- Nunca uses un número de pedido nuevo porque se perdió una respuesta. Eso puede recargar el teléfono dos veces.
#Consultar pedidos de recarga
GET/api/v1/recharge/orders/{order_id} devuelve un pedido.
Puedes usar el ID de pedido de CardV (O-00005678).
{
"order_id": "O-00005678",
"external_order_id": "SHOP-RC-20260930-0001",
"status": "processing",
"order_status": "processing",
"status_title": "Recharge processing",
"status_message": "The recharge request is being processed. Delivery is not confirmed yet.",
"next_step": "Keep this order open and wait for confirmation before placing another recharge.",
"poll_after_seconds": 12,
"country": "US",
"operator": {"operator_key": "us-att", "name": "AT&T", "logo_url": ""},
"subtype": "airtime",
"account": "12***00",
"local_amount": "10.0000",
"local_currency": "USD",
"merchant_price": "9.6200",
"merchant_currency": "USD",
"attempts": [{"attempt_no": 1, "status": "processing", "error_message": "", "submitted_at": "2026-09-30T08:16:02.511201Z", "completed_at": null}],
"created_at": "2026-09-30T08:16:01.004211Z",
"updated_at": "2026-09-30T08:16:02.611978Z",
"...": "more fields"
}- Un ID de pedido desconocido, o un pedido de otra cuenta, devuelve HTTP 404.
status_title,status_messageynext_stepson textos en inglés que puedes mostrar a tu equipo.poll_after_secondsindica cuánto esperar antes de la siguiente consulta.0significa que el pedido ya terminó.
#Listar pedidos de recarga
GET/api/v1/recharge/orders muestra tus pedidos de recarga, del más reciente al más antiguo.
GET /api/v1/recharge/orders?status=processing&limit=50&offset=0{"count": 3, "limit": 50, "results": ["..."]}- Filtros:
statusysearch(ID de pedido de CardV, tu número de pedido o nombre del operador). limitvale 20 por defecto. El máximo es 100. Los valores mayores se reducen a 100.- Un
limituoffsetnegativo o que no sea un número devuelve HTTP 400.
#Estado
accepted ──► processing ──► succeeded
│
├──► manual_review ──► succeeded o refunded
│
└──► failed ──► refunded (el dinero vuelve a tu billetera)| Estado | ¿Terminado? | Qué hacer |
|---|---|---|
accepted | No | Espera. Ya se cobró de la billetera, pero la recarga no ha empezado. |
processing | No | Espera. Puede tardar varios minutos. No vuelvas a hacer el pedido. |
manual_review | No | CardV está revisando el resultado con el operador. Espera. |
succeeded | Sí | El teléfono se recargó. Avísale a tu cliente. |
failed | Todavía no | La recarga no se completó. Espera a que pase a refunded. |
refunded | Sí | El dinero ya volvió a tu billetera. Puedes hacer un pedido nuevo. |
- Consulta después de
poll_after_secondsy luego cada vez con más espera: 30 s, 60 s y después cada 5 minutos. Respeta el límite de solicitudes. - Trata un estado desconocido como "todavía no terminado".
- Mientras un pedido no haya terminado, no envíes otra recarga al mismo número con un número de pedido nuevo. Si el primero también se completa, el teléfono se recarga dos veces.
#Webhooks y reembolsos
Los pedidos de recarga envían los mismos webhooks que los demás pedidos:
order.succeeded, order.failed y order.refunded.
El webhook trae el ID de pedido de CardV y tu número de pedido, con una lista items vacía.
Después de un webhook, consulta el pedido con GET/api/v1/recharge/orders/{order_id}.
Los reembolsos son automáticos. Cuando el operador confirma una falla, CardV devuelve el
merchant_price completo a tu billetera y el pedido pasa a refunded.
Puedes ver el reembolso en la página de transacciones del Portal.
Una recarga que se completó no se puede reembolsar ni cancelar.
#Errores
Los errores siguen las Convenciones. Una cotización o un pedido rechazado devuelve HTTP 400 y no se cobra nada.
| Clave | Dónde | Qué hacer |
|---|---|---|
detail | Cotización, pedido | País, operador, tipo o monto no disponible. Revisa la lista de operadores. |
amount | Cotización, pedido | No es un número, es cero o está fuera de rango. |
local_currency | Cotización, pedido | No es un código ISO 4217 de 3 letras. |
account | Pedido | Falta el número de teléfono. |
quote_token | Pedido | Falta, venció, se modificó o no coincide. Revisa code y vuelve a cotizar. |
balance | Pedido | Agrega fondos en el Portal. |
risk | Pedido | Llegaste a un límite de pedidos. Contacta a CardV. |
external_order_id | Pedido | Ya se usó en otro pedido distinto. Ver Reintentar sin riesgo. |
wallet | Pedido | No hay una billetera activa. Contacta a CardV. |
Los errores de quote_token incluyen un code:
{"code": "quote_expired", "quote_token": "This quote expired. Refresh the price and confirm again."}code | Qué significa |
|---|---|
quote_required | No se envió ningún quote_token. |
quote_expired | Tiene más de 300 segundos. Vuelve a cotizar. |
quote_invalid | Se modificó o es de otra recarga. Vuelve a cotizar. |
price_changed | Tu precio cambió desde la cotización. Vuelve a cotizar y confirma el precio nuevo. |
HTTP 403 significa un problema de credenciales, firma, IP o aprobación. Ver Autenticación.
¿Dudas sobre tu integración? Escribe a [email protected] con tu Merchant ID y el ID del pedido o de la solicitud.