Saltar al contenido

Para desarrolladores

API y webhooks de bigger Control

Conecte su tienda en línea u otro sistema: consulte facturas, clientes, productos y cobros, emita facturas desde su sistema y reciba avisos firmados cuando algo pase en su empresa.

Para empezar

La API vive en https://biggercontrol.com/api/publica/v1/ (el entorno de pruebas, en prueba.biggercontrol.com). Habla JSON, todos los textos de error vienen en español y los importes son siempre texto con dos decimales ("575.00"), nunca números, para no perder centavos.

  1. Cree una llave. Quien administra la empresa entra a Administración › Conexiones, le pone un nombre (por ejemplo «Tienda en línea») y elige su permiso: solo leer, o leer y emitir facturas. La llave se muestra una sola vez: cópiela en ese momento. Si se pierde, se revoca y se crea otra.
  2. Llámela desde su servidor, nunca desde una página web: la API no admite CORS y rechaza los pedidos que traen la cabecera Origin. Una llave dentro de una página la ve cualquiera.
  3. Pruebe primero. Las llaves del entorno de pruebas empiezan con bc_test_ y las de producción con bc_live_; una no sirve en el entorno de la otra.
curl https://biggercontrol.com/api/publica/v1/facturas?limite=5 \
  -H "Authorization: Bearer bc_live_SU_LLAVE_AQUI"

La empresa sale siempre de la llave: el pedido no dice (ni puede decir) de qué empresa es. Una llave solo ve lo de su empresa.

Responsabilidad fiscal

Una factura emitida por la API es una factura fiscal de su empresa. Gasta un número de su CAI, queda en el libro de ventas y en la declaración del ISV, igual que una emitida en pantalla. Quien conecta el sistema responde por lo que ese sistema emite: los datos del cliente, los precios, el ISV y que no se emita dos veces lo mismo. Pruebe siempre con una llave bc_test_ en el entorno de pruebas, y use una Idempotency-Key distinta por cada pedido de su tienda.

Autenticación

Cada pedido lleva la llave en la cabecera Authorization: Bearer <llave>. Bigger Control solo guarda una huella de la llave (HMAC-SHA256 con un secreto del servidor): ni nosotros podemos volver a mostrarla. Una llave revocada deja de servir en el acto.

PermisoPuede
Solo leerConsultar facturas, clientes, productos y cobros pendientes.
Leer y emitir facturasLo anterior y además emitir facturas. No puede anular, registrar pagos ni cambiar nada de la empresa.

Errores

Toda respuesta que no sale bien trae el código HTTP y un JSON con un codigo (para su programa) y un mensaje en español (para una persona):

{
  "error": {
    "codigo": "pedido_rechazado",
    "mensaje": "Escriba al menos una línea de la factura.",
    "faltas": ["Escriba al menos una línea de la factura."]
  }
}
HTTPcodigoQué pasó
400idempotency_key_falta, idempotency_key_mala, cuerpo_malo, parametro_maloFalta o no vale la Idempotency-Key, el cuerpo no es un objeto JSON de a lo más 64 KB, o un parámetro de la dirección no es válido.
401llave_falta, llave_invalidaNo viene la llave, o no existe, es de otro entorno o fue revocada.
403sin_permiso, origen_no_permitidoLa llave no tiene ese permiso (por ejemplo, emitir con una llave de solo leer), la empresa no tiene el módulo (productos necesita Inventario) o el pedido viene de una página web.
404no_existe, no_encontradaEsa dirección o ese recurso no existe.
405metodo_no_permitidoEse método no existe para esa dirección (la cabecera Allow dice cuáles sí).
409idempotency_key_reusada, ocupadoLa Idempotency-Key ya se usó con una factura distinta, o hay otra factura emitiéndose en ese instante (repita el pedido).
415tipo_no_permitidoFalta Content-Type: application/json.
422pedido_rechazado, campo_no_permitidoLos datos no pasan las reglas (RTN, montos, líneas…; faltas trae la lista) o el pedido trae campos que la API no acepta.
423empresa_bloqueadaEl sistema bloqueó la emisión de la empresa por seguridad. Se puede leer, no emitir; avise a quien administra.
429limite_excedidoDemasiados pedidos (vea Límites). La cabecera Retry-After dice cuántos segundos esperar.
503reintentar, no_disponibleNo se pudo confirmar si la factura salió: repita el mismo pedido con la misma Idempotency-Key.

Límites

  • 100 pedidos por minuto por llave. Pasado el límite, 429 con Retry-After. Otra llave de la misma empresa no se ve afectada.
  • Una dirección que manda muchas llaves que no valen se frena un rato, aunque después mande una buena.
  • El cuerpo de un pedido puede pesar hasta 64 KB. Las listas se piden de a 50 como máximo.
  • Una empresa puede tener hasta 10 llaves vigentes y 5 webhooks activos.

