Volver al programa de revendedores

API de Revendedores

Consulta el catálogo con tus precios mayoristas, crea pedidos y recibe los códigos automáticamente desde tu propio sistema.

Primeros pasos

La API es REST sobre HTTPS y responde siempre en JSON. Toda la integración se hace con cuatro llamadas: consultar catálogo, crear pedido, consultar estado y (opcional) revisar tu saldo.

Y puedes quedarte con menos. Si conectas tu WhatsApp, al crear el pedido le entregamos el código a tu cliente por tu número: te ahorras consultar el estado y reenviar nada. Con eso, la integración entera es una sola llamada. Está en entrega directa.

URL base

https://juegodigital.store/jd-api/v1

Antes de integrar necesitas

  • Una cuenta de revendedor activa en la tienda.
  • Tu clave de API, que aparece en tu panel: Mi cuenta — Revendedor.
  • Saldo en tu billetera: cada pedido se cobra de ahí al crearse.

¿Quieres probar antes de tener cuenta? Puedes. El modo de prueba es público y no cobra nada: integra tu sistema completo y pásalo a producción cambiando solo la URL y la clave.

¿Aún no tienes acceso? Escríbenos por WhatsApp y activamos tu cuenta con tu clave. Solicitar acceso

Autenticación

Cada petición lleva tu clave en la cabecera X-JD-Key. No se usan tokens temporales ni OAuth: es una sola clave permanente.

X-JD-Key: tu_clave_de_api

Tu clave es como tu contraseña. Va siempre en el servidor, nunca en el código de tu página web ni en una app: quien la tenga puede gastar tu saldo. Si se te filtra, escríbenos y la cambiamos.

Modo de prueba (sandbox)

Antes de mover dinero real, integra contra el modo de prueba: responde exactamente igual que la API real, pero no cobra tu saldo, no consume stock y no crea pedidos. Puedes usarlo ahora mismo, incluso sin ser revendedor todavía.

URL base de prueba

https://juegodigital.store/jd-api/v1/test

Clave de prueba (pública)

X-JD-Key: jd_test_publica_2026

Los endpoints son los mismos: /perfil, /productos, /pedidos, /pedidos/{codigo} y /agente. Toda respuesta de prueba incluye "modo": "prueba" para que nunca confundas un entorno con el otro.

Productos para probar cada camino

El catálogo de prueba trae ids reservados que provocan el error que quieras, sin tener que esperar a que ocurra de verdad:

producto_idQué pasa
8412Pedido correcto (también 8413, 8420, 8431, 8455).
8888Responde 422 — sin stock.
7777Responde 422 — saldo insuficiente.
cualquier otroResponde 404 — producto no encontrado.

Prueba tu integración en un minuto

# Comprobar que tu cliente HTTP funciona
curl -H "X-JD-Key: jd_test_publica_2026" \
  "https://juegodigital.store/jd-api/v1/test/perfil"

# Crear un pedido de prueba (no cuesta nada)
curl -X POST -H "X-JD-Key: jd_test_publica_2026" \
  -H "Content-Type: application/json" \
  -d '{"producto_id":8412,"cantidad":1}' \
  "https://juegodigital.store/jd-api/v1/test/pedidos"

# Probar el error de sin stock
curl -X POST -H "X-JD-Key: jd_test_publica_2026" \
  -H "Content-Type: application/json" \
  -d '{"producto_id":8888}' \
  "https://juegodigital.store/jd-api/v1/test/pedidos"

Para pasar a producción solo cambias dos cosas: la URL base (quita /test) y la clave (la tuya, de tu panel). Ni una línea más de tu código.

Los pedidos de prueba no existen: sus códigos empiezan por JD-TEST-, no aparecen en tu historial y los datos entregados son ficticios. La Tienda (búsqueda en mayoristas) no tiene modo de prueba.

El agente también responde en modo prueba, pero con una respuesta de ejemplo: no consume ninguna IA. Sirve para ver la forma exacta de la respuesta y montar tu integración antes de poner tu clave.

Límites por nivel

Cada nivel tiene su propio límite de peticiones por minuto. Al pasarte recibes un 429 y basta esperar un minuto.

