Documentación técnica

API REST de SD Invoice

Referencia pública para autenticar una integración, emitir comprobantes FE 4.4 con seguridad y manejar respuestas, límites y errores sin duplicar documentos.

Base URL

Empezar una integración

Todos los endpoints usan HTTPS y JSON, salvo las descargas de XML, PDF o ticket. Creá una llave exclusiva para cada integración y guardala únicamente en el servidor o gestor de secretos.

https://sdinvoice.com/api/v1
Authorization: Bearer cf_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Los ejemplos usan datos e identificadores ficticios. No copies una llave real en tickets, repositorios, aplicaciones móviles ni código del navegador.

Autenticación y menor privilegio

Una llave, permisos explícitos

Las llaves se crean en Configuración → API y se muestran completas una sola vez. Pueden tener vencimiento, editar sus permisos sin rotarse y revocarse de inmediato. Escribir no incluye leer: seleccioná ambos alcances cuando el flujo necesite crear y luego consultar.

PermisoQué habilita
invoices:readListar comprobantes y consultar estado, XML, PDF, ticket o respuesta de Hacienda.
invoices:writeEmitir facturas, tiquetes, notas y otros comprobantes admitidos.
catalog:readListar clientes y productos; buscar códigos CABYS.
catalog:writeCrear o actualizar clientes por identificación.
collections:read / writeOperar endpoints del módulo de Cobranza cuando la licencia está activa.
accounting:read / writeLeer libros y estados financieros, y registrar asientos manuales, con el add-on Contabilidad activo.
vet:read / write / adminOperar expedientes y flujos veterinarios según el alcance y la licencia.

Referencia del núcleo

Endpoints disponibles

Las listas por cursor devuelven { data, count, hasNext, nextCursor }. Enviá nextCursor como cursor hasta que sea nulo. El parámetro limit controla el tamaño y q filtra cuando el recurso lo admite.

Los cuerpos de escritura son estrictos: campos desconocidos o mal escritos devuelven 422, también dentro de filas anidadas. /vet/catalogs no incluye propietarios, productos ni lotes; clientes y productos usan sus catálogos paginados y los lotes viven en /vet/lots.

En consultas contables, desde y hasta son opcionales pero, cuando se envían, exigen una fecha civil real en formato YYYY-MM-DD. Fechas sin ceros o timestamps ISO devuelven 422 invalid_request.

MétodoRutaUsoPermiso
GET/api/v1/invoicesLista comprobantes por cursor; acepta status, limit y cursor.invoices:read
POST/api/v1/invoicesValida y emite un comprobante FE 4.4.invoices:write
GET/api/v1/invoices/:idConsulta estado y totales; poll=true solicita actualización a Hacienda.invoices:read
GET/api/v1/invoices/:id/xmlDescarga el XML firmado.invoices:read
GET/api/v1/invoices/:id/pdfGenera o descarga la representación PDF.invoices:read
GET/api/v1/invoices/:id/ticketDescarga la representación de tiquete.invoices:read
GET/api/v1/invoices/:id/responseDescarga la respuesta XML de Hacienda.invoices:read
GET/api/v1/clientsBusca clientes con q, limit y cursor.catalog:read
POST/api/v1/clientsCrea o actualiza un cliente por identificación.catalog:write
GET/api/v1/productsBusca productos con q, limit y cursor.catalog:read
GET/api/v1/cabysBusca CABYS por código o descripción; máximo 50.catalog:read
GET/api/v1/accounting/accountsCatálogo de cuentas contables.accounting:read
GET/api/v1/accounting/periodsPeriodos contables y su estado; un mes sin fila está abierto.accounting:read
GET/api/v1/accounting/entriesLista asientos por rango y estado; pageSize máximo 200.accounting:read
GET/api/v1/accounting/entries/:idCabecera y líneas de un asiento.accounting:read
GET/api/v1/accounting/ledger/:accountIdLibro mayor de una cuenta con saldo corrido; pageSize máximo 500.accounting:read
GET/api/v1/accounting/statements/trial-balanceBalanza de comprobación del rango.accounting:read
GET/api/v1/accounting/statements/incomeEstado de resultados del rango.accounting:read
GET/api/v1/accounting/statements/balance-sheetBalance de situación acumulado a una fecha.accounting:read
POST/api/v1/accounting/entriesCrea un asiento en borrador; requiere Idempotency-Key.accounting:write
PATCH/api/v1/accounting/entries/:idReemplaza un borrador completo; requiere Idempotency-Key.accounting:write
POST/api/v1/accounting/entries/:id/postPostea el borrador y devuelve su número.accounting:write
POST/api/v1/accounting/entries/:id/voidAnula el asiento; los automáticos se rechazan.accounting:write
GET/api/v1/collections/contractsContratos activos disponibles para crear carteras.collections:read
GET/api/v1/collections/portfoliosLista carteras por página.collections:read
GET/api/v1/collections/portfolios/:idDetalle, contrato y totales de una cartera.collections:read
POST/api/v1/collections/portfoliosCrea una cartera sobre un contrato activo.collections:write
GET/api/v1/collections/casesDescubre casos; filtra por portfolioId, stage o q.collections:read
GET/api/v1/collections/cases/:idExpediente con obligaciones y saldos.collections:read
GET/api/v1/collections/paymentsLista pagos de un caseId.collections:read
POST/api/v1/collections/paymentsRegistra un pago idempotente.collections:write
POST/api/v1/collections/obligationsCarga hasta 100 filas en línea; cargas mayores devuelven un trabajo 202.collections:write
GET/api/v1/collections/imports/:idEstado, avance y resultado de una carga 202.collections:read
GET/api/v1/vet/catalogsIDs de sucursales, especies, profesionales y catálogos clínicos.vet:read
GET/api/v1/vet/lotsLista lotes por cursor; acepta productId, q, limit y cursor.vet:read
GET/api/v1/vet/lots/:idDetalle de un lote; recursos de otra empresa responden 404.vet:read
GET/api/v1/vet/patientsBusca pacientes con q, limit y cursor.vet:read
POST/api/v1/vet/patientsCrea un paciente; requiere Idempotency-Key.vet:write
GET/api/v1/vet/patients/:idExpediente clínico completo del paciente.vet:read
GET/api/v1/vet/consultations/:idConsulta clínica indicada por el enlace self.vet:read
POST/api/v1/vet/appointments | consultations | prescriptionsCrea operaciones clínicas idempotentes.vet:write
POST/api/v1/vet/vaccinations | lab-orders | hospitalizationsRegistra operaciones clínicas idempotentes.vet:write