Facturas

GET /facturas: la lista, de la más nueva a la más vieja. Parámetros opcionales: buscar (por número o cifras de él, nombre del cliente sin importar mayúsculas ni tildes, o RTN), limite (1 a 50, por omisión 25), antes (el siguiente de la página anterior) y estado (emitida o anulada).

curl "https://biggercontrol.com/api/publica/v1/facturas?limite=2&estado=emitida" \
  -H "Authorization: Bearer bc_live_SU_LLAVE_AQUI"

{
  "facturas": [
    { "correlativo": "000-001-01-00000012", "fecha": "2026-10-16", "cliente": "TIENDA S.A.",
      "rtn": "08019999999999", "total": "575.00", "estado": "emitida", "cobro": null }
  ],
  "siguiente": "000-001-01-00000011",
  "total": 12
}

siguiente es null cuando no hay más páginas; total cuenta todas las del filtro.

GET /facturas/{correlativo}: una factura con sus líneas.

{
  "factura": {
    "correlativo": "000-001-01-00000012", "estado": "emitida", "motivo": null, "cobro": null,
    "fecha": "2026-10-16", "cliente": "TIENDA S.A.", "rtn_cliente": "0801-9999-999999",
    "condicion": "Contado", "vence": "", "cai": "...", "orden_compra": "",
    "lineas": [ { "cantidad": "2", "descripcion": "Camisa blanca", "precio": "250.00", "descuento": "0.00", "total": "500.00" } ],
    "descuento": "0.00", "subtotal": "500.00", "gravado": "500.00", "importe_exento": "0.00", "isv": "75.00", "total": "575.00"
  }
}

Una factura anulada trae "estado": "anulada" y su motivo.

Emitir una factura

POST /facturas con una llave de leer y emitir facturas. Usa el mismo motor que la pantalla de Nueva factura: el siguiente número del CAI vigente, el ISV, el candado y todas las validaciones. El número, la fecha y la clave de emisión los pone el sistema: no se mandan (si vienen, el pedido se rechaza con campo_no_permitido).

La cabecera Idempotency-Key es obligatoria (de 8 a 64 letras, números, guion o guion bajo; por ejemplo el número de pedido de su tienda). Si la red falla y usted repite el pedido con la misma clave y el mismo contenido, recibe la misma factura (200, "repetida": true, cabecera Idempotent-Replayed: true) y no se emite otra. La misma clave con un contenido distinto es 409.

curl -X POST https://biggercontrol.com/api/publica/v1/facturas \
  -H "Authorization: Bearer bc_live_SU_LLAVE_AQUI" \
  -H "Idempotency-Key: pedido-tienda-1001" \
  -H "Content-Type: application/json" \
  -d '{
    "cliente": "TIENDA EN LINEA S.A.",
    "rtn": "08019999999999",
    "condicion": "Contado",
    "lineas": [ { "descripcion": "Camisa blanca", "cantidad": "2", "precio": "250" } ]
  }'

HTTP 201
{ "factura": { "correlativo": "000-001-01-00000012", "fecha": "2026-10-16", "total": "575.00", "estado": "emitida", "repetida": false } }
CampoQué es
cliente (obligatorio)Nombre o razón social del cliente.
rtn (obligatorio)RTN del cliente: 14 números (se aceptan guiones). Para consumidor final use el que su empresa use en pantalla.
lineas (obligatorio)De 1 a 6 líneas: descripcion, cantidad y precio (texto con cifras, precio sin ISV); opcional exento: true si no paga ISV y, con el módulo Inventario, producto (el id de GET /productos) para que la venta baje la existencia.
condicion"Contado" o "Crédito". Sin ella se toma como crédito.
descuentoDescuento en lempiras, como texto (por omisión, ninguno).
vence, plazo_mesesVencimiento (AAAA-MM-DD) o meses de crédito, solo en crédito.
cobro, orden_compra, ingresoReferencias opcionales que salen impresas en la factura.
bodegaCon Inventario, el id de la bodega de donde salen los productos.

La respuesta puede traer avisos (por ejemplo, sin existencia suficiente): no impiden la factura.

Si recibe 503 (reintentar), no se sabe si la factura salió: repita el pedido con la misma Idempotency-Key. Nunca genere una clave nueva para reintentar.

Clientes

GET /clientes: el directorio de clientes, los más usados primero. Parámetros: q (busca en el nombre y el RTN) y limite (1 a 500).

{ "clientes": [ { "rtn": "08019999999999", "nombre": "TIENDA S.A.", "nombre_comercial": "", "direccion": "", "telefono": "", "correo": "" } ], "total": 1 }

Productos