NivelPeticiones por minutoSe te abre en el panel
Starter30La API, tu panel y la Tienda
Avanzado60Tu WhatsApp de entregas
Élite120Tus agentes de IA
Agregador240Tus pasarelas de pago

Cada nivel suma al anterior: lo que se te abre, lo conservas. En tu panel solo aparecen las herramientas que ya tienes desbloqueadas — si no las ves, es que aún no te tocan. También podemos abrirte una suelta sin esperar a que subas: escríbenos.

Tu nivel actual y tu límite exacto los devuelve GET /perfil.

Perfil y saldo

GET /jd-api/v1/perfil

Tu nivel, tu saldo disponible y tu límite de peticiones. Útil para comprobar que tu clave funciona antes de integrar el resto.

Respuesta

{
  "nombre": "Tu Negocio SAS",
  "tier": "avanzado",
  "gasto_acumulado": 1450000,
  "saldo_billetera": 320000,
  "peticiones_por_minuto": 60
}

Catálogo con tus precios

GET /jd-api/v1/productos

Devuelve los productos con tu precio de revendedor ya calculado y su disponibilidad. Resultados de 50 en 50.

Parámetros

ParámetroTipoDescripción
qtextoOpcional. Filtra por nombre del producto.
pagenúmeroOpcional. Página de resultados (por defecto 1).

Respuesta

{
  "moneda": "COP",
  "pagina": 1,
  "paginas": 7,
  "productos": [
    {
      "id": 8412,
      "nombre": "Steam Wallet USD 10",
      "precio_publico": 18900,
      "precio_revendedor": 14200,
      "en_stock": true
    }
  ]
}

El id es lo que necesitas para crear el pedido. Consulta en_stock antes de vender: si está en false, el pedido será rechazado.

Crear un pedido

POST /jd-api/v1/pedidos

Crea el pedido y descuenta el total de tu billetera en el momento. La entrega se prepara enseguida; el código se consulta con el endpoint de estado.

Cuerpo

CampoTipoDescripción
producto_idnúmeroObligatorio. El id del catálogo.
cantidadnúmeroOpcional (por defecto 1). Entre 1 y 20.
cliente_whatsapptextoOpcional. El WhatsApp de tu cliente, con código de país. Si lo mandas, le entregamos el código a él por tu número. Ver entrega directa.
{ "producto_id": 8412, "cantidad": 1, "cliente_whatsapp": "573001234567" }

Respuesta 201

{
  "pedido": "JD-8412",
  "total_cobrado": 14200,
  "estado": "en_proceso",
  "consultar_en": "https://juegodigital.store/jd-api/v1/pedidos/JD-8412",
  "entrega_directa": "Se enviará a tu cliente por tu WhatsApp al entregarse."
}

Guarda el valor de pedido. Es el identificador con el que consultas la entrega y con el que te atendemos cualquier caso.

entrega_directa solo aparece si mandaste cliente_whatsapp, y te dice si de verdad va a salir. Si tu WhatsApp no está conectado o el interruptor está apagado, te lo avisa ahí mismo en vez de callarse.

Estado del pedido y códigos

GET /jd-api/v1/pedidos/{codigo}

Devuelve el estado del pedido y, cuando ya está listo, el código o los datos entregados de cada artículo. Consúltalo cada pocos segundos hasta que estado sea entregado.

Respuesta

{
  "pedido": "JD-8412",
  "estado": "completed",
  "total": 14200,
  "creado": "2026-08-07 14:22:10",
  "items": [
    {
      "producto": "Steam Wallet USD 10",
      "cantidad": 1,
      "precio": 14200,
      "entregado": "XXXXX-XXXXX-XXXXX",
      "estado": "entregado"
    }
  ]
}

Mientras el artículo no esté listo, entregado viene en null y su estado es en_proceso.

Recargas de celular y datos

Recarga la línea de tu cliente en Colombia y más de 150 países. A diferencia del resto del catálogo, una recarga no es un producto: es una operación contra un número de teléfono y un monto que eliges tú. Aun así queda registrada como un pedido normal, con su factura y sumando a tu gasto acumulado.

