01
Qué podés hacer
La API trabaja sobre los movimientos de caja de tu empresa: los comprobantes de gastos e ingresos que hoy cargás desde el panel o por WhatsApp. Todo lo que cargues por API aparece en el panel con el origen “integración externa” y el nombre de tu credencial.
Escribir
Registrar y corregir
Creás egresos e ingresos, los modificás y los eliminás. Solo los que cargó la integración: lo que cargó una persona no se toca por API.
Leer
Consultar
Traés un movimiento o listás los de tu empresa con filtros. También leés tus proyectos, proveedores, categorías y medios de pago.
IA
Extraer de un texto o una imagen
Mandás un texto, una foto o un PDF y Sorby arma el movimiento. Queda en borrador para que una persona lo revise y lo confirme.
Dirección baseTodos los ejemplos usan https://api.sorbydata.com/api/v1. Los datos van en JSON (UTF-8), las fechas en formato ISO 8601 y los montos como número, no como texto.
02
Tu API key
La API key es la llave de tu empresa: identifica quién llama y qué puede hacer. Es una por integración (por ejemplo, una para tu ERP y otra para un proceso nocturno), así podés revocar una sin cortar las demás.
Cómo crearla
La creás vos, desde el panel de Sorby, en Administración → Integraciones. Solo la ven quienes tienen el permiso Gestionar integraciones.
- Tocá Crear API key y ponele un nombre que diga para qué es (por ejemplo, “ERP contable”).
- Elegí los permisos (ver tabla). Te recomendamos empezar por los mínimos, por ejemplo solo lectura, y ampliar cuando haga falta.
- Elegí el vencimiento (por defecto, 90 días). Pasada esa fecha la key deja de funcionar y tenés que crear otra.
- Copiala en el momento. Se muestra una sola vez: no la podemos volver a mostrar. Guardala en un gestor de secretos. Si la perdés, revocala y creá otra.
En la misma pantalla ves el último uso de cada key, cuándo vence y podés revocarla al instante. Una key vencida o revocada deja de funcionar de inmediato.
¿No ves la pestaña Integraciones?Todavía no está habilitada para tu empresa o tu usuario. Pedinos que la activemos: antes confirmamos que quien lo pide administra la empresa.
| Permiso | Qué habilita |
|---|---|
catalogos:leer | Leer proyectos, proveedores, categorías, medios de pago y la configuración de tu empresa. |
movimientos:leer | Consultar y listar movimientos. |
movimientos:escribir | Registrar, modificar y eliminar movimientos. |
extraccion:usar | Cargar desde un texto o una imagen (además de movimientos:escribir). |
Cuidala como una contraseñaQuien tenga la key puede operar con los permisos que le diste, sobre los datos de tu empresa. No la pongas en una app móvil, en el navegador, en un chat ni en un repositorio: usala solo desde tu servidor. Una key por integración, con los permisos mínimos y con vencimiento. Si sospechás que se filtró, revocala en el momento. Si dejás de usar una integración, revocala también.
La key tiene la forma sk_<8 caracteres>_<48 caracteres>.
03
Autenticarte
En cada pedido mandás la key en el encabezado Authorization. Para comprobar que anda, pedí /me:
curl https://api.sorbydata.com/api/v1/me \
-H "Authorization: Bearer sk_xxxxxxxx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
{ "credencial_id": "…", "empresa_id": "…", "nombre": "ERP contable",
"scopes": ["catalogos:leer", "movimientos:leer", "movimientos:escribir"] }
Tu empresa sale siempre de la key: nunca la mandás vos. Si la key falta, es inválida, fue revocada, está vencida, la respuesta es siempre el mismo 401, sin pistas de cuál de los casos fue.
04
Leer tus catálogos
Antes de registrar un movimiento necesitás los identificadores de tu empresa: el proyecto, el proveedor, la categoría. Todos son GET y piden el permiso catalogos:leer.
| Ruta | Qué devuelve |
|---|---|
GET/proyectos | { proyectos: [{ id, nombre }] }, solo los activos. |
GET/proveedores | { proveedores: [{ id, nombre, razon_social, cuit, alias }] }. Filtros: ?buscar=texto y ?cuit=30711111119. Sirve para vincular tu proveedor con el nuestro. |
GET/categorias | { categorias: [{ nombre, subcategorias: [] }] }, con los nombres exactos que acepta el alta. |
GET/medios-pago | { medios_pago: [...], default } |
GET/configuracion-movimientos | Los obligatorios de tu empresa, los tipos_factura aceptados, los estados (si tu empresa los usa), los tags_extra y las monedas. |
Empezá por la configuración/configuracion-movimientos te dice qué campos son obligatorios en tu empresa. Si no lo mirás, te enterás recién cuando un alta falla con 422.
05
Registrar un movimiento
POST/movimientos · permiso movimientos:escribir
curl -X POST https://api.sorbydata.com/api/v1/movimientos \
-H "Authorization: Bearer $KEY" \
-H "Idempotency-Key: factura-0001-00012345" \
-H "Content-Type: application/json" \
-d '{
"type": "egreso",
"total": 125000,
"moneda": "ARS",
"fecha_factura": "2026-10-15",
"proyecto_id": "6650f0c2a1b2c3d4e5f60718",
"proveedor_id": "6650f0c2a1b2c3d4e5f60999",
"categoria": "Materiales",
"medio_pago": "Transferencia",
"numero_factura": "0001-00012345"
}'
Campos
| Campo | Detalle |
|---|---|
type * | "egreso" o "ingreso". |
total * | Número. Si tu empresa tiene IVA, es el total con IVA. |
moneda | "ARS" (por defecto) o "USD". |
fecha_factura | Fecha del comprobante. Si no la mandás, usamos la de hoy. |
proyecto_id | Id de /proyectos. |
proveedor_id | Id de /proveedores. Solo por id: no se acepta un nombre libre, así no se crean proveedores por error. |
categoria, subcategoria | Nombres exactos de /categorias. |
medio_pago, tipo_factura, estado | Valores de /medios-pago y /configuracion-movimientos. |
numero_factura, subtotal, observacion, fecha_vencimiento, tags_extra | Opcionales. |
borrador | true para guardarlo como borrador sin exigir los obligatorios. Por defecto false. |
(*) type y total siempre. Los demás obligatorios dependen de tu empresa. Un campo que no está en la lista da 400.
La respuesta es 201 con el movimiento:
{ "id": "…", "codigo_operacion": "…", "type": "egreso", "moneda": "ARS", "total": 125000,
"fecha_factura": "2026-10-15T00:00:00.000Z", "proyecto_id": "…", "proyecto_nombre": "Torre Norte",
"proveedor_id": "…", "proveedor_nombre": "Corralón Sur", "categoria": "Materiales",
"medio_pago": "Transferencia", "estado": null, "es_borrador": false,
"origen": "integracion_externa", "creado_en": "2026-10-15T14:02:11.000Z", … }
La Idempotency-Key: obligatoria
Si tu pedido se corta por un timeout y lo repetís, no queremos duplicar el comprobante. Por eso cada alta lleva un encabezado Idempotency-Key (hasta 200 caracteres) que vos elegís y es único por comprobante; lo más simple es usar el id o el número del comprobante en tu sistema.
- Repetís el mismo pedido con la misma key: devolvemos el movimiento original con
200y"repetido": true. No se crea otro. - Usás la misma key con otro contenido: seguimos devolviendo el original. Cambió el comprobante, cambiá la key.
- Si la key corresponde a un movimiento que ya eliminaste, responde
409: usá una nueva.
Lo que no se inventaUn proyecto, un proveedor o una categoría que no existen en tu empresa dan 422. No creamos nada por vos: primero se da de alta en Sorby.
06
Cargar desde un texto o una imagen
POST/movimientos/extraer · permisos movimientos:escribir y extraccion:usar
Si tu sistema solo tiene el comprobante escaneado o una nota, mandalo y Sorby interpreta los datos con IA, usando los proyectos, proveedores y categorías de tu empresa. El resultado queda como borrador: una persona lo revisa y lo confirma en el panel. La API no confirma borradores.
Desde un texto
curl -X POST https://api.sorbydata.com/api/v1/movimientos/extraer \
-H "Authorization: Bearer $KEY" \
-H "Idempotency-Key: nota-889" \
-H "Content-Type: application/json" \
-d '{ "texto": "Pagué $5000 a Corralón Sur en efectivo por cemento", "proyecto_id": "6650f0c2a1b2c3d4e5f60718" }'
Desde una imagen o un PDF
# subiendo el archivo
curl -X POST https://api.sorbydata.com/api/v1/movimientos/extraer \
-H "Authorization: Bearer $KEY" -H "Idempotency-Key: scan-889" \
-F "archivo=@factura.pdf"
# o indicando una dirección pública
curl -X POST … -H "Content-Type: application/json" \
-d '{ "archivo_url": "https://tu-sistema.com/facturas/889.pdf" }'
El archivo puede pesar hasta 20 MB. archivo_url debe ser una dirección https pública; no aceptamos direcciones internas o privadas.
Opciones y respuesta
proyecto_id(opcional): fuerza el proyecto en vez de que la IA lo deduzca.modo_guardado:"borrador"(por defecto, lo guarda) o"no_guardar"(solo te devuelve lo extraído, sin id).
{ "movimiento": { "id": "…", "es_borrador": true, "total": 5000, "proveedor_nombre": null, … },
"advertencias": [ { "campo": "proveedor", "codigo": "proveedor_no_resuelto", "valor_extraido": "Corralón Sur" } ] }
Las advertencias no son erroresLo que la IA no pudo vincular con tu empresa (un proveedor que no existe, una categoría que no coincide) no frena la carga: queda sin completar en el borrador y te lo avisamos en advertencias. Quien lo confirme en el panel lo completa.
Mandá también la Idempotency-Key: así un reintento no te cobra la IA dos veces. Esta ruta tiene su propio límite, más bajo (ver más abajo).
07
Consultar y listar
Los dos piden el permiso movimientos:leer.
GET/movimientos/:id devuelve el movimiento (404 si no existe o no es de tu empresa).
GET/movimientos lista los movimientos de tu empresa, todos, no solo los que cargó la integración. Filtros:
| Parámetro | Qué hace |
|---|---|
proyecto_id, proveedor_id | Acota por proyecto o proveedor. |
desde, hasta | Rango sobre fecha_factura. |
type | egreso o ingreso. |
origen | Por ejemplo integracion_externa para ver solo lo que cargó una integración. |
incluir_borradores | true para incluirlos (por defecto no aparecen). |
pagina, limite | Paginado; limite hasta 100. |
curl "https://api.sorbydata.com/api/v1/movimientos?desde=2026-10-01&hasta=2026-10-31&limite=50" \
-H "Authorization: Bearer $KEY"
{ "datos": [ … ], "pagina": 1, "limite": 50, "total": 132 }
08
Modificar y eliminar
PUT/movimientos/:id modifica solo los campos que mandes (los mismos del alta, salvo type). DELETE/movimientos/:id lo elimina y responde 204. Los dos piden movimientos:escribir.
- Solo se pueden modificar o eliminar los movimientos cargados por una integración. Si fue cargado por una persona, la respuesta es
403. - Un movimiento con pagos asociados o un ingreso ya facturado no se modifica ni se elimina por API (
409): se resuelve desde el panel. - Los borradores se pueden completar con
PUT; confirmarlos se hace en el panel.
09
Errores y límites
Todos los errores tienen la misma forma, así tu sistema los puede manejar en un solo lugar:
{ "error": { "code": "proyecto_no_encontrado",
"message": "El proyecto no existe en tu empresa",
"campo": "proyecto_id", "detalle": null } }
| Código | Cuándo |
|---|---|
400 | JSON inválido, campo desconocido o de tipo incorrecto. |
401 | Key ausente, inválida, revocada o vencida. |
403 | La key no tiene el permiso, o el movimiento no se puede modificar por API. |
404 | No existe, o es de otra empresa. |
409 | Movimiento con pagos o facturado; Idempotency-Key ya usada. |
422 | Proyecto, proveedor o categoría inexistentes; faltan campos obligatorios (en detalle.faltantes viene la lista). |
429 | Demasiados pedidos. El encabezado Retry-After indica cuántos segundos esperar. |
Límites
- Hasta 120 pedidos por minuto por key, y 20 por minuto en la extracción con IA.
- Ante un
429o un error5xx, reintentá esperando cada vez más (por ejemplo 1 s, 2 s, 4 s). Con laIdempotency-Keyreintentar es seguro.
10
Problemas frecuentes
Me da 401 aunque la key es correcta
Revisá que mandes Authorization: Bearer sk_… completo, sin comillas ni espacios, y que la key no haya sido revocada, ni esté vencida. Con /me probás solo la conexión.
Me da 403 al registrar un movimiento
A tu key le falta el permiso movimientos:escribir (y extraccion:usar para extraer). Pedinos que la ampliemos o te emitimos otra.
Me da 422 con “campos_obligatorios”
Tu empresa exige campos que no mandaste. Mirá detalle.faltantes o /configuracion-movimientos. Si todavía no los tenés, mandá "borrador": true y completalo después.
Cargué un movimiento y no lo veo en el listado
Los borradores no aparecen salvo que pidas incluir_borradores=true. Los de la extracción con IA siempre son borradores.
Quiero corregir algo que cargó una persona
Por API solo se corrige lo cargado por una integración. Esto es a propósito: la integración no pisa el trabajo del equipo. Hacelo desde el panel.
Necesito otra cosa que no está acá
Hoy la API cubre movimientos de caja y sus catálogos. Contanos qué necesitás integrar y lo sumamos.