GET /productos: el catálogo con su existencia. Necesita que a la empresa le hayan activado el módulo Inventario (si no, 403). No incluye costos.

{
  "productos": [ { "id": 3, "codigo": "CAM-01", "barras": "", "nombre": "Camisa blanca", "tipo": "producto", "unidad": "pieza",
                   "precio": "250.00", "gravado": true, "activo": true, "existencia": "10", "minimo": "5", "bajo_minimo": false,
                   "por_bodega": { "1": "10" } } ],
  "bodegas": [ { "id": 1, "nombre": "Principal", "por_omision": true, "activa": true } ]
}

Un servicio ("tipo": "servicio") no lleva existencia: existencia va vacía.

Cobros pendientes

GET /cobros/pendientes: lo que los clientes deben (facturas a crédito con saldo), agrupado por cliente.

{ "hoy": "2026-10-17", "pendiente": "1725.00", "vencido": "0.00", "n": 3,
  "clientes": [ { "cliente": "TIENDA S.A.", "rtn": "08019999999999", "debe": "1725.00", "vencido": "0.00",
                  "facturas": [ { "correlativo": "000-001-01-00000012", "fecha": "2026-10-16", "vence": "2026-11-15",
                                  "total": "575.00", "pagado": "0.00", "saldo": "575.00", "dias_atraso": 0 } ] } ] }

Asistentes de IA (MCP)

bigger Control tiene un servidor MCP remoto (Model Context Protocol) para que su asistente de IA, como Claude o ChatGPT, consulte la empresa y prepare facturas por usted. Vive en https://biggercontrol.com/mcp (el entorno de pruebas, en prueba.biggercontrol.com/mcp), usa el transporte Streamable HTTP con mensajes JSON-RPC 2.0 por POST y habla la versión 2026-07-28 del protocolo y las anteriores (2025-11-25, 2025-06-18 y 2025-03-26, con initialize). No ofrece canal GET, y, como la API pública, no admite CORS ni pedidos con Origin.

Cómo conectarlo

  • Claude (claude.ai) y ChatGPT piden OAuth: quien administra abre Administración › Conexiones, copia la dirección y la pega al añadir un conector personalizado (los nombres de los menús dependen del asistente y de su plan). Se abre la pantalla de bigger Control, elige solo leer o leer y emitir, aprueba y escribe su contraseña. La conexión queda en la lista de llaves con su nombre y fecha (por ejemplo «Claude · 17/10/2026») y se revoca desde ahí, en el acto.
  • Claude Code, Claude Desktop y Cursor dejan poner una cabecera: use una llave de la API como Authorization: Bearer <llave>.
claude mcp add --transport http bigger-control https://biggercontrol.com/mcp \
  --header "Authorization: Bearer bc_live_SU_LLAVE_AQUI"

OAuth 2.1

Sin token, /mcp contesta 401 con WWW-Authenticate: Bearer resource_metadata="…/.well-known/oauth-protected-resource/mcp". Los metadatos están en /.well-known/oauth-protected-resource y /.well-known/oauth-authorization-server (los únicos con CORS abierto: son públicos y de solo lectura). Hay registro dinámico de clientes públicos (POST /oauth/register), PKCE con S256 obligatorio y el parámetro resource. El código de autorización vale 2 minutos y un uso; el token de acceso, 1 hora; el de renovación, 30 días y también un uso (cada renovación entrega un par nuevo, y presentar uno ya usado revoca la conexión). Todo secreto se guarda con HMAC, como las llaves. Los tokens solo valen en /mcp, atados a una empresa y a un permiso.

Herramientas

HerramientaQué hacePermiso
resumen_del_mesFacturado con y sin ISV, emitidas, anuladas, ISV del mes y lo que deben los clientes.Leer
buscar_facturasPor número, cliente o RTN, y por estado.Leer
ver_facturaUna factura completa.Leer
clientesEl directorio de clientes.Leer
cobros_pendientesLo que deben, con vencidas y días de atraso.Leer
productosCatálogo con existencias (si la empresa tiene Inventario).Leer
preparar_facturaVista previa con totales y el número que tocaría, más una confirmacion de un solo uso que vence en 10 minutos. No emite.Leer y emitir
emitir_facturaEmite la factura preparada. Exige la confirmacion; repetir la misma no duplica (la segunda vez se rechaza). Respeta el cupo del plan.Leer y emitir

Las herramientas llevan las anotaciones MCP: readOnlyHint en las de leer, y destructiveHint e idempotentHint en emitir_factura. Anular una factura no se expone: se hace en la pantalla. Cada factura emitida así queda en la bitácora de la empresa como «emitida por asistente: Claude» (el nombre del asistente conectado). Los pedidos cuentan en el mismo límite por llave que la API (100 por minuto), y la empresa sale siempre del token.