Una recarga no se puede deshacer. En cuanto el operador la acredita, el saldo entra en la línea de destino de forma definitiva: no hay cancelación ni reembolso. Verifica el número y el operador antes de enviarla.

El operador lo eliges tú

No deducimos el operador a partir del número, a propósito. La portabilidad numérica permite conservar el número al cambiar de compañía, así que el prefijo dejó de identificar al operador: un 300 puede ser hoy de cualquiera. Pregúntaselo a tu cliente. Una recarga enviada al operador equivocado no llega y no es reembolsable.

GET /jd-api/v1/recargas/paises

Los países disponibles, con su código ISO.

GET /jd-api/v1/recargas/operadores?pais=CO

Los operadores de un país. De aquí sale el id que necesitas para cotizar y recargar.

Cotizar antes de cobrar

POST /jd-api/v1/recargas/cotizar
CampoTipoDescripción
operador_idnúmeroObligatorio. El id del operador.
montonúmeroObligatorio. En la moneda del país de destino.
{ "precio": 11050, "operador": "WOM Colombia" }

El precio es lo que se te va a descontar. Consúltalo siempre antes de recargar: el costo del mayorista cambia con el tipo de cambio.

Recargar

POST /jd-api/v1/recargas
CampoTipoDescripción
operador_idnúmeroObligatorio.
telefonotextoObligatorio. La línea de destino, solo dígitos.
paistextoCódigo ISO del país (por defecto CO).
montonúmeroObligatorio. En la moneda del país de destino.
curl -X POST -H "X-JD-Key: tu_clave" \
  -H "Content-Type: application/json" \
  -d '{"operador_id":683,"telefono":"3001234567","pais":"CO","monto":10000}' \
  "https://juegodigital.store/jd-api/v1/recargas"

Respuesta 201

{
  "pedido": "JD-8420",
  "total_cobrado": 11050,
  "estado": "entregado",
  "comprobante": "90210034",
  "consultar_en": "https://juegodigital.store/jd-api/v1/pedidos/JD-8420"
}

Si la recarga falla, el saldo vuelve solo. Cuando el proveedor la rechaza, te devolvemos el importe a tu billetera automáticamente y el pedido queda cancelado. La respuesta te dice el motivo con un 422. Nunca te quedas sin saldo y sin recarga.

Si se corta la conexión al enviar —tu red, un tiempo de espera agotado— consulta tus pedidos antes de reintentar. La recarga puede haber salido aunque no recibieras la respuesta, y repetirla la enviaría dos veces.

Las recargas no tienen modo de prueba: el proveedor no expone un entorno de pruebas para nuestro canal. Empieza con el monto más bajo y con tu propio número.

Mayorista: el catálogo completo

Busca productos que no están publicados en nuestra tienda y añádelos a tu catálogo para venderlos al instante. Disponible en todos los niveles.

GET /jd-api/v1/disponibles

Parámetro q obligatorio, mínimo 3 letras. Devuelve resultados con un token por producto y el precio ya calculado para ti.

POST /jd-api/v1/disponibles/agregar

Envía token (el que trajo la búsqueda) y el producto queda disponible para comprarlo con POST /pedidos.

{
  "mensaje": "Producto agregado a tu catálogo.",
  "producto_id": 9317,
  "nombre": "Xbox Game Pass Ultimate 3 meses",
  "precio": 128400
}

eSIM: datos para viajeros

Planes de datos móviles en más de 100 destinos. Se entregan como código QR: tu cliente lo escanea y tiene internet sin cambiar de chip.

No se buscan por nombre, se buscan por destino. Nadie escribe «Japan 3GB 15Days»: se elige el país y se comparan los planes. Por eso el eSIM tiene sus dos rutas y no entra por /disponibles.

GET /jd-api/v1/esim/paises

Los destinos cubiertos hoy, con su código ISO de 2 letras. La lista la da el proveedor, así que no se queda vieja cuando añaden países.

GET /jd-api/v1/esim/planes?pais=JP

