API REST de facturación electrónica para Bolivia, integrada con el SIAT de Impuestos Nacionales. Esta guía te lleva de cero a tu primera factura en minutos.
Documentación interactiva (Swagger):
https://api.factura.bo/docs
| Entorno | URL Base | SIAT |
|---|---|---|
| Sandbox (pruebas) | https://apisandbox.factura.bo |
Piloto |
| Producción | https://api.factura.bo |
Real |
Los endpoints son idénticos en ambos entornos. Desarrolla contra sandbox y cambia la URL base al pasar a producción.
Todas las peticiones protegidas llevan tu API Key en la cabecera:
X-API-KEY: tu_api_key
La API Key identifica a tu empresa (NIT) y su configuración: modalidad de facturación, créditos disponibles y token SIAT. Se obtiene en el panel de administración o contactando a gm@simplifyit.com.bo.
Todos los endpoints responden el mismo envelope:
{
"ok": true,
"datos": { },
"error": null,
"timestamp": "2026-07-02T14:30:00+00:00"
}
| HTTP | Significado |
|---|---|
200 |
Operación exitosa (ok: true) |
400 |
Datos inválidos, falta configuración, o el SIAT rechazó el documento |
402 |
Créditos de facturación agotados |
403 |
API Key inválida, cliente inactivo, o email en sandbox (ver §8) |
404 |
Recurso no encontrado / punto de venta no sincronizado |
409 |
Ya hay una operación en curso con la misma X-Idempotency-Key, o intentaste revertir una anulación sobre una factura que no está ANULADA — reintenta o esperá unos segundos |
502 |
El SIAT no respondió, se cayó a mitad de la operación, o rechazó con un error no HTTP |
Cuando tu request llegó bien pero Impuestos Nacionales lo rechazó, el error
viene como HTTP 400 o 502 con este formato:
{
"detail": "El SIAT rechazó la factura: [{'codigo': 1040, 'descripcion': 'FECHA DE EMISION NO SE ENCUENTRA EN EL RANGO DE CONTINGENCIA ...'}]"
}
detail siempre empieza con una frase fija ("El SIAT rechazó...") seguida de
la lista de mensajes tal cual los devolvió el SIAT — parseá por el patrón
'codigo': X si necesitás manejar casos específicos en tu código.
| Código | Significa | Qué hacer |
|---|---|---|
123 |
CUFD fuera de tolerancia (vencido) | Llamá a POST /v1/sincronizar — el CUFD vence cada 24h |
981 |
El evento significativo tiene fecha_fin en el futuro, o se solapa con otro ya registrado |
Registrá el evento después de que termine el corte, nunca antes; no declares ventanas que se crucen con eventos previos |
984 |
El CUFD no corresponde a la ventana del evento declarado | Normalmente se resuelve solo; si persiste, resincronizá CUFD y reintentá |
902 "Cafc no encontrado" |
Falta el campo cafc en una factura offline de tipo de evento 5, 6 o 7 |
Ver §7.1 — esos tres tipos exigen CAFC |
1040 |
La fecha de emisión de una factura offline queda fuera del rango [inicio, fin] del evento |
Declará la ventana con el fecha_emision real de tus facturas, no con tu reloj local (ver §7) |
1047 |
El número de factura excede el rango autorizado por tu CAFC | Pedí al SIN un CAFC nuevo con un rango mayor |
954 |
El paquete de contingencia supera las 500 facturas permitidas | Mandá los paquetes de a 500 como máximo |
1002 / 1006 |
CUF o CUFD del archivo no coincide con lo esperado por el SIAT en un paquete | No mezcles facturas de eventos o CUFD distintos en un mismo paquete |
1049 |
En una nota de crédito/débito, la línea codigo_detalle_transaccion=1 no replica exacto la cantidad/precio de la factura original |
Ver §6 — esa línea tiene que ser una copia exacta del ítem original |
Obtiene los códigos CUIS y CUFD del SIAT. El CUFD vence cada 24 h: llama a este endpoint todos los días antes de facturar (idealmente con un cron a las 00:05 hora Bolivia).
curl -X POST https://apisandbox.factura.bo/v1/sincronizar \
-H "X-API-KEY: $API_KEY" -H "Content-Type: application/json" \
-d '{
"nit": 123456789,
"codigo_sistema": "TU_CODIGO_SISTEMA",
"sucursal": 0,
"punto_venta": 0
}'
curl -X POST https://apisandbox.factura.bo/v1/sincronizar/catalogos \
-H "X-API-KEY: $API_KEY" -H "Content-Type: application/json" \
-d '{"nit": 123456789, "codigo_sistema": "TU_CODIGO_SISTEMA"}'
Se descargan los 18 catálogos del SIAT en una sola llamada. Luego consulta
cualquiera con GET /v1/catalogos/{nombre}: actividades,
actividades_documento_sector, eventos_significativos, fecha_hora,
leyendas, mensajes_servicios, metodos_pago, motivos_anulacion,
paises, productos_servicios, tipos_documento_identidad,
tipos_documento_sector, tipos_emision, tipos_factura,
tipos_habitacion, tipos_moneda, tipos_punto_venta, unidades_medida.
curl -X POST https://apisandbox.factura.bo/v1/facturas \
-H "X-API-KEY: $API_KEY" -H "Content-Type: application/json" \
-d '{
"emisor": {
"sucursal": 0,
"punto_venta": 0,
"actividad_economica": "620000"
},
"cliente": {
"tipo_documento": 5,
"numero_documento": "987654321",
"razon_social": "ACME S.R.L.",
"correo": "cliente@acme.bo"
},
"metodo_pago": 1,
"items": [
{
"codigo_producto": "SRV-001",
"codigo_sin": 83141,
"descripcion": "Desarrollo de software",
"cantidad": 1,
"unidad_medida": 58,
"precio_unitario": 1500.00
}
]
}'
Respuesta:
{
"ok": true,
"datos": {
"cuf": "3001000100001000000001241220000071",
"numero_factura": 42,
"estado": "EMITIDA",
"url_pdf": "https://storage.googleapis.com/...",
"url_xml": "https://storage.googleapis.com/...",
"pdf_base64": "JVBERi0xLjQK...",
"respuesta_siat": { "transaccion": true }
}
}
Guarda el CUF: es el identificador único de la factura para consultas, anulaciones y notas de crédito.
Una factura recibida por el SIAT no puede revertirse, solo anularse. Para
que un timeout o un reintento de red nunca genere un duplicado fiscal, envía
el header opcional X-Idempotency-Key con un valor único por operación
(el ID de tu pedido, un UUID, etc.):
curl -X POST https://apisandbox.factura.bo/v1/facturas \
-H "X-API-KEY: $API_KEY" \
-H "X-Idempotency-Key: pedido-4521" \
-H "Content-Type: application/json" -d '{ ... }'
409 (espera su respuesta).Las claves se recuerdan por 30 días. No aplica dentro de /v1/facturas/lote.
Cada tipo de actividad usa su propio endpoint con campos específicos.
Si tu actividad no tiene sector especial, usa el general (POST /v1/facturas).
| Código SIAT | Sector | Endpoint |
|---|---|---|
| 1 | Compra y Venta (general) | POST /v1/facturas |
| 2 | Alquiler de Bien Inmueble | POST /v1/facturas/alquiler |
| 3 | Exportación de bienes | POST /v1/facturas/exportacion |
| 4 | Exportación en Libre Consignación | POST /v1/facturas/exportacion-libre-consignacion |
| 6 | Servicio Turístico y Hospedaje (Ley 292, sin crédito fiscal) | POST /v1/facturas/turismo |
| 8 | Tasa Cero (libros, transporte internacional) | POST /v1/facturas/tasa-cero |
| 11 | Sector Educativo | POST /v1/facturas/educacion |
| 13 | Servicio Básico (agua, gas, electricidad) | POST /v1/facturas/servicio-basico |
| 14 | Alcanzada por el ICE | POST /v1/facturas/ice |
| 16 | Hotel | POST /v1/facturas/hotel |
| 17 | Hospital y Clínica | POST /v1/facturas/hospital |
| 28 | Exportación de Servicios | POST /v1/facturas/exportacion-servicios |
| 24 | Nota Fiscal Crédito/Débito | POST /v1/notas/fiscal |
| 47 | Nota Crédito/Débito/Descuento | POST /v1/notas |
| 48 | Nota Crédito/Débito con ICE | POST /v1/notas/ice |
La lista siempre actualizada: GET /v1/catalogos/sectores (no requiere pasos previos).
| Campo | Tipo | Descripción |
|---|---|---|
emisor.sucursal |
int | 0 = casa matriz |
emisor.punto_venta |
int | 0 si solo tienes uno |
emisor.actividad_economica |
string | Código CAEB (catálogo actividades) |
cliente.tipo_documento |
int | 1=CI, 2=CEX, 3=Pasaporte, 4=Otro, 5=NIT |
cliente.numero_documento |
string | "0" para consumidor final |
cliente.razon_social |
string | Obligatorio con NIT |
metodo_pago |
int | 1=Efectivo, 2=Tarjeta, 7=Transferencia (catálogo metodos_pago) |
moneda |
int | 1=BOB (defecto), 2=USD |
tipo_cambio |
float | Solo si moneda != 1. Usa el oficial: GET /ExchangeRate |
descuento_adicional |
float | Descuento global en Bs |
contingencia |
bool | true = emisión offline (ver §7) |
codigo_excepcion |
int | 1 = emitir aunque el NIT del cliente sea inválido |
numero_tarjeta |
string | Primeros 4 + últimos 4 dígitos, el resto enmascarado con asteriscos: 1234****5678 |
cafc |
string | Código de Autorización de Facturación por Contingencia. Solo con contingencia: true y tipo_evento 5, 6 o 7 (ver §7.1) |
| Campo | Tipo | Descripción |
|---|---|---|
codigo_producto |
string | Tu código interno |
codigo_sin |
int | Código del catálogo productos_servicios del SIAT |
descripcion |
string | Texto que aparece en la factura |
cantidad |
float | Hasta 5 decimales |
unidad_medida |
int | Catálogo SIAT (58=Servicio, 1=Unidad, 2=Kg…) |
precio_unitario |
float | En la moneda de la factura |
descuento |
float | Descuento de este ítem en Bs |
numero_serie / numero_imei |
string | Solo sector Compra y Venta (1). Para equipos con número de serie o IMEI que el SIAT exige rastrear |
Para emisiones masivas (mensualidades, ciclos de servicios básicos, cierres de día) envía varias facturas en un solo request con éxito parcial: cada una se procesa de forma independiente y las fallidas se reportan por índice sin afectar a las demás.
curl -X POST https://apisandbox.factura.bo/v1/facturas/lote \
-H "X-API-KEY: $API_KEY" -H "Content-Type: application/json" \
-d '{
"facturas": [
{"sector": 1, "factura": { ...igual que POST /v1/facturas... }},
{"sector": 11, "factura": { ...igual que POST /v1/facturas/educacion... }}
]
}'
La respuesta indica total, exitosas, fallidas y un array resultados
donde resultados[i] corresponde a facturas[i]: las exitosas traen su CUF y
enlaces; las fallidas, el motivo. Corrige solo esas y reenvíalas en otro lote.
Las notas de crédito/débito no se aceptan en lote.
Ajustan o revierten una factura ya emitida sin eliminarla. Referencia
obligatoria a la factura original, y el detalle no es una copia simple
de la factura original: por cada ítem que ajustás mandás dos líneas,
distinguidas por codigo_detalle_transaccion — esto no es un "motivo", es
una etiqueta estructural que el SIAT exige:
1 → línea que replica el ítem exacto de la factura original (misma
cantidad y precio — el SIAT rechaza con código 1049 si no coinciden).2 → línea propia de esta nota, el ajuste real (para una devolución
total es igual a la línea 1; para una devolución/descuento parcial, ahí
va la diferencia).monto_total_devuelto se calcula sobre las líneas tipo 2, nunca sobre la
factura original. monto_efectivo_credito_debito no es el mismo valor:
equivale al 13% (IVA) de monto_total_devuelto, redondeado a 2 decimales.
curl -X POST https://apisandbox.factura.bo/v1/notas \
-H "X-API-KEY: $API_KEY" -H "Content-Type: application/json" \
-d '{
"emisor": {"sucursal": 0, "punto_venta": 0, "actividad_economica": "620000"},
"cliente": {"tipo_documento": 5, "numero_documento": "987654321", "razon_social": "ACME S.R.L."},
"cuf_factura_original": "3001000100001000000001241220000071",
"numero_factura_original": 42,
"fecha_emision_factura_original": "2026-06-15",
"monto_total_original": 1500.00,
"monto_total_devuelto": 500.00,
"monto_efectivo_credito_debito": 65.00,
"items": [
{
"nro_item": 1,
"codigo_producto": "SRV-001",
"codigo_sin": 83141,
"descripcion": "Desarrollo de software",
"cantidad": 1,
"precio_unitario": 500.00,
"codigo_detalle_transaccion": 1
},
{
"nro_item": 1,
"codigo_producto": "SRV-001",
"codigo_sin": 83141,
"descripcion": "Desarrollo de software",
"cantidad": 1,
"precio_unitario": 500.00,
"codigo_detalle_transaccion": 2
}
]
}'
El XSD del SIAT exige un mínimo de 2 líneas de detalle en total, aunque solo estés ajustando un ítem.
Cuando pierdas conexión con el SIAT:
1. POST /v1/contingencia/evento → registra el corte (ver tipos de evento abajo)
2. POST /v1/facturas → emite normalmente con "contingencia": true
3. POST /v1/contingencia/paquete → al volver la conexión, envía todo lo acumulado
4. POST /v1/contingencia/validar-paquete → confirma que el SIAT procesó el paquete (codigo_recepcion del paso 3)
Las facturas offline quedan en estado OFFLINE y recién pasan a EMITIDA
(y descuentan su crédito) en el paso 4, una por una, según lo que el SIAT
confirme para cada archivo — no en el paso 3. El SIAT procesa los paquetes de
forma asíncrona: la validación del paso 4 puede haber archivos observados
(rechazados individualmente) aunque transaccion: true a nivel paquete —
esos quedan OFFLINE sin cobrarse. Revisá siempre datos.mensajes, no solo
el código HTTP. Podés llamar al paso 4 más de una vez para el mismo
codigo_recepcion (por ejemplo, mientras esperás a que el SIAT termine de
procesar) sin riesgo de que te cobre dos veces.
Importante — registrá el evento DESPUÉS del corte, no antes. fecha_fin
nunca puede quedar en el futuro (el SIAT lo rechaza con código 981), y la
ventana [fecha_inicio, fecha_fin] tiene que cubrir el momento real en que
emitiste cada factura offline. Si tu servidor y el nuestro tienen aunque sea
un pequeño desfase de reloj, construí la ventana con el campo fecha_emision
que te devuelve cada factura emitida (no con tu reloj local) para evitar el
código 1040 ("fecha de emisión fuera del rango de contingencia").
| Código | Descripción | ¿Necesita cafc? |
|---|---|---|
1 |
Corte del servicio de internet | No |
2 |
Inaccesibilidad al servicio web de la Administración Tributaria | No |
3 |
Ingreso a zonas sin internet por despliegue de punto de venta | No |
4 |
Venta en lugares sin internet | No |
5 |
Virus informático o falla de software | Sí |
6 |
Cambio de infraestructura de sistema o falla de hardware | Sí |
7 |
Corte de suministro de energía eléctrica | Sí |
La diferencia real: los tipos 1-4 son problemas de conectividad — tu
sistema sigue funcionando y puede firmar XML localmente, solo se corta el
enlace con el SIAT. Los tipos 5-7 son casos donde tu propio sistema no pudo
operar — para esos, el SIAT exige un CAFC (Código de Autorización de
Facturación por Contingencia), que se pide directamente a soporte del SIN
(no es autoservicio como el CAFC de facturas manuales impresas). Una vez
que lo tengas, incluilo como campo cafc en cada factura que emitas con
"contingencia": true para esos tipos de evento — sin él, el envío del
paquete se rechaza con código 902 ("Cafc no encontrado"). El CAFC viene
con un rango de números de factura autorizados; si lo excedés, el SIAT
rechaza con código 1047 y hay que pedir uno nuevo con un rango mayor.
Para auditar los cortes registrados:
GET /v1/contingencia/eventos?fecha=2026-07-01 → eventos significativos de esa fecha ante el SIAT
GET /v1/facturas → historial con filtros (?desde=&hasta=&estado=&nit_cliente=&limite=)
GET /v1/facturas/{cuf} → una factura (estado local + URLs de PDF/XML)
GET /v1/facturas/{cuf}/estado-siat → verificación EN TIEMPO REAL ante el SIAT
POST /v1/facturas/{cuf}/anular → anulación (motivo, ver tabla abajo)
POST /v1/facturas/{cuf}/revertir-anulacion → revierte una anulación: la factura vuelve a estar vigente
motivo |
Descripción |
|---|---|
1 |
Factura mal emitida |
2 |
Nota crédito-débito mal emitida |
3 |
Datos de emisión incorrectos |
4 |
Factura o nota crédito-débito devuelta |
(catálogo vigente: GET /v1/catalogos/motivos_anulacion)
La reversión solo aplica a facturas en estado ANULADA (responde 409 en otro
caso) y emite el webhook factura.anulacion_revertida al confirmarse.
Cada factura emitida devuelve url_publica: un enlace permanente que puedes
enviar a tu cliente por email, WhatsApp o QR. El CUF actúa como token de acceso.
GET /f/{cuf} → página de verificación (estado, emisor, fecha, descargas)
GET /f/{cuf}/pdf → descarga el PDF tamaño A4 (enlace siempre vigente)
GET /f/{cuf}/ticket → descarga el ticket de 80mm para impresoras térmicas
GET /f/{cuf}/xml → descarga el XML fiscal
Cada emisión devuelve ambos formatos gráficos: url_pdf (A4, para email y
archivo) y url_ticket (80mm, para el punto de venta).
A diferencia de url_pdf/url_xml (URLs firmadas que expiran), los enlaces
/f/{cuf}/... nunca caducan: generan una URL fresca en cada descarga.
Si al emitir incluyes cliente.correo, la factura se envía automáticamente
por email con el PDF adjunto y el enlace público de verificación.
Para reenviarla (o enviarla a otra dirección):
curl -X POST "https://api.factura.bo/v1/facturas/{cuf}/reenviar-email?email=otro@correo.com" \
-H "X-API-KEY: $API_KEY"
Si omites ?email=, se usa el correo registrado al emitir.
En sandbox nunca se envían emails. Las facturas de prueba no generan correos al cliente final, aunque incluyas
cliente.correo, y el endpoint de reenvío responde403. Así puedes probar con datos reales sin riesgo de notificar a nadie. El envío automático también puede activarse o desactivarse por cuenta en producción (responde403si está desactivado).
En vez de consultar el estado repetidamente, registra una URL de tu servidor y recibe los eventos cuando ocurren:
curl -X POST https://apisandbox.factura.bo/v1/webhooks \
-H "X-API-KEY: $API_KEY" -H "Content-Type: application/json" \
-d '{"url": "https://tu-sistema.com/webhooks/facturabo", "eventos": ["factura.*", "creditos.bajos"]}'
La respuesta incluye un secreto (whsec_...) que solo se muestra una vez.
Eventos disponibles: factura.emitida, factura.offline, factura.anulada,
factura.anulacion_revertida, nota.emitida, contingencia.paquete_enviado,
creditos.bajos, siat.caido, siat.recuperado, webhook.prueba.
Puedes suscribirte con * (todos) o por prefijo (factura.*).
siat.caido/siat.recuperado: te avisan cuando el SIAT de Impuestos Nacionales deja de responder (3 sondeos fallidos consecutivos) y cuando se recupera. Úsalos para activar el modo contingencia automáticamente en tu sistema, sin esperar a que una emisión falle.
Cada entrega va firmada (estándar Standard Webhooks) con estos headers:
Webhook-Id: evt_a1b2c3... ← único por evento; descarta duplicados con él
Webhook-Timestamp: 1751470000 ← rechaza mensajes con más de 5 min de antigüedad
Webhook-Signature: v1,K5oZfz... ← HMAC-SHA256 del contenido
Verifica la firma en tu servidor antes de confiar en el evento:
import base64, hashlib, hmac
def verificar_firma(secreto, headers, cuerpo_crudo):
llave = base64.b64decode(secreto.split("_", 1)[1])
contenido = f"{headers['webhook-id']}.{headers['webhook-timestamp']}.{cuerpo_crudo}"
esperada = "v1," + base64.b64encode(
hmac.new(llave, contenido.encode(), hashlib.sha256).digest()).decode()
return hmac.compare_digest(esperada, headers["webhook-signature"])
Si tu servidor no responde 2xx, la entrega se reintenta automáticamente con backoff exponencial. Gestión completa:
POST /v1/webhooks → registrar (devuelve el secreto)
GET /v1/webhooks → listar
DELETE /v1/webhooks/{id} → eliminar
POST /v1/webhooks/{id}/rotar → nuevo secreto
POST /v1/webhooks/{id}/probar → evento de prueba síncrono (valida tu firma)
POST /v1/nit/validar → valida el NIT del cliente ante el SIAT antes de facturar
GET /v1/cuenta → créditos restantes, modalidad, estado
GET /v1/cuenta/consumo → historial de créditos consumidos por día o por mes (?desde=&hasta=&agrupar_por=dia|mes)
GET /v1/cuenta/api-key → tu API Key y contra qué URL usarla
POST /v1/cuenta/api-key/regenerar → cambia tu API Key por una nueva
GET /v1/estado → estado de la API y del SIAT (sin autenticación)
POST /v1/operaciones/puntos-venta → registrar un punto de venta nuevo en el SIAT
GET /v1/operaciones/puntos-venta → listar puntos de venta registrados
DELETE /v1/operaciones/puntos-venta/{codigo} → cerrar (dar de baja) un punto de venta
La llave llega por correo al crear la cuenta, y también podés verla en app.factura.bo → Más → API Key. Desde ahí se regenera si se te filtró:
curl -X POST https://api.factura.bo/v1/cuenta/api-key/regenerar \
-H "X-API-KEY: tu_api_key"
[!WARNING] La llave anterior deja de funcionar en el acto. Todo lo que la esté usando se corta hasta que pegues la nueva.
Si entrás desde el portal con tu sesión, solo el propietario de la cuenta
puede ver o cambiar la llave; un usuario con rol cajero puede emitir pero no
llevársela.
GET /v1/cuenta te da la foto de hoy. Para entender tu ritmo de consumo —
cuánto gastaste esta semana, si el mes pasado tuviste un pico — usá
GET /v1/cuenta/consumo:
curl "https://api.factura.bo/v1/cuenta/consumo?desde=2026-07-01&hasta=2026-07-31&agrupar_por=dia" \
-H "X-API-KEY: $API_KEY"
{
"ok": true,
"datos": {
"desde": "2026-07-01",
"hasta": "2026-07-31",
"agrupado_por": "dia",
"total_consumido": 340,
"creditos_disponibles": 2790,
"consumo": [
{"periodo": "2026-07-01", "creditos_consumidos": 12},
{"periodo": "2026-07-02", "creditos_consumidos": 9}
]
}
}
Sin desde/hasta, devuelve los últimos 30 días. Solo cuenta facturas y
notas emitidas en línea: las offline (contingencia) no descuentan
crédito hasta que su paquete es validado por el SIAT.
¿No puedes emitir y sospechas que el SIAT está caído? Consulta
factura.bo/estado: sondeamos el SIAT cada
5 minutos con la operación oficial verificarComunicacion y publicamos su
estado (OPERATIVO / DEGRADADO / CAIDO), la latencia y el uptime de los
últimos 90 días, tanto de producción como del piloto.
La versión JSON es GET /v1/estado — pública, gratuita y sin API key:
{
"api": {"estado": "OPERATIVO", "ambiente": "produccion"},
"siat_produccion": {"estado": "OPERATIVO", "ultima_latencia_ms": 840, "uptime_30d": 99.87},
"siat_piloto": {"estado": "OPERATIVO", "ultima_latencia_ms": 1220, "uptime_30d": 99.62}
}
Para reaccionar sin consultar, suscríbete a los webhooks siat.caido y
siat.recuperado (sección 9).
Pensados para el contador de tu empresa:
GET /v1/reportes/libro-ventas?gestion=2026&mes=6 → Libro de Ventas IVA en CSV (formato RCV)
GET /v1/reportes/respaldo?gestion=2026&mes=6 → ZIP con todos los XML y PDF del mes
{numero}_{cuf}.xml y .pdf de cada factura
(parámetro formato=xml|pdf|ambos).GET /ExchangeRate → USD/BOB y UFV oficiales del día
GET /ExchangeRate/history?limit=30 → histórico
GET /ExchangeRate/history/2026-07-01 → una fecha específica
Se actualiza cada noche a las 00:05 hora Bolivia desde el sitio del Banco
Central de Bolivia. Úsalo para llenar tipo_cambio en facturas en USD.
| Modalidad | Cómo funciona | Requisito |
|---|---|---|
| 1 — Electrónica en Línea | El servicio firma el XML con tu certificado digital | Certificado .p12 (se sube al aprovisionar) |
| 2 — Computarizada en Línea | XML sin firma, con código de control | Solo token SIAT |
La modalidad se configura por empresa al aprovisionarla; el emisor no necesita cambiar nada en sus requests.
codigo_excepcion: 1).GET /v1/cuenta y recarga antes de agotarlos (HTTP 402).url_pdf/url_xml son URLs firmadas con expiración. Para
compartir con el cliente final usa url_publica (/f/{cuf}), que nunca
caduca y genera descargas frescas en cada acceso.factura.bo expone un servidor MCP (Model Context Protocol): conecta tu asistente de IA (Claude, ChatGPT, Cursor, etc.) y podrás facturar y consultar conversando.
"Emite una factura a ACME S.R.L., NIT 987654321, por 2 horas de consultoría a 500 Bs cada una" → el asistente emite la factura y te devuelve el PDF.
Configuración (ejemplo para Claude Desktop / clientes compatibles):
{
"mcpServers": {
"factura-bo": {
"type": "http",
"url": "https://api.factura.bo/mcp",
"headers": { "X-API-KEY": "tu_api_key" }
}
}
}
En Claude Code:
claude mcp add --transport http factura-bo https://api.factura.bo/mcp \
--header "X-API-KEY: tu_api_key"
Herramientas disponibles:
| Herramienta | Requiere API Key |
|---|---|
consultar_tipo_de_cambio — USD y UFV oficiales del BCB |
No |
consultar_estado_siat — ¿está caído el SIAT? Estado y uptime |
No |
listar_sectores — tipos de factura soportados |
No |
consultar_creditos — saldo de tu cuenta |
Sí |
validar_nit — verifica un NIT ante el SIAT |
Sí |
listar_facturas — historial con filtros |
Sí |
consultar_factura — detalle por CUF |
Sí |
emitir_factura — emite factura de Compra y Venta (Sector 1) |
Sí |
Por seguridad, la anulación no está disponible por MCP (es permanente):
hazla desde tu sistema o con el API. Para pruebas usa el servidor sandbox:
https://apisandbox.factura.bo/mcp.
Existe un addon oficial para Odoo 19: SimplifyIT: Facturación Electrónica Bolivia (SIAT) — emisión desde tus facturas de cliente, validación de NIT desde el contacto, anulación, notas de crédito y sincronización diaria del CUFD. Compatible con Odoo Community y Enterprise.
¿Dudas o necesitas tu API Key? Escríbenos a gm@simplifyit.com.bo.
factura.bo — Facturación electrónica para Bolivia (SIAT) · SimplifyIT S.R.L. · gm@simplifyit.com.bo · factura.bo