Consulta el catálogo con tus precios de distribuidor, mira tu saldo y compra desde tu propio sistema.
Viene incluida con los planes Mayorista y Distribuidor. Las claves se crean en Mi cuenta → Mis claves de API.
https://recargasdigitales.com/api/v1| Prefijo | Qué hace | |
|---|---|---|
| Pruebas | rd_test_… | Lee el catálogo y tus precios de verdad. Los pedidos son simulados: no se entrega nada, no se te cobra nada. Billetera de mentira de 1.000 $. |
| Producción | rd_live_… | Los pedidos se cobran de tu billetera y se entregan. |
El entorno va en la clave, no en un parámetro. No hay ninguna combinación de
campos que haga que una clave rd_test_ compre de verdad. Empieza con la de
pruebas y cambia sólo la clave cuando todo funcione: no hay que tocar nada más.
La clave va en una cabecera. Las dos formas valen:
-H "Authorization: Bearer rd_live_xxxxxxxx…"
-H "X-API-Key: rd_live_xxxxxxxx…"
⚠️ La clave no se acepta por la URL. Las URL acaban en el registro de
accesos, en el historial del navegador y en el Referer. Una clave que compra
no puede vivir ahí.
⚠️ La clave se enseña una sola vez. No la guardamos en claro, así que no
podemos volver a enseñártela ni nosotros. Si la pierdes, revócala y crea otra.
Tu clave deja de valer el día que caduque tu plan. No hay que revocar nada:
empezarás a recibir 401. Mira dias_restantes en /saldo para verlo venir.
CLAVE=rd_test_pega_aqui_tu_clave
# 1 · ¿Qué puedo hacer con esta clave?
curl -s -H "Authorization: Bearer $CLAVE" \
https://recargasdigitales.com/api/v1/ayuda
# 2 · Mi saldo
curl -s -H "Authorization: Bearer $CLAVE" \
https://recargasdigitales.com/api/v1/saldo
# 3 · Diez productos con mi precio
curl -s -H "Authorization: Bearer $CLAVE" \
"https://recargasdigitales.com/api/v1/catalogo?n=10"
Todo lo que devuelve esta API tiene ok y peticion_id:
{ "ok": true, "peticion_id": "rd-4f2a9c…", "…": "…", "ms": 35 }
{ "ok": false, "peticion_id": "rd-4f2a9c…",
"error": "saldo_insuficiente",
"mensaje": "Tu saldo es $1.20 y este pedido son $5.00…" }
error es un código estable en minúsculas. Es lo que debes comparar en tu código.mensaje es para una persona y puede cambiar mañana. No programes contra él.peticion_id identifica esa llamada exacta. Guárdalo en tu registro: es lo único que necesitamos para encontrar qué pasó cuando nos escribas.Cada clave lleva los permisos que le des al crearla. Da sólo los que necesites: una clave que alimenta un escaparate no tiene por qué poder comprar.
| Permiso | Da acceso a |
|---|---|
catalogo | GET /catalogo |
precio | GET /precio |
saldo | GET /saldo |
pedidos | POST /pedido, GET /pedido, GET /pedidos |
Sin el permiso, la respuesta es 403 sin_permiso.
300 por minuto y por clave en producción, 600 en pruebas. Todas las respuestas lo dicen:
X-RateLimit-Limit: 300
X-RateLimit-Remaining: 297
⚠️ Lee el número de la cabecera, no de aquí. El tope se puede ajustar, y un
cliente que lleve el 300 escrito a fuego se equivocará el día que cambie.
X-RateLimit-Limit viene en todas las respuestas autenticadas.
Al pasarte recibes 429 demasiadas_llamadas con Retry-After en segundos y
reintentar_en_s en el cuerpo. Usa ese número: reintentar a ciegas es lo
que dispara el siguiente tope.
GET /ayudaQué hay, en qué entorno estás y qué permisos tiene tu clave. No pide ningún permiso: es la primera llamada que conviene hacer.
GET /catalogoLos productos y variantes activos con tu precio.
| Parámetro | Por omisión | Qué hace |
|---|---|---|
n | 200 | Cuántos, máximo 500 |
desde | 0 | Desde cuál (paginado) |
buscar | — | Filtra por nombre de producto o variante |
region | — | Código de país del producto |
tipo | — | Tipo de recarga |
modificado_desde | — | 2026-09-01 o 2026-09-01T10:00:00. Sólo lo que cambió |
curl -s -H "Authorization: Bearer $CLAVE" \
"https://recargasdigitales.com/api/v1/catalogo?buscar=netflix&n=20"
{
"ok": true,
"desde": 0, "n": 20, "total": 3022, "siguiente": 20,
"variantes": [
{
"variante_id": "ae1f42de-49f9-401e-a759-be1b9eb55699",
"producto_id": "8e323eb0-68f6-4f0e-82d7-c081128fdf09",
"producto": "8 Ball Pool",
"variante": "Golden Spin",
"region": null,
"entrega": "recarga_directa",
"tipo": null,
"imagen": "https://recargasdigitales.com/uploads/catalogo/285dc415.webp",
"precio_usd": 0.82,
"publico_usd": 0.89,
"ahorro_usd": 0.07,
"stock": 99
}
]
}
precio_usd es lo que se te cobra a ti. Pon tu margen sobre este número.publico_usd es lo que paga quien entra sin plan. Sirve para enseñar un «antes / ahora», no para calcular.stock: null significa sin límite conocido, no cero.imagen es la URL de la foto en nuestro servidor, siempre absoluta y siempre presente: si un producto no tiene foto propia devolvemos un marcador, para que nunca te salga el icono de imagen rota. Enlázala directamente — no hace falta que te descargues nada, y así las mejoras de una imagen te llegan solas.desde hasta que siguiente sea null:
desde=0
while [ "$desde" != "null" ]; do
r=$(curl -s -H "Authorization: Bearer $CLAVE" \
"https://recargasdigitales.com/api/v1/catalogo?n=500&desde=$desde")
echo "$r" | jq -c '.variantes[]'
desde=$(echo "$r" | jq -r '.siguiente')
done
GET /precioEl precio de una variante, con los campos de entrega que hace falta mandar
para comprarla. Es la llamada que se hace justo antes de POST /pedido.
| Parámetro | Por omisión | |
|---|---|---|
variante | *obligatorio* | El variante_id del catálogo |
cantidad | 1 | De 1 a 20 |
curl -s -H "Authorization: Bearer $CLAVE" \
"https://recargasdigitales.com/api/v1/precio?variante=ae1f42de-…&cantidad=3"
{
"ok": true,
"variante": { "…": "…", "precio_usd": 0.82 },
"cantidad": 3,
"total_usd": 2.46,
"campos_requeridos": [
{ "clave": "telefono", "etiqueta": "Número a recargar", "tipo": "telefono", "opciones": null }
],
"comprable": true
}
Usa total_usd tal cual. Si lo multiplicas y redondeas por tu cuenta, tu total
puede no cuadrar con el que te cobre /pedido y lo leerás como un cobro de más.
GET /saldo{ "ok": true, "entorno": "produccion", "saldo_usd": 148.30, "moneda": "USD",
"plan": { "nombre": "Distribuidor", "hasta": "2026-10-13", "dias_restantes": 30 } }
Con una clave de pruebas devuelve la billetera simulada.
POST /pedido · comprarcurl -s -X POST \
-H "Authorization: Bearer $CLAVE" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: mi-pedido-000123" \
-d '{
"variante_id": "ae1f42de-49f9-401e-a759-be1b9eb55699",
"cantidad": 1,
"datos": { "telefono": "04121234567" },
"precio_max_usd": 0.90
}' \
https://recargasdigitales.com/api/v1/pedido
Idempotency-Key es obligatoriaUn identificador único tuyo para ese pedido — el número de pedido de tu
sistema, o un UUID. Entre 8 y 120 caracteres de A-Z a-z 0-9 . _ : -.
Si reintentas con la misma clave, no se compra dos veces: te devolvemos el
pedido que ya existía con "reintento": true y código 200 en vez de 201.
⚠️ Esto no es burocracia. Tu librería HTTP reintenta sola cuando se le agota el
tiempo de espera, tu cola reintenta el trabajo fallido y tu operador pulsa dos
veces. Sin esta cabecera, cada reintento sería otra gift card comprada y
cobrada.
>
Una clave por pedido. Reutilizarla para comprar otra cosa distinta da
409 idempotency_key_reutilizada, no el pedido viejo en silencio.
El reintento se contesta antes que nada. Si ya existe un pedido con esa clave, te lo devolvemos aunque ahora no te llegue el saldo (la primera compra se lo gastó), aunque el precio haya cambiado o aunque hayamos cerrado la compra por API. La pregunta «¿se creó mi pedido?» no depende de nada más.
Si no sabes si tu POST llegó —se cortó la conexión, tu servidor se
reinició— pregunta por tu propia clave, sin arriesgarte a comprar otra vez:
curl -s -H "Authorization: Bearer $CLAVE" \
"https://recargasdigitales.com/api/v1/pedido?idem=mi-pedido-000123"
200 con el pedido, o 404 no_existe: no se creó y puedes volver a
intentarlo. Un tiempo de espera agotado nunca significa «no se creó»; este 404,
sí.
| Campo | ||
|---|---|---|
variante_id | *obligatorio* | Del catálogo |
cantidad | 1 | De 1 a 20 |
datos | {} | Los campos_requeridos que diga /precio |
precio_max_usd | — | Recomendado. «No compres si el precio unitario subió de aquí» |
simular | false | Hace todas las comprobaciones —permisos, datos, precio, saldo— y no compra ni escribe nada. Con una clave de producción o de pruebas |
Usa precio_max_usd. Los precios de esta tienda siguen al coste del
proveedor y se mueven solos. Sin este campo, un cambio de precio entre que
consultas y compras te lo comes tú.
{
"ok": true,
"entorno": "produccion",
"reintento": false,
"pedido": {
"pedido_id": "9f1c…",
"numero": "9F1C2A4B",
"estado": "entregado",
"total_usd": 0.82,
"creado": "2026-09-13 21:04:11",
"lineas": [ { "variante_id": "…", "descripcion": "8 Ball Pool · Golden Spin",
"cantidad": 1, "precio_usd": 0.82, "datos": {"telefono":"04121234567"} } ],
"entregas": [ { "entrega_id": "…", "tipo": "codigo",
"codigo": "XXXX-XXXX-XXXX", "codigo_pin": null } ]
},
"saldo_usd": 147.48
}
Estados posibles: entregado, pendiente, enviado, rechazado,
devuelto.
pendiente no es un error: significa que el mayorista todavía no ha confirmado.
Vuelve a preguntar por GET /pedido?id=… en unos minutos. No repitas el
POST — para eso está la Idempotency-Key.
| HTTP | error | Qué pasó |
|---|---|---|
| 400 | falta_idempotency_key | No mandaste la cabecera |
| 400 | idempotency_key_invalida | Menos de 8 caracteres o caracteres raros |
| 402 | saldo_insuficiente | Recarga tu billetera desde la web |
| 403 | kyc_requerido | Hay que verificar la identidad. Se hace desde la web |
| 404 | no_existe | Esa variante ya no está en el catálogo |
| 409 | precio_cambio | El precio subió por encima de tu precio_max_usd |
| 409 | importe_excesivo | Por encima del tope por pedido (500 $ por omisión) |
| 409 | producto_fisico | Los productos que hay que enviar se compran por la web |
| 409 | no_comprable | Producto «a consultar» o sin precio |
| 422 | datos_invalidos | Faltan campos de entrega. Vienen en detalles |
| 503 | compra_cerrada | Hemos cerrado la compra por API temporalmente |
GET /pedido?id=… · GET /pedido?idem=…Cómo va un pedido y qué se entregó, con los códigos. Por el pedido_id que
te devolvimos, o por tu propia Idempotency-Key (en la misma clave de API con
la que compraste).
curl -s -H "Authorization: Bearer $CLAVE" \
"https://recargasdigitales.com/api/v1/pedido?id=9f1c…"
⚠️ Cada vez que se piden los códigos de un pedido queda registrado, igual que
cuando se destapan desde la web. Si un cliente reclama que su código ya estaba
canjeado, eso es lo que permite saber quién lo vio y cuándo.
GET /pedidosTus últimos pedidos. n (máx. 100) y desde. No trae los códigos: se piden
de uno en uno con la ruta de arriba.
POST /pruebas/reiniciarSólo con clave rd_test_. Borra tus pedidos simulados y vuelve a llenar la
billetera de mentira. Es lo que te permite ejecutar tu batería de pruebas dos
veces seguidas.
curl -s -X POST -H "Authorization: Bearer $CLAVE_TEST" \
https://recargasdigitales.com/api/v1/pruebas/reiniciar
En pruebas puedes forzar el desenlace de un pedido con ?forzar=:
curl -s -X POST "…/api/v1/pedido?forzar=rechazado" … # estado: rechazado
curl -s -X POST "…/api/v1/pedido?forzar=pendiente" … # estado: pendiente (y se queda así)
curl -s -X POST "…/api/v1/pedido?forzar=tarda" … # pendiente, y entregado 30 s después
curl -s -X POST "…/api/v1/pedido?forzar=cuenta" … # entrega de cuenta: usuario, clave, perfil, pin
curl -s -X POST "…/api/v1/pedido?forzar=pin" … # código con su PIN (codigo + codigo_pin)
curl -s -X POST "…/api/v1/pedido?forzar=recarga" … # recarga directa: sólo destino, sin código
Todas las entregas traen los mismos campos que en producción —codigo,
codigo_pin, usuario, clave, perfil, pin, destino, referencia,
instrucciones, caduca_el—, con null en los que no aplican. Pinta todos los
que vengan con valor: una cuenta pintada sólo con su clave, sin el usuario, no
le sirve a nadie.
Con forzar=tarda, consulta con GET /pedido hasta que cambie: es lo que
tendrás que hacer en producción cuando el mayorista no entrega en el acto.
Lo que de verdad hay que probar no es el camino feliz —ése sale solo— sino qué
hace tu sistema cuando un pedido se rechaza o se queda pendiente. En producción
eso depende del mayorista y no se puede provocar.
| HTTP | error | |
|---|---|---|
| 401 | no_autorizado | Falta la clave, no existe, está revocada o tu plan caducó |
| 403 | sin_permiso | Esa clave no lleva el permiso que pide la ruta |
| 404 | ruta_desconocida | Mira GET /ayuda |
| 404 | version_desconocida | Sólo existe v1 |
| 405 | metodo_no_admitido | La cabecera Allow dice cuáles valen |
| 429 | demasiadas_llamadas | Espera lo que diga Retry-After |
| 500 | fallo_interno | Mándanos el peticion_id |
El 401 no distingue entre «no mandaste clave», «esa clave no existe», «está
revocada» y «tu plan caducó». Es a propósito: distinguirlos le diría a quien
prueba claves al azar cuáles ha acertado. Si no sabes cuál es tu caso, mira
tu página de claves.
1. La clave va en el servidor, nunca en el navegador. Esta API no admite
CORS a propósito: si la llamas desde el JavaScript de una página pública,
estás regalando la clave. Llámala desde tu backend.
2. Una clave por integración, con los permisos justos. Así puedes revocar
una sin parar las demás.
3. Guarda el peticion_id de cada llamada en tu registro.
4. Usa siempre precio_max_usd en los pedidos.
5. Cachea el catálogo y refréscalo con modificado_desde en vez de bajarlo
entero cada vez.
6. Trata pendiente como un estado normal y consúltalo por GET /pedido.
Nunca reenviando el POST.