Los planes de ese destino, de más barato a más caro, con tu precio ya calculado y un token por plan.

{
  "pais": "JP",
  "planes": [
    {
      "token": "eyJpdiI6...",
      "nombre": "Japón 3GB · 15 días",
      "precio": 48900,
      "en_stock": true
    }
  ]
}

Para comprarlo, manda ese token a POST /jd-api/v1/disponibles/agregar y luego POST /pedidos con el producto_id que te devuelve. El QR llega en el endpoint de estado igual que un código.

Un eSIM se instala una sola vez. Si tu cliente lo borra del teléfono, ese QR ya no sirve y hay que comprar otro. Adviérteselo al entregárselo.

Entrega directa a tu cliente Desde Avanzado

Manda cliente_whatsapp al crear el pedido y, en cuanto se entrega, el código sale hacia tu cliente por tu propio número. Tú no reenvías nada.

Qué hace falta

  1. Conectar tu WhatsApp en tu panel: WaChat (URL, token y nombre de instancia) o WABA por Twilio (Account SID, Auth Token y número remitente).
  2. Encender «Entregar a mi cliente automáticamente». Viene apagado: no mandamos mensajes en tu nombre sin que lo pidas.
  3. Opcional: escribir tu propio mensaje de entrega, con {detalle} donde van los códigos.

Si usas WABA oficial, necesitas una plantilla aprobada. WhatsApp no permite que un negocio escriba primero con texto libre: hace falta una plantilla de Meta (su ContentSid, que pegas en tu panel) salvo que tu cliente te haya escrito en las últimas 24 horas. Con WaChat esto no aplica.

Si el envío falla, no se pierde en silencio: lo recibes como evento entrega.whatsapp.fallo en tu webhook, con el motivo. Tu pedido sigue entregado y el código está siempre en el endpoint de estado.

Agentes de IA Desde Élite

POST /jd-api/v1/agente

Le mandas el mensaje de tu cliente y te devuelve la respuesta ya redactada con tu marca. Conéctalo a tu WhatsApp, tu web o tu bot. Usa tu propia clave de IA (la pones en tu panel): pagas el consumo directo al proveedor, sin margen nuestro. Si no tienes cómo pagar una, te alquilamos la nuestra por suscripción.

Los cuatro tipos

tipoPara qué
ventasRecomienda productos, da precios y cierra la compra. (por defecto)
soporteAyuda a quien ya compró: código que falla, región, canje. No vende.
atencionDudas generales, estado de pedidos y quejas.
marketingTe escribe a ti: publicaciones, estados y promociones listas para publicar.

La lista también la devuelve GET /jd-api/v1/agente/tipos, por si quieres pintarla en tu interfaz.

Cuerpo

CampoTipoDescripción
mensajetextoObligatorio. Lo que escribió tu cliente.
tipotextoOpcional. Uno de los cuatro de arriba (por defecto ventas).
historiallistaOpcional. Turnos previos: [{"rol":"cliente","texto":"..."},{"rol":"agente","texto":"..."}]. Se usan los últimos 10.
curl -X POST -H "X-JD-Key: tu_clave" \
  -H "Content-Type: application/json" \
  -d '{"tipo":"ventas","mensaje":"hola, tienes Steam Wallet?"}' \
  "https://juegodigital.store/jd-api/v1/agente"

Respuesta

{
  "respuesta": "¡Hola! Sí, tenemos Steam Wallet USD 10 por $18.500...",
  "tipo": "ventas"
}

El agente no sabe nada de nosotros. Habla siempre en nombre de tu negocio y tiene prohibido mencionar proveedores o de dónde salen los productos, aunque tu cliente insista.

Solo menciona productos de tu catálogo, con el precio sugerido de venta al público (tu costo más margen) — nunca tu precio de compra. Si algo no está disponible, dice que no lo maneja en vez de inventarlo.

¿No quieres llamar tú a esta ruta? No hace falta. Apunta el webhook de tu WhatsApp a tu dirección del panel y el agente contesta solo, sin que programes nada: tu agente contesta tu WhatsApp.

Tu agente contesta tu WhatsApp Desde Élite