Responsabilidad fiscal: la factura que su asistente emita es una factura de su empresa y usted responde por ella, igual que por las de la pantalla. Por eso el asistente tiene que mostrarle la vista previa y pedirle permiso antes de llamar a emitir_factura.

Webhooks

En Administración › Conexiones quien administra registra la dirección de su sistema y elige los eventos. Bigger Control envía un POST con JSON a esa dirección cada vez que el evento ocurre.

  • La dirección debe ser https, de un sitio público de internet, sin usuario ni contraseña y en el puerto normal (443). Nunca se envía a direcciones locales o privadas (localhost, 10.x, 172.16 a 172.31, 192.168.x, 169.254.x, ::1…) ni a direcciones numéricas: se valida al registrarla y otra vez en cada envío.
  • No se siguen redirecciones. Su sistema debe contestar con un código 2xx en menos de 8 segundos; no hace falta que devuelva nada en el cuerpo (y bigger Control no lo guarda).
  • Reintentos: si no contesta 2xx, se repite a 1 minuto, 5 minutos, 30 minutos, 2 horas, 6 horas y 24 horas. Tras 7 intentos la entrega queda «Fallida». El registro de entregas está en la misma pantalla.
  • Un aviso puede llegar más de una vez (un reintento después de que su sistema ya lo procesó): use el id del aviso (ent_123) para ignorar los repetidos. Los avisos no garantizan el orden.
  • El secreto de la firma (whsec_…) se muestra una sola vez al registrar el webhook.

Verificar la firma

Cada envío trae estas cabeceras: X-BiggerControl-Evento, X-BiggerControl-Entrega y X-BiggerControl-Firma, con la forma t=1760000000,v1=<hexadecimal>. La firma es el HMAC-SHA256, en hexadecimal, del texto «t.cuerpo» (el valor de t, un punto y el cuerpo EXACTO que recibió, sin volver a formatearlo) con su secreto como llave.

  1. Lea t y v1 de la cabecera.
  2. Calcule el HMAC-SHA256 de t + "." + cuerpo con su secreto whsec_….
  3. Compárelo con v1 en tiempo constante.
  4. Rechace el aviso si t es de hace más de 5 minutos (evita que repitan uno viejo). Cada reintento se firma de nuevo con la hora de su envío.
// Node.js
import { createHmac, timingSafeEqual } from "node:crypto";

export function firmaValida(cuerpoCrudo, cabecera, secreto) {
  const t = /t=(\d+)/.exec(cabecera)?.[1];
  const v1 = /v1=([0-9a-f]{64})/.exec(cabecera)?.[1];
  if (!t || !v1 || Math.abs(Date.now() / 1000 - Number(t)) > 300) return false;
  const esperada = createHmac("sha256", secreto).update(`${t}.${cuerpoCrudo}`).digest("hex");
  return timingSafeEqual(Buffer.from(esperada), Buffer.from(v1));
}
# Python
import hmac, hashlib, re, time

def firma_valida(cuerpo_crudo: bytes, cabecera: str, secreto: str) -> bool:
    t = re.search(r"t=(\d+)", cabecera); v1 = re.search(r"v1=([0-9a-f]{64})", cabecera)
    if not t or not v1 or abs(time.time() - int(t.group(1))) > 300:
        return False
    esperada = hmac.new(secreto.encode(), t.group(1).encode() + b"." + cuerpo_crudo, hashlib.sha256).hexdigest()
    return hmac.compare_digest(esperada, v1.group(1))

Eventos y campos

Todos los avisos tienen la misma envoltura. Los datos del evento son lo mínimo (números, fechas, totales y estados), sin el nombre ni el RTN del cliente: pida el detalle con la API.

{
  "id": "ent_41",
  "evento": "factura.emitida",
  "creado": "2026-10-16T16:42:05.000Z",
  "entorno": "produccion",
  "datos": { "correlativo": "000-001-01-00000012", "fecha": "2026-10-16", "total": "575.00", "estado": "emitida" }
}
EventoCuándoCampos de datos
factura.emitidaSe emite una factura nueva (por pantalla, caja o API). Repetir una Idempotency-Key no avisa otra vez.correlativo, fecha, total, estado
factura.anuladaSe anula una factura.correlativo, estado
pago.registradoSe registra un pago de un cliente.id, factura, fecha, monto, saldo (lo que queda), saldada
nota.emitidaSe emite una nota de crédito o de débito.correlativo, tipo (credito o debito), factura, fecha, total
inventario.bajo_minimoUna factura deja un producto por debajo de su mínimo (una vez por cruce, no en cada venta).producto (id), codigo, existencia, minimo, factura

Dudas o algo que falta. Escríbanos a soporte@biggercontrol.com con el código y el mensaje del error. Nunca nos mande su llave ni su secreto.