En Cobranza, una carga de más de 100 obligaciones responde 202 con links.self. Consultá ese enlace hasta obtener status: completed o failed; processed, total y result permiten seguir el avance sin mantener una conexión HTTP abierta. El payload personal se elimina al terminar o agotar reintentos; además, cualquier job vence tras 30 días sin actividad aunque nunca haya alcanzado un estado terminal.

POST /api/v1/invoices

Emitir un comprobante

Una factura requiere tipo de documento, receptor —inline o por clientId—, medios de pago y al menos una línea. Cada línea lleva CABYS de 13 dígitos, descripción, unidad, cantidad, precio y tarifa de IVA. Notas de crédito o débito requieren la referencia al documento ajustado.

Payload JSON

{
  "tipoDoc": "01",
  "receptor": {
    "idType": "02",
    "idNumber": "3101123456",
    "legalName": "Cliente Ejemplo S.A.",
    "email": "facturas@cliente.example"
  },
  "condicionVenta": "01",
  "medioPago": ["01"],
  "moneda": "CRC",
  "tipoCambio": 1,
  "lines": [
    {
      "cabysCode": "8311100000000",
      "description": "Servicio profesional",
      "unit": "Sp",
      "quantity": 1,
      "unitPrice": 25000,
      "ivaRate": 13
    }
  ],
  "notes": "Orden de compra 1842"
}

Respuesta 201

{
  "id": "6aaebdd3-6d65-4d34-a9ad-85a03db71c95",
  "clave": "50610082600310112345600100001010000000001199999999",
  "consecutivo": "00100001010000000001",
  "status": "processing",
  "links": {
    "self": "/api/v1/invoices/6aaebdd3-...",
    "xml": "/api/v1/invoices/6aaebdd3-.../xml",
    "pdf": "/api/v1/invoices/6aaebdd3-.../pdf"
  }
}
Ensayo sin emisión: enviá saveDraftOnly: true para validar el esquema, receptor y cálculos y guardar un borrador sin reservar consecutivo, firmar ni enviar a Hacienda. El ensayo no sustituye la verificación final de licencia ni existencia del CABYS.

Reintentos seguros

Idempotency-Key evita duplicados

Generá una clave estable desde el identificador de la operación en tu sistema y enviala en cada intento. El mismo cuerpo con la misma clave recupera la respuesta original. Un cuerpo distinto con una clave ya usada devuelve 409. Fuera de la emisión fiscal, operación y respuesta idempotente se confirman en un único commit.

Idempotency-Key: orden-1842
  • • Conservá la misma clave ante timeouts, errores de red, 429 o 5xx.
  • • Si la operación original sigue en vuelo, recibís 409 inmediatamente; aplicá backoff antes de reintentar.
  • • No reintentes 403 o 422 sin corregir permisos o datos.
  • • No reutilices una clave para una operación comercial diferente.

Control de tráfico

Límites y retroceso

300/min

Lecturas por API key

60/min

Escrituras por API key

600/min

Protección general por IP

Son las cuotas estándar y pueden ajustarse por configuración operativa. Las respuestas incluyen encabezados de límite y remanente. Cuando recibás 429, esperá los segundos indicados en Retry-After y aplicá retroceso exponencial con jitter.

Diagnóstico

Formato uniforme de errores

{ "error": { "code": "validation_error", "message": "lines: Mínimo una línea" } }
HTTPCódigoQué significa
400invalid_json / invalid_requestJSON inválido, parámetro ausente o UUID mal formado.
401unauthorizedLlave ausente, inválida, revocada o vencida.
403forbidden / tenant_suspendedFalta un permiso o la empresa está suspendida.
404not_found / xml_unavailableEl recurso o artefacto no existe o todavía no está disponible.
409idempotency_in_progressLa solicitud original con esa clave sigue procesándose.
409idempotency_key_reuseLa misma clave se reutilizó con un payload distinto.
400empresa_not_supportedUna API key opera solo sobre la empresa que la emitió.
409entry_not_draft / entry_not_manualEl asiento ya no es editable o lo gobierna el motor de posteo.
422unbalanced_entry / unknown_account / unknown_cost_centerEl asiento no cuadra o usa una dimensión ajena al catálogo de la empresa.
422validation_error / invalid_requestEl payload incumple el esquema o una regla de negocio.
429rate_limitedCuota excedida; respetá Retry-After.
500internal_errorFallo interno reintentable con retroceso e idempotencia.

¿Necesitás validar un caso antes de integrar?

Compartinos el flujo, volumen esperado y tipos de comprobante. Nunca envíes una API key real por correo.