La otra mitad del puente: en vez de llamar tú al agente desde tu código, apuntas tu WhatsApp a una dirección nuestra y a partir de ahí contesta solo, con tu marca y a cualquier hora.

Cómo se conecta

  1. En tu panel, sección Tus herramientas, copia tu dirección de webhook (es única y secreta).
  2. Pégala en tu WaChat, o en Twilio en «When a message comes in».
  3. Enciende «Que mi agente conteste solo» y elige cuál de los cuatro atiende.

A partir de ahí: llega el mensaje de tu cliente, responde tu agente con tu clave de IA y la respuesta sale por tu número. Recuerda los últimos 10 turnos de cada conversación durante dos horas, así que el cliente puede seguir preguntando sin repetirlo todo.

Lo que hace por su cuenta

  • No se contesta a sí mismo. Los mensajes que envías tú se ignoran; si no, dos bots pueden quedarse hablando solos y gastando tu saldo.
  • Freno por número: hasta 12 respuestas por minuto al mismo cliente. Cada respuesta te cuesta dinero.
  • Los acuses de recibo y los cambios de estado no se contestan, aunque tu pasarela los mande por la misma dirección.

Esa dirección es una llave. Quien la tenga puede hacer trabajar a tu agente y gastar tu saldo de IA. No la publiques; si se te escapa, genera otra desde tu panel y la anterior deja de servir al instante.

Webhooks: que te avisemos nosotros

En vez de preguntar «¿ya está?» en bucle, registra una URL tuya y te avisamos a ti en cuanto el pedido se entrega. Se configura en tu panel: Mi cuenta — Revendedor — Avisos automáticos.

Qué recibes

Un POST con este cuerpo. Responde 200 para confirmar que lo recibiste.

{
  "evento": "pedido.entregado",
  "enviado_en": "2026-08-07T14:22:10-05:00",
  "intento": 1,
  "datos": {
    "pedido": "JD-8412",
    "estado": "completed",
    "total": 14200,
    "items": [
      {
        "producto": "Steam Wallet USD 10",
        "cantidad": 1,
        "precio": 14200,
        "entregado": "XXXXX-XXXXX-XXXXX",
        "estado": "entregado"
      }
    ]
  }
}

Eventos

EventoCuándo
pedido.entregadoAl quedar entregado un pedido tuyo.
saldo.bajoCuando tu saldo baja del límite que elegiste.
entrega.whatsapp.falloSi la entrega directa a tu cliente no salió. Trae el motivo, tu pedido y el número. Tu pedido sigue entregado: lo que falló es el mensaje.
pruebaCuando pulsas «Enviar aviso de prueba» en tu panel.

Comprueba la firma (importante)

Cada aviso lleva la cabecera X-JD-Signature: el HMAC-SHA256 del cuerpo crudo con tu secreto. Sin comprobarla, cualquiera que descubra tu URL podría inventarte entregas.

// PHP
$cuerpo = file_get_contents('php://input');
$firma  = $_SERVER['HTTP_X_JD_SIGNATURE'] ?? '';
$mia    = hash_hmac('sha256', $cuerpo, 'TU_SECRETO');

if (!hash_equals($mia, $firma)) {
    http_response_code(401);
    exit;
}

$datos = json_decode($cuerpo, true);
// ... entrega a tu cliente ...
http_response_code(200);

Si tu servidor está caído

No se pierde nada: reintentamos a los 1, 5, 15, 60 y 180 minutos. Cada envío trae su número de intento. Tras el quinto fallo, dejamos de intentarlo — consulta ese pedido con GET /pedidos/{codigo}.

Tu URL debe ser HTTPS y pública. No aceptamos direcciones de red interna (localhost, 192.168.*): es una protección para los dos.

Aviso de saldo bajo

Cada pedido se descuenta de tu billetera. Cuando el saldo se agota, la API responde 422 saldo insuficiente y pierdes ventas sin enterarte.

En tu panel eliges a partir de qué saldo quieres el aviso. Al bajar de ahí te llega correo y WhatsApp — como máximo una vez al día — y, si tienes webhook, también el evento saldo.bajo para que tu sistema reaccione solo (por ejemplo, avisándote en tu propio panel).

Errores

Todos los errores responden con el código HTTP correspondiente y un cuerpo { "error": "..." } con el motivo en español.

CódigoSignificadoQué hacer
401Clave inválida o revendedor inactivoRevisa la cabecera X-JD-Key y que tu cuenta siga activa.
403Tu nivel no incluye esa funciónLos agentes de IA se abren en Élite y tu WhatsApp en Avanzado. Escríbenos para subir de nivel o para que te abramos esa función suelta.
404Producto o pedido no encontradoVerifica el producto_id o el código del pedido.
422Sin stock, saldo insuficiente o datos inválidosEl mensaje dice exactamente cuál de los tres es.
429Límite de peticiones alcanzadoEspera un minuto. Sube de nivel si necesitas más ritmo.

Ejemplo completo

Comprar un producto y recuperar su código, de principio a fin.

cURL

# 1. Buscar el producto
curl -H "X-JD-Key: tu_clave" \
  "https://juegodigital.store/jd-api/v1/productos?q=steam"

# 2. Crear el pedido — con el WhatsApp de tu cliente,
#    para que el codigo le llegue a el desde tu numero
curl -X POST -H "X-JD-Key: tu_clave" \
  -H "Content-Type: application/json" \
  -d '{"producto_id":8412,"cantidad":1,"cliente_whatsapp":"573001234567"}' \
  "https://juegodigital.store/jd-api/v1/pedidos"

# 3. Consultar la entrega (opcional si usas la entrega directa)
curl -H "X-JD-Key: tu_clave" \
  "https://juegodigital.store/jd-api/v1/pedidos/JD-8412"

PHP

// Crear el pedido
$ch = curl_init('https://juegodigital.store/jd-api/v1/pedidos');
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'X-JD-Key: tu_clave',
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'producto_id' => 8412,
        'cantidad' => 1,
        'cliente_whatsapp' => '573001234567',
    ]),
]);

$pedido = json_decode(curl_exec($ch), true);
curl_close($ch);

// Consultar hasta que llegue el codigo
$codigo = $pedido['pedido'];

JavaScript (Node)

const r = await fetch('https://juegodigital.store/jd-api/v1/pedidos', {
  method: 'POST',
  headers: {
    'X-JD-Key': process.env.JD_KEY,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    producto_id: 8412,
    cantidad: 1,
    cliente_whatsapp: '573001234567'
  })
});

const pedido = await r.json();
console.log(pedido.pedido);

Plantilla de Google Sheets

¿No programas? Con esta plantilla vendes desde una hoja de cálculo: trae el catálogo con tus precios, crea pedidos y trae los códigos entregados. Solo tienes que pegar tu clave.

1. Abre una hoja en blanco

Entra a sheets.new. No prepares nada: las pestañas las crea el propio código.

2. Pega el código

En el menú de Google Sheets: Extensiones — Apps Script. Borra lo que haya, pega esto y guarda (el icono del disquete).

// ============================================================
//  Juego Digital Store - Plantilla de revendedor
//  Solo tienes que pegar tu clave en la pestana Config (B1).
//  Modo: escribe "prueba" o "produccion" en Config B2.
// ============================================================

var DOMINIO = 'https://juegodigital.store';

function jdConfig() {
  var h = SpreadsheetApp.getActive().getSheetByName('Config');
  var clave = String(h.getRange('B1').getValue() || '').trim();
  var modo = String(h.getRange('B2').getValue() || 'prueba').trim().toLowerCase();

  if (!clave) {
    throw new Error('Pega tu clave de API en la pestana Config, celda B1.');
  }

  var base = DOMINIO + '/jd-api/v1';
  if (modo !== 'produccion') { base = base + '/test'; }

  return { clave: clave, base: base, modo: modo };
}

function jdLlamar(ruta, metodo, cuerpo) {
  var cfg = jdConfig();
  var opciones = {
    method: metodo || 'get',
    headers: { 'X-JD-Key': cfg.clave },
    muteHttpExceptions: true
  };

  if (cuerpo) {
    opciones.contentType = 'application/json';
    opciones.payload = JSON.stringify(cuerpo);
  }

  var r = UrlFetchApp.fetch(cfg.base + ruta, opciones);
  var datos = JSON.parse(r.getContentText() || 'null');

  if (r.getResponseCode() >= 400) {
    throw new Error((datos && datos.error) ? datos.error : 'Error ' + r.getResponseCode());
  }

  return datos;
}

// ---------- 1. Traer el catalogo con tus precios ----------
function traerCatalogo() {
  var datos = jdLlamar('/productos', 'get');
  var h = SpreadsheetApp.getActive().getSheetByName('Catalogo');

  h.clear();
  h.appendRow(['id', 'nombre', 'precio publico', 'tu precio', 'en stock']);

  var filas = datos.productos.map(function (p) {
    return [p.id, p.nombre, p.precio_publico, p.precio_revendedor, p.en_stock ? 'SI' : 'NO'];
  });

  if (filas.length) {
    h.getRange(2, 1, filas.length, 5).setValues(filas);
  }

  h.getRange('A1:E1').setFontWeight('bold');
  h.autoResizeColumns(1, 5);

  SpreadsheetApp.getActive().toast('Catalogo actualizado: ' + filas.length + ' productos.');
}

// ---------- 2. Crear los pedidos pendientes ----------
//  En la pestana Pedidos escribe en la columna A el id del producto
//  y en la B la cantidad. Deja el resto vacio: se llena solo.
function crearPedidos() {
  var h = SpreadsheetApp.getActive().getSheetByName('Pedidos');

  if (h.getLastRow() < 1) {
    h.appendRow(['producto id', 'cantidad', 'codigo', 'estado', 'entregado', 'total']);
    h.getRange('A1:F1').setFontWeight('bold');
    SpreadsheetApp.getActive().toast('Escribe el id y la cantidad en las filas de abajo.');
    return;
  }

  var ultima = h.getLastRow();
  var hechos = 0;

  for (var f = 2; f <= ultima; f++) {
    var id = h.getRange(f, 1).getValue();
    var codigo = String(h.getRange(f, 3).getValue() || '').trim();

    if (!id || codigo) { continue; }

    var cantidad = Number(h.getRange(f, 2).getValue()) || 1;

    var cuerpo = { producto_id: Number(id), cantidad: cantidad };

    // Columna G: si pones ahi el WhatsApp de tu cliente, el codigo le llega
    // a el desde TU numero y no tienes que reenviar nada.
    var wa = String(h.getRange(f, 7).getValue() || '').replace(/\D+/g, '');
    if (wa) { cuerpo.cliente_whatsapp = wa; }

    try {
      var r = jdLlamar('/pedidos', 'post', cuerpo);
      h.getRange(f, 3).setValue(r.pedido);
      h.getRange(f, 4).setValue(r.estado);
      h.getRange(f, 6).setValue(r.total_cobrado);
      hechos++;
    } catch (e) {
      h.getRange(f, 4).setValue('ERROR: ' + e.message);
    }
  }

  SpreadsheetApp.getActive().toast('Pedidos creados: ' + hechos);
}

// ---------- 3. Traer los codigos entregados ----------
function actualizarEstados() {
  var h = SpreadsheetApp.getActive().getSheetByName('Pedidos');
  var ultima = h.getLastRow();
  var listos = 0;

  for (var f = 2; f <= ultima; f++) {
    var codigo = String(h.getRange(f, 3).getValue() || '').trim();
    var entregado = String(h.getRange(f, 5).getValue() || '').trim();

    if (!codigo || entregado) { continue; }

    try {
      var r = jdLlamar('/pedidos/' + codigo, 'get');
      var item = (r.items && r.items.length) ? r.items[0] : null;

      h.getRange(f, 4).setValue(item ? item.estado : r.estado);

      if (item && item.entregado) {
        h.getRange(f, 5).setValue(item.entregado);
        listos++;
      }
    } catch (e) {
      h.getRange(f, 4).setValue('ERROR: ' + e.message);
    }
  }

  SpreadsheetApp.getActive().toast('Entregas nuevas: ' + listos);
}

// ---------- Instalador ----------
// Ejecuta esta funcion UNA vez y la hoja se arma sola: crea las tres
// pestanas, sus titulos y el formato. No hay que preparar nada a mano.
function instalar() {
  var libro = SpreadsheetApp.getActive();

  function pestana(nombre) {
    var h = libro.getSheetByName(nombre);
    return h ? h : libro.insertSheet(nombre);
  }

  var cfg = pestana('Config');
  cfg.getRange('A1').setValue('Clave');
  cfg.getRange('A2').setValue('Modo');
  if (!String(cfg.getRange('B2').getValue() || '').trim()) {
    cfg.getRange('B2').setValue('prueba');
  }
  cfg.getRange('A4').setValue('Pega tu clave en B1. En B2: prueba o produccion.');
  cfg.getRange('A1:A2').setFontWeight('bold');
  cfg.setColumnWidth(1, 190);
  cfg.setColumnWidth(2, 340);

  var cat = pestana('Catalogo');
  cat.clear();
  cat.getRange('A1:E1')
     .setValues([['id', 'producto', 'precio publico', 'mi precio', 'stock']])
     .setFontWeight('bold');
  cat.setFrozenRows(1);
  cat.setColumnWidth(2, 320);

  var ped = pestana('Pedidos');
  ped.clear();
  ped.getRange('A1:G1')
     .setValues([['id producto', 'cantidad', 'codigo pedido', 'estado', 'entregado', 'total', 'whatsapp cliente']])
     .setFontWeight('bold');
  ped.setFrozenRows(1);
  ped.setColumnWidth(3, 190);
  ped.setColumnWidth(5, 380);
  ped.setColumnWidth(7, 180);
  // Los numeros de telefono se escriben como TEXTO: si no, la hoja se come
  // el cero inicial y manda el mensaje a un numero que no existe.
  ped.getRange('G2:G').setNumberFormat('@');

  // La hoja en blanco que Google crea por defecto ya no hace falta.
  var sobra = libro.getSheetByName('Hoja 1') || libro.getSheetByName('Sheet1');
  if (sobra && libro.getSheets().length > 3) { libro.deleteSheet(sobra); }

  libro.setActiveSheet(cfg);
  libro.toast('Listo. Pega tu clave en Config B1 y usa el menu Juego Digital.');
}

// ---------- Menu ----------
function onOpen() {
  SpreadsheetApp.getUi()
    .createMenu('Juego Digital')
    .addItem('0. Instalar la plantilla', 'instalar')
    .addSeparator()
    .addItem('1. Traer catalogo', 'traerCatalogo')
    .addItem('2. Crear pedidos', 'crearPedidos')
    .addItem('3. Traer codigos entregados', 'actualizarEstados')
    .addToUi();
}

3. Instálala de un clic

Vuelve a la hoja y recárgala: arriba aparece el menú Juego Digital. Pulsa 0. Instalar la plantilla y se arma sola —las tres pestañas, los títulos y el formato—. Solo queda pegar tu clave en Config B1.

La primera vez Google te pedirá permiso para que el script salga a internet. Es normal: el permiso es para hablar con nuestra API, nada más. Si te avisa de que la app «no está verificada», entra en Configuración avanzada — Ir al proyecto: el aviso sale porque el script es tuyo, no está publicado en ninguna tienda.

4. Úsala

  • Traer catálogo llena la pestaña Catalogo con tus precios.
  • En Pedidos, escribe el id del producto en la columna A y la cantidad en la B.
  • Opcional: pon el WhatsApp de tu cliente en la columna G y el código le llegará a él desde tu número — sin que reenvíes nada.
  • Crear pedidos los compra; Traer códigos entregados rellena la entrega.

Empieza en modo prueba (Config B2 = prueba): no gasta saldo. Cuando todo funcione, cambia esa celda a produccion y pega tu clave real — no hay que tocar el código.

Soporte para integradores

Si algo no responde como dice esta página, escríbenos con el código del pedido y la hora: lo revisamos con el registro del servidor.

Escribir por WhatsApp