SAP Business One
SAP Business One 10.0 o superior, integrado por Service Layer (API REST/OData en el puerto 50000). Vale igual para las dos variantes: Business One sobre Microsoft SQL Server y Business One sobre SAP HANA.
Este es EL punto que te importaba, asi que lo digo sin adornos. SI SERVICE LAYER YA ESTA CORRIENDO, ESTO SON HORAS. No dias, no semanas, no un proyecto. Un comercio que hoy entra a https://su-servidor:50000 y ve cargar la referencia de la API tiene practicamente todo el trabajo de infraestructura hecho. Lo que queda de su lado es crear un usuario, asignarle una licencia, marcarle permisos y elegir una cuenta contable. Eso es una mañana de trabajo del contador. Y para HANA la probabilidad es alta: Service Layer viene con la plataforma desde 9.x, y en la mayoria de las instalaciones de HANA ya esta andando porque el Web Client depende de el. DONDE SE ROMPE ESTA PROMESA, tres escenarios concretos: 1. Microsoft SQL Server en version 9.2 o 9.3. Ahi no hay Service Layer y no hay atajo. Hay que actualizar a 10.0, y eso es un proyecto del socio implementador de 1 a 3 SEMANAS, con pruebas de add-ons, de reportes de Crystal y de personalizaciones. Cuando alguien te diga que la integracion con SAP tardo un mes, casi siempre fue esto y no la integracion. 2. Service Layer no instalado en una 10.0. Tecnicamente son 2 a 4 horas de instalacion, pero en la practica lo que tarda es conseguir la ventana de mantenimiento y que el partner tenga agenda. Eso puede ser una semana de espera con dos horas de trabajo adentro. 3. El certificado y el firewall. Suena trivial y no lo es: el certificado autofirmado del Service Layer hace que el conector rechace la conexion, y la gente pierde medio dia culpando al codigo antes de darse cuenta. Presupuesta esa media hora del paso 6 en serio. COMPARACION PARA CALIBRAR: la gente asume que SAP es lo mas dificil de integrar y que una plataforma en la nube es facil. Para este caso concreto es al reves. Service Layer es una API OData bien documentada, con un manual oficial de 224 paginas que trae ejemplos de payload reales; encontrar el objeto correcto y el payload correcto es directo. Lo dificil de SAP no es la API: es la BUROCRACIA de alrededor — la licencia, el partner, la ventana de mantenimiento, el firewall corporativo. Si el comercio te resuelve esas cuatro cosas en un dia, tenes la integracion andando en dos. LO QUE SI ES UN DOLOR DE CABEZA, dicho sin marketing: las validaciones contables de SAP al crear el Incoming Payment. SAP no te deja postear un documento que no cuadre, y tiene razon, pero los mensajes de error son crudos y a veces la localizacion exige campos que no estan en la documentacion general (asignaciones de flujo de caja, series de numeracion, dimensiones). Ahi es donde se van las 6 horas del paso 11 y no en la parte de HTTP. Presupuesta eso y no prometas que sale en una tarde.
Quien lo hace
Sin rodeos: esto NO lo hace el dueño solo, y en la mayoria de los casos tampoco el contador solo.
EL DUEÑO: no toca nada tecnico. Su trabajo es decidir tres cosas y firmarlas: (1) que cuenta de banco del mayor se acredita cuando entra un cobro de ROKI, (2) si compra o libera una licencia de SAP para el usuario de integracion, (3) si autoriza abrir o no un puerto en el firewall de la oficina. Tambien es el unico que puede pedirle al socio implementador que haga trabajo facturable.
EL CONTADOR (si es superusuario de SAP): puede hacer solo la parte de adentro del cliente de SAP, y es bastante: crear el usuario de integracion en "Administration → Setup → General → Users", asignarle licencia en "Administration → License → License Administration", darle permisos en "Administration → System Initialization → Authorizations → General Authorizations", y confirmar la cuenta de banco en "Administration → Setup → Banking → House Bank Accounts". Ojo: la documentacion oficial de SAP es explicita en que solo un usuario definido como Superuser puede entrar al submenu de Authorizations. Si el contador no es superusuario, no puede.
EL SOCIO IMPLEMENTADOR (el partner SAP): hace falta SI O SI en estos casos:
- Si Service Layer no esta instalado. La instalacion se hace con el Components Setup Wizard (install.exe en \Packages.x64\ComponentsWizard), pide la clave del site user del SLD, pide certificado, y en instalaciones distribuidas hay que correr el wizard en cada maquina. Eso no lo hace el contador. Y si el comercio esta en SQL Server con version 9.x, el partner tiene que hacer un upgrade completo a 10.0 antes — eso ya no son horas, son dias.
- Si hay que tocar el firewall, el certificado TLS, o el DNS.
- Si el comercio esta en SAP Business One Cloud alojado por el partner: ahi el comercio no tiene acceso al servidor y TODO pasa por el partner.
- Para responder si el contrato de licencias del comercio cubre Indirect Access. Eso es tema contractual, no tecnico.
EL PROGRAMADOR: obligatorio. No hay forma de evitarlo. Service Layer es una API cruda de OData; no trae ningun conector de pagos, ninguna pantalla, ningun "boton de cobrar". Alguien tiene que escribir el conector: login, sesion, crear el pago en ROKI, recibir el webhook, verificar la firma, y postear el Incoming Payment. No es trabajo de un consultor funcional de SAP.
Resumen honesto: el mejor arreglo es contador + programador, con el partner de reserva. Si Service Layer ya esta andando, el partner casi no participa. Si no esta andando, el partner es el cuello de botella y el proyecto se te va de horas a semanas por calendario de ellos, no por trabajo real.
Que tiene que existir antes de empezar
Donde: En el cliente de escritorio de SAP: "Help → About SAP Business One". El License Guide oficial cita ese mismo menu. Ahi se lee la version y el patch level.
Service Layer para la variante Microsoft SQL Server recien se libero con SAP Business One 10.0. En 9.2 y 9.3 sobre SQL Server simplemente no existe: no hay puerto 50000, no hay nada que llamar. Si el comercio esta en 9.x sobre SQL, este proyecto no empieza hasta que el partner haga el upgrade, y eso es otro proyecto.
Donde: Prueba 1, la mas simple: abrir un navegador EN EL SERVIDOR o en una maquina de la misma red y entrar a "https://<servidor>:50000". El Administrator's Guide dice textual que ahi se accede al documento de ayuda de la API: "you can access the API help document for the Service Layer in a Web browser from anywhere via this URL: https://<Load Balancer Address>:<Load Balancer Port>". Si carga la referencia de la API, Service Layer esta vivo. Prueba 2: "https://<servidor>:50000/balancer-manager", que la guia oficial nombra como el balancer manager para ver el estado de cada miembro. Prueba 3: "https://<servidor>:50000/ServiceLayerController", el SAP Business One Service Layer Controller (existe desde 10.0 PL00 en HANA y 10.0 PL02 en Microsoft SQL). Prueba 4: en el SLD, "https://<servidor>:40000/ControlCenter", pestaña "Services", buscar un servicio de tipo Service Layer en la lista.
Es el unico prerequisito que define si esto son horas o semanas. Si las cuatro pruebas responden, el 80% del trabajo del lado del comercio ya esta hecho. El puerto 40000 del SLD es el mismo en las dos variantes (SQL y HANA), asi que esta prueba sirve para ambas.
Donde: En el servidor: ir a la carpeta de instalacion, ruta por defecto "\Packages.x64\ComponentsWizard", correr "install.exe". En el wizard: ventana "Setup Wizard" → elegir "Installation and Upgrade"; ventana "Select Features" → marcar "Service Layer"; ventana "Network Address"; ventana "Service Port" (puerto para SSO, por defecto 40001); ventana "Specify Security Certificate"; ventana "Landscape Server" (pide direccion del servidor de landscape y la clave del site user); ventana "Database Instances"; ventana "Service Layer" → marcar "Install Service Layer Load Balancer and Port" (puerto por defecto 50000), llenar "Service Layer Load Balancer Members" con "Starting Port" (por defecto 50001) y "Node Count" (por defecto 10); ventana "Review Settings" → "Install".
Prerequisito documentado: Windows PowerShell 5 o superior en la maquina. Ademas la instalacion remota NO esta soportada: si el load balancer va en el servidor A y los miembros en B y C, hay que correr el wizard en cada servidor por separado. Esto lo hace el socio implementador, con ventana de mantenimiento. Presupuesta 2 a 4 horas y reinicio de servicios.
Donde: "Administration → Setup → General → Users" (se abre la ventana "Users - Setup"). Crear un usuario nuevo con un User Code claro tipo ROKICONNECT y una contraseña larga generada al azar.
Trazabilidad y control de daño. Todo Incoming Payment que cree el conector va a quedar firmado con ese usuario, y si algo sale mal se bloquea ese usuario sin dejar sin sistema al contador. Ademas SAP licencia por usuario nombrado y prohibe explicitamente compartir un usuario entre personas: usar el usuario del contador para una integracion es exactamente lo que el License Guide dice que no se hace.
Donde: "Administration → License → License Administration", pestaña "Assignment". Ahi se ven las columnas de tipos de licencia: Professional, Limited CRM, Limited Financials, Limited Logistics, Indirect Access, mas los campos "Total Assigned" y "Total Free".
Aca hay que ser preciso porque hay mucha confusion. El License Guide oficial de SAP Business One 10.0 dice: los tipos Professional User, Limited CRM User, Limited Financials User, Limited Logistics User y Starter User "all include Indirect Access authorizations". O sea: si el usuario de integracion tiene una licencia Professional o Limited asignada, el acceso por API ya esta cubierto contractualmente. Tambien existe el tipo Indirect Access suelto para este uso exacto. Lo tecnico: para hacer login contra Service Layer solo hace falta un usuario y contraseña validos de SAP Business One, y en la practica Service Layer NO fuerza la verificacion de licencia en cada llamada. Eso no significa que sea gratis: la licencia es una obligacion de contrato, no un candado tecnico. Preguntale al socio implementador si el contrato del comercio ya trae Indirect Access o si hay que comprarlo. Si hay que comprarlo, es plata y es decision del dueño.
Donde: "Administration → System Initialization → Authorizations → General Authorizations". Del lado izquierdo se elige el usuario ROKICONNECT, y en el arbol de la derecha se le da autorizacion completa (Full Authorization) SOLO a la rama del modulo Banking que corresponde a los Incoming Payments, y lectura (Read Only) a la rama de Sales - A/R para las facturas de deudores. Todo lo demas: No Authorization.
El conector solo necesita hacer dos cosas: LEER una factura de deudores y CREAR un pago recibido. Nada mas. Con eso, aunque le roben la contraseña al conector, nadie puede crear articulos, tocar precios, ver nomina ni borrar clientes. AVISO HONESTO: la ruta del menu esta confirmada en la documentacion oficial de SAP, pero los nombres exactos de las hojas del arbol de autorizaciones (las lineas de adentro de Banking y de Sales - A/R) varian por localizacion y por version, y no los encontre escritos textualmente en los manuales que lei. Que el contador los confirme en pantalla en vez de que alguien se los invente. Recorda ademas que solo un Superuser puede entrar a este submenu.
Donde: "Administration → Setup → Banking → House Bank Accounts" (ventana "House Bank Accounts - Setup").
El Incoming Payment no se puede crear en el aire: hay que decirle a SAP contra que cuenta entra el dinero. El conector va a mandar ese codigo de cuenta en el campo TransferAccount (los ejemplos oficiales de la API usan valores como "_SYS00000000004"). Esta es una decision del CONTADOR, no del programador: normalmente se abre una cuenta puente tipo "ROKI Connect por liquidar", porque la plata todavia no cayo en el banco fisico el dia que el cliente paga. Si esto no se define bien, la conciliacion bancaria se vuelve un infierno al mes siguiente.
Donde: En la pantalla "Choose Company" del cliente de SAP, columna del nombre de base de datos. Es algo tipo SBODEMOHN o el nombre que le puso el implementador.
El login contra Service Layer pide tres cosas: CompanyDB, UserName y Password. Si el CompanyDB esta mal escrito, aunque sea una mayuscula, el login falla y el mensaje no siempre es claro. Anotalo tal cual, respetando mayusculas.
Donde: Regla de firewall interno de la oficina. Desde la maquina del conector: probar que abre "https://<servidor>:50000".
Ojo con el detalle de seguridad que trae la propia guia de SAP: el trafico entre el load balancer y los miembros va por HTTP, no HTTPS, y SAP recomienda configurar el firewall de cada maquina miembro para que SOLO acepte visitas del load balancer. O sea: el conector habla al 50000, nunca al 50001+.
Donde: Se define durante la instalacion en la ventana "Specify Security Certificate", donde el instalador permite tambien "use a self-signed certificate".
Service Layer obliga HTTPS con TLS 1.2 o 1.3. La mayoria de instalaciones quedaron con certificado autofirmado. Un cliente HTTP normal va a rechazar esa conexion. Hay que exportar ese certificado e instalarlo en el almacen de confianza de la maquina del conector. Desactivar la verificacion de certificado es la salida facil y es una mala idea: te expone a que cualquiera en la red interna se haga pasar por el servidor de SAP.
Donde: Regla de firewall de salida.
El conector tiene que poder hacer POST a https://aura.roki.systems/api/connect/v1/payments y GET a /payments/{id}. Muchas redes de oficina bloquean salida arbitraria desde servidores. Es una linea de firewall, pero si no se pide antes, se descubre el dia de la prueba y se pierde la tarde.
Los pasos
- 1. Averiguar en que estas parado (15 minutos, lo hace el contador)
Abri el cliente de SAP y anda a "Help → About SAP Business One". Anota la version y el patch level. Despues abri un navegador en una maquina de la red de la oficina y entra a "https://<direccion-del-servidor>:50000". Si carga una pagina con la referencia de la API de Service Layer: felicidades, ya tenes lo dificil. Segui al paso 2. Si no carga nada y la version es 10.0 o superior: Service Layer no esta instalado. Anda al paso 1-bis. Si la version dice 9.2 o 9.3 y la base es Microsoft SQL Server: pará todo. No hay Service Layer posible. Hay que actualizar a 10.0 primero y eso es un proyecto aparte con el socio implementador. Esta guia no aplica hasta que eso termine. Si la version dice 9.3 y la base es SAP HANA: probablemente si tenes Service Layer, seguí probando. Segunda comprobacion, la del SLD: entra a "https://<direccion-del-servidor>:40000/ControlCenter", pestaña "Services". Si en esa lista aparece un servicio de tipo Service Layer, esta registrado correctamente. El puerto 40000 es el mismo en SQL Server y en HANA. - 1-bis. Instalar Service Layer, solo si no esta (2 a 4 horas, lo hace el socio implementador)
Esto NO lo hace el dueño ni el contador. Requiere acceso de administrador al servidor, la clave del site user del SLD, y una ventana de mantenimiento porque se reinician servicios. El partner corre "install.exe" desde "\Packages.x64\ComponentsWizard". Prerequisito documentado: Windows PowerShell 5 o superior instalado en esa maquina. La secuencia de ventanas es: "Setup Wizard" → elegir "Installation and Upgrade". "Select Features" → marcar "Service Layer". "Network Address" → elegir IP o hostname (viene prellenado con el FQDN). "Service Port" → puerto para SSO, por defecto 40001. "Specify Security Certificate" → certificado propio o autofirmado. "Landscape Server" → direccion y clave del site user. "Database Instances" → elegir la instancia si hay varias. "Service Layer" → marcar "Install Service Layer Load Balancer and Port" con puerto 50000, y llenar "Service Layer Load Balancer Members" con "Starting Port" 50001 y "Node Count" (por defecto 10; para un comercio chico con 3 o 5 alcanza y sobra). "Review Settings" → "Install". Detalle que se olvida: la instalacion remota no esta soportada. Si el load balancer va en un servidor y los miembros en otros, hay que correr el wizard maquina por maquina. Al terminar, verificar en "https://<servidor>:50000/balancer-manager" que los miembros aparecen con estado Ok. - 2. Crear el usuario de integracion (10 minutos, lo hace el contador si es superusuario)
En el cliente de SAP: "Administration → Setup → General → Users". Se abre la ventana "Users - Setup". Crea un usuario nuevo. Sugerencia de User Code: ROKICONNECT. Contraseña: generada al azar, larga, guardada en un gestor de contraseñas, nunca en un correo ni en un WhatsApp. NO marques la casilla de Superuser. NO reutilices "manager". NO uses el usuario "Support" (ese esta reservado para soporte del partner, viene bloqueado por defecto y solo funciona si el remote support platform subio un reporte en los ultimos 7 dias). Anota tambien el nombre exacto de la base de datos de la compañia, que lo vas a ver en la pantalla "Choose Company". Ese es el CompanyDB del login. - 3. Asignarle licencia (10 minutos, lo hace el contador; la decision de comprar es del dueño)
"Administration → License → License Administration", pestaña "Assignment". Busca el usuario ROKICONNECT y asignale una licencia. Mira las columnas "Total Assigned" y "Total Free" para saber si hay un asiento libre. Que licencia: si el comercio tiene un asiento Professional o Limited libre, con eso alcanza — el License Guide de SAP dice que esos tipos ya incluyen las autorizaciones de Indirect Access. Si no hay asiento libre, hay que comprar uno, y ahi decide el dueño. Lo tecnico contra lo contractual, dicho claro: tecnicamente Service Layer te va a dejar hacer login con un usuario valido aunque el tema de licencia este flojo, porque no fuerza la verificacion en cada llamada. Contractualmente SAP exige la autorizacion de Indirect Access. No juegues a que "funciona igual": preguntale al socio implementador si el contrato ya lo cubre. Una auditoria de SAP no es un buen dia. - 4. Darle permisos minimos (15 minutos, lo hace el contador si es superusuario)
"Administration → System Initialization → Authorizations → General Authorizations". En la lista de la izquierda selecciona ROKICONNECT. En el arbol de la derecha: - Rama del modulo Banking, la parte de Incoming Payments: Full Authorization. - Rama del modulo Sales - A/R, la parte de A/R Invoice: Read Only (el conector solo necesita leer la factura, jamas modificarla). - Todo el resto del arbol: No Authorization. Aviso honesto: la ruta del menu esta confirmada palabra por palabra en la documentacion oficial de SAP, pero los nombres exactos de cada hoja del arbol cambian segun localizacion y version, y no los encontre escritos textualmente en los manuales que lei. Confirmalos en pantalla, no los inventes. Recorda que solo un usuario definido como Superuser puede entrar a este submenu. - 5. Definir la cuenta contable del cobro (20 minutos, lo decide el contador)
"Administration → Setup → Banking → House Bank Accounts" (ventana "House Bank Accounts - Setup"). Decidi contra que cuenta entra la plata de ROKI. Anota el codigo de cuenta de mayor que devuelve esa pantalla; el conector lo va a usar en el campo TransferAccount. Recomendacion contable, no tecnica: usa una cuenta puente tipo "ROKI Connect por liquidar" en vez de la cuenta del banco real. El cliente paga hoy, pero la plata cae en la cuenta bancaria dias despues. Si asentas directo contra el banco, la conciliacion bancaria del mes no va a cuadrar nunca y le vas a echar la culpa al sistema. - 6. Exportar el certificado y abrir las reglas de red (30 minutos, socio implementador o quien administre la red)
Exporta el certificado TLS del Service Layer e instalalo en el almacen de confianza de la maquina donde va a correr el conector. Si es autofirmado (lo mas comun), sin esto ninguna libreria HTTP seria va a conectarse. Reglas de firewall que hay que pedir: - Desde la maquina del conector hacia el servidor de SAP: TCP 50000 (solo el load balancer, nunca los 50001+; la propia guia de SAP recomienda que los miembros solo acepten trafico del load balancer). - Desde la maquina del conector hacia internet: HTTPS a aura.roki.systems. NO abras el 50000 a internet. El Administrator's Guide de SAP lo dice literal, y en las dos variantes: "The Service Layer is for internal component calls only and you do not need to expose it to the Internet." - 7. Probar el login a mano antes de escribir una linea de codigo (10 minutos, lo hace el programador)
Con Postman o curl, desde la maquina del conector: POST https://<servidor>:50000/b1s/v1/Login {"CompanyDB": "SBODEMOHN", "UserName": "ROKICONNECT", "Password": "..."} Respuesta esperada, 200 OK, con dos cookies en la cabecera y un cuerpo asi: Set-Cookie: B1SESSION=PTRzIjYK-weN6-1Lx1-ZG0J-3ARxfjcU0Shy;HttpOnly; Set-Cookie: ROUTEID=.node1; path=/b1s { "SessionId": "...", "Version": "1000110", "SessionTimeout": 30 } Si eso responde, TODO lo demas es programacion normal. Si no responde, el problema esta en los pasos 1 a 6 y no tiene sentido avanzar. Dos versiones de la API conviven: /b1s/v1 es OData v3 y /b1s/v2 es OData v4. Usa v2 en proyectos nuevos: desde SAP Business One FP 2405 OData v3 esta deprecado. El endpoint de Login funciona en ambas. - 8. Programar el manejo de sesion (1 hora, lo hace el programador)
La sesion se abre con Login y se cierra con Logout. El campo "SessionTimeout": 30 significa 30 minutos de inactividad. Reglas que el conector tiene que respetar: - Mandar la cookie B1SESSION en TODAS las peticiones. Es obligatoria. La documentacion es explicita: si tu aplicacion no corre dentro de un navegador, vos tenes que poner la cookie a mano en cada request. - Mandar tambien ROUTEID. Es opcional pero mantiene la pegajosidad de sesion contra el mismo nodo del load balancer, y sin ella vas a ver errores raros e intermitentes cuando hay varios nodos. - Si la sesion venció, Service Layer devuelve 401 Unauthorized con este cuerpo exacto: { "error": { "code": 301, "message": { "lang": "en-us", "value": "Invalid session or session already timeout." } } }. Al ver eso, hacer Login de nuevo y reintentar la operacion UNA vez. - No abras una sesion por cada cobro. Manten una sesion viva y renovala. - Haz Logout cuando el conector se apaga. Sesiones colgadas consumen recursos del servidor. Si hace falta subir el timeout, se cambia con el parametro SessionTimeout en el archivo de configuracion conf/b1s.conf, o desde la interfaz del Service Layer Controller en "https://<servidor>:<puerto>/ServiceLayerController", pestaña Service Layer Settings. Nota para servidores Windows: antes de usar el Controller hay que verificar con Get-ExecutionPolicy que la politica de ejecucion de PowerShell este en "Unrestricted", y si no, ponerla con Set-ExecutionPolicy Unrestricted. - 9. Crear el cobro en ROKI y mandarle el link al cliente (2 a 3 horas, lo hace el programador)
Cuando el comercio emite una factura de deudores en SAP y quiere cobrarla, el conector hace: POST https://aura.roki.systems/api/connect/v1/payments Authorization: Bearer sk_test_... (sk_live_... en produccion) { "amount": 1500.00, "external_reference": "FAC-001", "name": "Factura 001" } El monto va en lempiras con decimales. 1500.00, no 150000. ROKI responde 201 con { id, checkout_url, transaction_id: null }. En external_reference mandale algo que puedas volver a encontrar en SAP. Aca esta la trampa mas importante de toda esta integracion: SAP tiene DOS numeros de documento y no son el mismo. - DocEntry: la clave interna del documento. Es lo que la API llama por la URL: GET /b1s/v2/Invoices(123). La documentacion oficial lo dice: "DocEntry is the key property". - DocNum: el numero que ve el humano en la factura impresa. Es perfectamente normal que la factura numero 1 tenga DocEntry 22 y DocNum 11. La documentacion oficial de SAP trae ese ejemplo tal cual. Recomendacion: manda en external_reference el DocNum (que es lo que el cliente reconoce en su factura) pero GUARDA aparte el DocEntry, porque es el DocEntry el que vas a necesitar para aplicar el pago. Si mandas DocNum y despues intentas aplicar el pago usando ese numero como si fuera DocEntry, vas a acreditar plata contra la factura equivocada. Silenciosamente. Sin error. El checkout_url se lo mandas al cliente por correo o WhatsApp, o lo pones en el PDF de la factura como un QR. - 10. Recibir el webhook de ROKI (3 a 5 horas, lo hace el programador; ver la seccion de webhook para el problema del firewall)
ROKI manda un POST a una URL publica HTTPS con la cabecera: ROKI-Signature: t=<unix>,v1=<hmac_sha256_hex> La firma es HMAC SHA-256 sobre timestamp + "." + el cuerpo CRUDO. Crudo significa los bytes tal cual llegaron, antes de parsear el JSON. Si tu framework te da el cuerpo ya deserializado y lo volves a serializar, la firma no va a coincidir nunca y vas a perder medio dia buscando el error en el lugar equivocado. Que tiene que hacer el receptor, en orden: 1. Leer el cuerpo crudo. 2. Recalcular el HMAC y compararlo en tiempo constante. 3. Verificar que el timestamp no sea viejo (rechaza cualquier cosa de mas de 5 minutos, para cortar reenvios). 4. Recien ahi parsear el JSON. 5. Si el evento es payment.approved, encolar el registro en SAP. 6. Responder 200 rapido. No hagas el trabajo pesado dentro del handler del webhook. Idempotencia, obligatoria: guarda el transaction_id de ROKI en tu base local antes de tocar SAP. Si el mismo webhook llega dos veces (y va a llegar), la segunda vez no debe crear un segundo Incoming Payment. Duplicar cobros en la contabilidad de un cliente es de los errores mas caros que podes cometer. - 11. Registrar el cobro en SAP: el Incoming Payment contra la factura de deudores (4 a 6 horas, lo hace el programador)
Este es el corazon de la integracion. El objeto de negocio exacto del Service Layer es IncomingPayments. La referencia oficial de la API lo describe asi: "This entity enables you to manipulate 'IncomingPayments'. It represents incoming payments from customers or, for returned goods, from vendors." El payload es del tipo 'Payment'. La factura de deudores es la entidad Invoices, payload tipo 'Document'. Por debajo, IncomingPayments se guarda en la tabla ORCT (VendorPayments, que es el equivalente de pagos a proveedores, va en OVPM — no los confundas). La llamada: POST https://<servidor>:50000/b1s/v2/IncomingPayments Cookie: B1SESSION=...; ROUTEID=.node1 { "CardCode": "C001", "DocDate": "2026-08-16", "DocCurrency": "HNL", "TransferAccount": "_SYS00000000004", "TransferDate": "2026-08-16", "TransferSum": 1500.00, "Remarks": "ROKI Connect - pago <id> - trx <transaction_id>", "PaymentInvoices": [ { "DocEntry": 4711, "InvoiceType": "it_Invoice", "SumApplied": 1500.00 } ] } Que es cada cosa: - CardCode: el codigo del cliente (socio de negocios) en SAP. - TransferAccount / TransferDate / TransferSum: el medio de pago. Los ejemplos oficiales de la API usan exactamente estos tres nombres para una transferencia bancaria, con la cuenta en formato "_SYS00000000004". Para efectivo los campos serian CashAccount y CashSum. - PaymentInvoices: la coleccion que ATA el pago a la factura. Este es el nombre correcto en Service Layer; el apendice oficial de equivalencias de nombres confirma que PaymentInvoices en Service Layer es Payments_Invoices en la DI API. - DocEntry dentro de PaymentInvoices: la clave interna de la factura, NO el DocNum. - SumApplied: cuanto de ese pago se aplica a esa factura. - Remarks: campo de texto libre, confirmado en los ejemplos oficiales. Meté ahi el id y el transaction_id de ROKI para que el contador pueda rastrear cualquier asiento hasta el cobro original. DOS ADVERTENCIAS HONESTAS sobre este payload: 1. El valor "it_Invoice" para InvoiceType aparece en los ejemplos de la comunidad de SAP y en la DI API, pero NO lo encontre escrito con ese nombre exacto en la Service Layer API Reference oficial que lei. Confirmalo contra el $metadata de la instalacion real antes de darlo por bueno. 2. Existe un campo TransferReference que se usa comunmente para guardar la referencia externa del pago, pero tampoco lo pude confirmar en la referencia oficial que lei. Por eso arriba use Remarks, que si esta confirmado. Buscar el DocEntry a partir del numero de factura, si no lo guardaste antes: GET https://<servidor>:50000/b1s/v2/Invoices?$select=DocEntry,DocNum,DocTotal,CardCode&$filter=DocNum eq 1 Y para anular un cobro (por ejemplo si ROKI hace un reverso): NO se borra. IncomingPayments no acepta DELETE. Se anula con la accion Cancel: POST https://<servidor>:50000/b1s/v2/IncomingPayments(123)/Cancel Eso genera un documento de anulacion contable, que es lo correcto. Tambien existe CancelbyCurrentSystemDate si necesitas que la anulacion lleve la fecha de hoy y no la del documento original. - 12. Programar el respaldo por consulta, que es lo que de verdad te salva (2 horas, lo hace el programador)
Los webhooks se pierden. El servidor se reinicia, la red se cae, el firewall parpadea. Necesitas una segunda via, y en el caso de SAP en oficina esta segunda via muchas veces es la UNICA via (ver la seccion del webhook). Un trabajo programado que corre cada 5 o 10 minutos: 1. Lee de tu base local todos los pagos que creaste en ROKI y que todavia no marcaste como registrados en SAP. 2. Para cada uno: GET https://aura.roki.systems/api/connect/v1/payments/{id} con el Bearer. 3. Si el estado indica aprobado y todavia no lo registraste, corre exactamente la misma logica del paso 11. 4. Marcalo como registrado usando el transaction_id como llave de idempotencia, la misma que usa el webhook. La clave es que el camino del webhook y el camino de la consulta terminen en la MISMA funcion idempotente. Asi da igual cual de los dos llegue primero: el resultado es un solo Incoming Payment en SAP. - 13. Probar en sandbox contra una compañia de prueba (2 a 3 horas, programador y contador juntos)
Usa la llave sk_test_ de ROKI y una base de datos de prueba de SAP (nunca la de produccion). Casos que hay que probar si o si: - Pago completo de una factura. Verificar en SAP que la factura queda cerrada y el saldo del cliente baja. - Pago parcial. Verificar que la factura queda abierta con el saldo correcto. - El mismo webhook llegando dos veces. Debe crear UN solo Incoming Payment. - Webhook con firma invalida. Debe rechazarse con 400 y quedar registrado en el log. - Sesion vencida a mitad de la operacion. El conector debe reloguearse solo y completar. - Service Layer caido. El conector debe reintentar, no perder el pago. - Anulacion con POST IncomingPayments(id)/Cancel. Que el CONTADOR mire los asientos resultantes en SAP y diga si estan bien. El programador no puede juzgar eso. Este paso es el que mas se salta y el que mas caro sale saltarse. - 14. Pasar a produccion (1 hora)
Cambiar sk_test_ por sk_live_. Apuntar a la base de datos real. Confirmar que la cuenta contable del paso 5 es la definitiva y no la de pruebas. Correr UN cobro real de monto chico, de punta a punta, y que el contador lo verifique en SAP antes de anunciarle nada a los clientes. Dejar el log del conector accesible: cuando algo falle dentro de tres meses, alguien va a necesitar ver que respondio SAP, y los mensajes de error de Service Layer son crudos pero informativos.
Como llega el webhook
RESPUESTA CORTA: SAP Business One NO puede recibir el webhook de ROKI. Ni instalado en la oficina, ni instalado en la nube. Nunca. Y el problema no es solamente el firewall.
Hay dos razones, y la segunda es la que importa:
RAZON 1, el firewall. Un SAP Business One tipico esta en un servidor dentro de la oficina, detras del router del comercio, con IP privada. Internet no puede alcanzarlo. Eso ya lo sabias.
RAZON 2, la que casi nadie dice: aunque abrieras el firewall de par en par, NO SERVIRIA. Service Layer es una API OData para manipular objetos de negocio (facturas, pagos, articulos). No tiene ni tendra nunca un endpoint que acepte un POST arbitrario de un tercero con un formato ajeno. No existe un "/webhooks/roki" donde ROKI pueda escribir. Service Layer no sabe verificar una cabecera ROKI-Signature ni interpretar un evento payment.approved. Es una API de base de datos con reglas de negocio, no un receptor de eventos.
Y ademas SAP te lo prohibe explicitamente. Los Administrator's Guide oficiales, tanto el de Microsoft SQL Server como el de SAP HANA, dicen textualmente en su apendice de puertos: "The service layer is for internal component calls only and you do not need to expose it to the Internet." Exponer el 50000 a internet no es una configuracion agresiva: es ir contra la recomendacion escrita del fabricante, con una API que da acceso a toda la contabilidad de la empresa.
LO QUE SE HACE EN SU LUGAR: un CONECTOR. Un servicio chico, escrito por vos, que se para en el medio. ROKI le habla al conector; el conector le habla a SAP. SAP y ROKI nunca se ven las caras.
Hay cuatro maneras de montar ese conector. En orden de lo que yo recomendaria:
OPCION A — CONECTOR ADENTRO, SIN WEBHOOK, POR CONSULTA. La recomendada para el 80% de los comercios. El conector corre en una maquina dentro de la red de la oficina, la misma red que el servidor de SAP. NO recibe el webhook. En su lugar consulta cada 5 minutos: GET https://aura.roki.systems/api/connect/v1/payments/{id} para todos los pagos que tiene pendientes. Ventajas: CERO cambios de firewall entrante. Cero puertos abiertos. Cero DNS publico. Cero certificado publico. Cero superficie de ataque nueva. El equipo de red del comercio no tiene que aprobar nada, porque solo se usa salida HTTPS que ya esta permitida. Desventaja: hay hasta 5 minutos de demora entre que el cliente paga y que el cobro aparece en SAP. Para cobrar facturas, 5 minutos no le importa a nadie. Si le importa, baja el intervalo a 1 minuto. Esta opcion es la que le recomiendo a cualquier comercio que no tenga un administrador de sistemas de tiempo completo. Es aburrida, es barata y no se rompe.
OPCION B — CONECTOR ADENTRO, CON TUNEL DE SALIDA. Si de verdad quieren el webhook instantaneo. El conector corre adentro igual que en la opcion A, pero abre un tunel saliente hacia un servicio publico (Cloudflare Tunnel, ngrok, o equivalente). Ese servicio te da una URL publica HTTPS que apunta al conector, y el trafico entra por una conexion que el propio conector inicio hacia afuera. Ventaja: webhook en tiempo real sin abrir un solo puerto entrante en el firewall. Desventaja: agregas una dependencia de un tercero. Si el tunel se cae, dejas de recibir. Por eso: aunque uses esta opcion, DEJA CORRIENDO igual la consulta de la opcion A como respaldo.
OPCION C — CONECTOR ADENTRO, CON UN PUERTO ABIERTO. Solo si el comercio ya tiene infraestructura seria. Se publica el conector en internet por HTTPS 443, con nombre de dominio propio y certificado de una autoridad reconocida, tipicamente detras de un proxy inverso. El Administrator's Guide de SAP describe justamente esos dos escenarios de acceso externo en su seccion "Preparing External Addresses": "Reverse proxy (recommended)" y "NAT/PAT". Regla que no se negocia: lo que se publica es el CONECTOR, en el 443. El puerto 50000 de Service Layer se queda adentro, siempre. Desventaja: ahora tenes un servicio expuesto a internet dentro de la red de la oficina, y eso hay que mantenerlo, parchearlo y monitorearlo. Muchos comercios chicos no estan para eso.
OPCION D — CONECTOR AFUERA, CON VPN A LA OFICINA. El conector vive en la nube y recibe el webhook comodamente, pero entonces tiene que llegar al 50000 que esta adentro, y eso exige una VPN sitio a sitio contra la oficina. Es la opcion mas cara y la que mas partes moviles tiene. Solo tiene sentido si el comercio YA tiene una VPN funcionando por otros motivos. Si no la tiene, no armes una VPN solo para esto.
DATO NUEVO Y RELEVANTE, PERO EN LA DIRECCION CONTRARIA: desde SAP Business One 10.0 FP 2602, Service Layer SI soporta webhooks propios. La documentacion dice literal: "As of SAP Business One 10.0 FP 2602, the Service Layer supports webhooks." Se administran con la entidad EventSubscriptions, se prenden por compañia llamando a CompanyService_UpdateAdminInfo con {"AdminInfo": {"EnableWebhook": "tYES"}}, y requieren un componente nuevo llamado Webhook Messenger Service. Soportan autenticacion HMAC SHA-256, igual que ROKI. PERO OJO, no te confundas de direccion: eso es SAP MANDANDO webhooks hacia afuera, no recibiendolos. Sirve para lo contrario: para que SAP le avise a tu conector cuando se crea una factura, y asi el conector genere el link de pago de ROKI automaticamente sin tener que andar consultando SAP. Es genuinamente util para el paso 9, pero NO resuelve el problema de recibir el cobro de ROKI. Y ademas, FP 2602 es de febrero de 2026: casi ningun comercio lo tiene instalado todavia. No armes el diseño asumiendo que esta disponible.
CONCLUSION PRACTICA: escribi el conector con la logica de registro del cobro en UNA sola funcion idempotente, con el transaction_id de ROKI como llave. Despues conectale dos disparadores: el webhook (si podes recibirlo) y la consulta periodica (siempre). Asi el mismo codigo sirve para un comercio con IP publica y para uno detras del router de la casa, y podes cambiar de opcion sin reescribir nada.
Lo que se rompe
- EL MITO DEL PUERTO, corregido: verifique los dos manuales oficiales y el puerto por defecto del Service Layer NO cambia entre SQL Server y HANA. Los dos dicen exactamente lo mismo: 50000 para el load balancer y 50001, 50002, 50003... para los miembros. Tu punto de partida era todavia mas fuerte de lo que creias. Si alguien te dice que en HANA es otro puerto, o esta pensando en el puerto de la base de datos (3xx13/3xx15 en HANA contra 1433 en SQL Server, que al conector no le importa) o lo cambiaron a mano en esa instalacion.
- LA DIFERENCIA REAL ENTRE SQL Y HANA NO ES EL PUERTO, ES LA VERSION MINIMA: Service Layer para Microsoft SQL Server recien existe desde SAP Business One 10.0. Un comercio con SQL Server en 9.2 o 9.3 no tiene puerto 50000 y no lo va a tener nunca sin un upgrade completo. En HANA existe desde 9.x. Si vas a preguntar UNA sola cosa antes de presupuestar, pregunta la version, no la base de datos.
- DocEntry NO ES DocNum. Es la trampa mas cara de esta integracion. DocEntry es la clave interna con la que la API identifica el documento; DocNum es el numero que ve el humano en la factura impresa. La documentacion oficial de SAP trae un ejemplo donde el mismo documento tiene DocEntry 22 y DocNum 11. Si aplicas un pago usando el DocNum como si fuera DocEntry, vas a acreditar la plata contra OTRA factura, de OTRO cliente, sin ningun mensaje de error. Guarda siempre el DocEntry, y si solo tenes el DocNum, buscalo con $filter=DocNum eq N antes de aplicar nada.
- LA SESION SE MUERE A LOS 30 MINUTOS. El campo SessionTimeout de la respuesta del login vale 30 por defecto. Cuando expira, Service Layer devuelve 401 con code 301 y el mensaje "Invalid session or session already timeout." El conector tiene que detectar ese codigo, reloguearse y reintentar. Si no lo programas, la integracion funciona perfecto en las pruebas de la tarde y se cae sola durante la noche.
- LA COOKIE B1SESSION ES OBLIGATORIA EN CADA LLAMADA, y si tu aplicacion no corre dentro de un navegador la tenes que poner a mano. La documentacion lo advierte explicitamente. Mucha gente hace el login, ve el 200 OK, y despues se pregunta por que la siguiente llamada da 401.
- LA COOKIE ROUTEID PARECE OPCIONAL Y NO LO ES EN LA PRACTICA. Es la que mantiene la pegajosidad contra el mismo nodo del load balancer. Si la instalacion tiene el default de 10 nodos y vos no la mandas, vas a ver errores intermitentes imposibles de reproducir: una llamada anda, la siguiente no.
- EL CUERPO CRUDO DEL WEBHOOK. La firma ROKI-Signature es HMAC sobre timestamp + "." + los bytes exactos del cuerpo. Si tu framework parsea el JSON y vos lo volves a serializar para calcular la firma, un espacio de diferencia y ya no coincide. Capturá el cuerpo crudo ANTES de que el framework lo toque. Es la causa numero uno de "la firma no me valida".
- IDEMPOTENCIA O COBROS DUPLICADOS. Los webhooks se reenvian. Si tu handler crea un Incoming Payment cada vez que llega un mensaje, un solo reenvio le acredita al cliente el doble. Guarda el transaction_id en tu base ANTES de tocar SAP y usalo como llave unica. Y que el webhook y la consulta de respaldo terminen en la MISMA funcion idempotente.
- EL CERTIFICADO AUTOFIRMADO. Service Layer obliga HTTPS con TLS 1.2 o 1.3, y la mayoria de instalaciones quedaron con el certificado autofirmado que ofrece el instalador en la ventana "Specify Security Certificate". Tu conector lo va a rechazar. La solucion correcta es exportar ese certificado e instalarlo en el almacen de confianza de la maquina del conector. La solucion facil es desactivar la verificacion, y es una mala idea: en la red interna cualquiera puede hacerse pasar por el servidor de SAP y quedarse con las credenciales de un usuario que puede crear asientos contables.
- NO EXPONGAS EL 50000 A INTERNET. Los dos Administrator's Guide lo dicen textual: "The service layer is for internal component calls only and you do not need to expose it to the Internet." Es una API con acceso a toda la contabilidad. Lo que se publica, si acaso, es el conector en el 443. Nunca Service Layer.
- LOS NODOS DEL 50001 EN ADELANTE HABLAN POR HTTP, NO HTTPS. La guia oficial recomienda configurar el firewall de cada maquina miembro para que solo acepte trafico del load balancer. Tu conector siempre le pega al 50000, jamas a un nodo directo.
- LOS WEBHOOKS DE SAP VAN EN LA DIRECCION CONTRARIA. Desde SAP Business One 10.0 FP 2602 Service Layer soporta webhooks con la entidad EventSubscriptions, pero eso es SAP AVISANDO hacia afuera cuando pasa algo adentro. No es SAP recibiendo. Sirve para que tu conector se entere de que se creo una factura y genere el link de pago solo, y eso es genuinamente util. No sirve para recibir el cobro de ROKI. Y ademas FP 2602 es de febrero de 2026: casi nadie lo tiene instalado, no diseñes asumiendolo.
- INCOMINGPAYMENTS NO SE BORRA. La referencia oficial de la API expone GET, POST, PATCH y las acciones Cancel, CancelbyCurrentSystemDate, GetApprovalTemplates y RequestApproveCancellation. No hay DELETE. Para revertir un cobro se usa POST IncomingPayments(id)/Cancel, que genera el documento contable de anulacion. Esta bien que sea asi: la contabilidad no se borra, se contra-asienta.
- EL MEDIO DE PAGO TIENE QUE CUADRAR CON LO APLICADO. Si mandas TransferSum 1500.00 pero en PaymentInvoices aplicas 1200.00, SAP rechaza el documento. Suena obvio y es donde mas se pierde tiempo en las pruebas, sobre todo con pagos parciales, descuentos por pronto pago y redondeos.
- LOS EJEMPLOS OFICIALES INCLUYEN CashFlowAssignments Y NO SIEMPRE ES OPCIONAL. Tanto el ejemplo de IncomingPayments como el de VendorPayments en la referencia oficial lo traen. Segun la configuracion de la compañia y la localizacion, el POST puede fallar sin esa coleccion. Si te da un error de flujo de caja, es por ahi.
- DOS COSAS QUE NO PUDE CONFIRMAR Y NO TE VOY A INVENTAR: (1) el valor "it_Invoice" para el campo InvoiceType aparece en ejemplos de la comunidad SAP y en la DI API, pero no lo vi escrito con ese nombre exacto en la Service Layer API Reference oficial que lei; (2) el campo TransferReference, que mucha gente usa para guardar la referencia externa del pago, tampoco lo pude confirmar en esa referencia. Verificá ambos contra el $metadata de la instalacion real (GET /b1s/v2/$metadata) antes de darlos por buenos. Mientras tanto usa Remarks, que si esta confirmado en los ejemplos oficiales.
- LA LICENCIA: TECNICAMENTE PERMISIVO, CONTRACTUALMENTE NO. Service Layer te deja hacer login con cualquier usuario valido y en la practica no fuerza la verificacion de licencia en cada llamada. Eso NO significa que la integracion sea gratis. El License Guide de SAP dice que los tipos Professional, Limited CRM, Limited Financials, Limited Logistics y Starter incluyen las autorizaciones de Indirect Access, y que el modelo es de usuario nombrado con prohibicion expresa de compartir usuarios. Que el partner confirme el contrato. No te escudes en que funciona.
- OLVIDARSE DEL RESPALDO POR CONSULTA. Si solo programas el webhook, el dia que se caiga la red o se reinicie el servidor vas a tener clientes que pagaron y facturas que en SAP siguen abiertas, y nadie se va a enterar hasta que llame un cliente enojado. El GET /payments/{id} periodico es barato de programar y es lo que convierte esto en un sistema confiable. Para un SAP en oficina, ademas, muchas veces es la unica via posible.
- EL SERVICE LAYER CONTROLLER EN WINDOWS PIDE POWERSHELL EN "Unrestricted". La documentacion es explicita: antes de usar el controller en la version de Microsoft SQL hay que verificar con Get-ExecutionPolicy y, si no esta en "Unrestricted", ponerlo con Set-ExecutionPolicy Unrestricted. Si el administrador no sabe esto, va a pensar que el controller esta roto.
- EL CONTROLLER NO ADMINISTRA INSTALACIONES DISTRIBUIDAS. La limitacion esta escrita en el manual: si algunos nodos estan en una maquina y el load balancer en otra, el Service Layer Controller no los maneja. Aplica igual en HANA y en SQL. En esos casos hay que ir a mano a cada servidor.
- USA /b1s/v2 EN PROYECTOS NUEVOS. /b1s/v1 es OData v3 y esta deprecado desde SAP Business One FP 2405; /b1s/v2 es OData v4 y es el protocolo principal. El endpoint de Login funciona en las dos, asi que es facil quedarse en v1 por inercia. No lo hagas.
- NO USES EL USUARIO "manager" NI EL USUARIO "Support". El primero tiene privilegios totales y si le roban la clave al conector perdes todo. El segundo esta reservado para soporte del partner: viene bloqueado por defecto, solo funciona si el remote support platform subio un reporte en los ultimos 7 dias, y todo lo que hace queda registrado con nombre y motivo. Ninguno de los dos es para una integracion.
Lo que no pudimos confirmar
Cada nombre de menu y cada puerto de esta pagina se verifico contra la documentacion oficial de la plataforma. Estos 6 puntos no se pudieron confirmar, y se dejan senalados en vez de presentarlos como ciertos:
- Ventana "Service Port" del Components Setup Wizard: "puerto para SSO, por defecto 40001" - nombre-distinto. La ventana se llama exactamente "Service Port" (confirmado), pero el valor por defecto ya no es 40001. En el Administrator's Guide 10.0 PL02 (v1.2.1, 2020-07-01) decia 40001; en las guias vigentes (SQ
- "El conector va a mandar ese codigo de cuenta en el campo TransferAccount (los ejemplos oficiales de la API usan valores como \"_SYS00000000004\")" - nombre-distinto. El campo TransferAccount y el valor _SYS00000000004 SI aparecen en la referencia oficial del Service Layer, pero en el ejemplo de POST /b1s/v2/VendorPayments (pagos efectuados a proveedores), no en el
- "El conector va a mandar ese codigo de cuenta [el que se define en House Bank Accounts - Setup] en el campo TransferAccount" - no-verificable. Ninguna documentacion oficial que pude leer conecta el codigo de la ventana "House Bank Accounts - Setup" con el campo TransferAccount de la API. TransferAccount recibe valores de formato _SYS00000000
- (Preambulo) "Los dos Administrator's Guide dicen exactamente lo mismo en su Appendix 1: List of Default Ports for Different Server Components" - nombre-distinto. El contenido de la tabla es identico palabra por palabra en las dos variantes: "50000 (for load balancer); 50001, 50002, 50003… (for load balancer members) | Service Layer | The service layer is for i
- "para hacer login contra Service Layer solo hace falta un usuario y contraseña validos" y "en la practica Service Layer NO fuerza la verificacion de licencia en - no-verificable. El login si esta documentado (CompanyDB + UserName + Password). Pero la afirmacion sobre que el Service Layer no valida licencia por llamada no aparece en ninguna guia oficial que pude leer, ni a favo
- En la pantalla "Choose Company" del cliente, columna del nombre de base de datos - no-verificable. La ventana "Choose Company" existe y esta citada en los Administrator's Guide ("the Choose Company window displays only the companies to which your Windows account is bound"; "Manually enter the compa
Fuentes
- https://help.sap.com/doc/fc2f5477516c404c8bf9ad1315a17238/10.0/en-US/Working_with_SAP_Business_One_Service_Lay
- https://help.sap.com/doc/3ec041c030424a96b54cfbe7192bfcb5/10.0/en-US/AdministratorGuide_SQL.pdf — "Administrat
- https://help.sap.com/doc/4e7c047f2c9e4cbe97800ffaf7b68f8e/10.0/en-US/B1_for_SAP_HANA_Admin_Guide.pdf — "Admini
- https://help.sap.com/doc/056f69366b5345a386bb8149f1700c19/10.0/en-US/Service%20Layer%20API%20Reference.html —
- https://help.sap.com/doc/14c6d92982fd4a9dbf7df66b5108433b/10.0/en-US/LicenseGuide.pdf — "License Guide for SAP
- https://help.sap.com/doc/089315d8d0f8475a9fc84fb919b501a3/10.0/en-US/SDKHelp/SAPbobsCOM~Payments.html — "API R
- https://help.sap.com/docs/SAP_BUSINESS_ONE/68a2e87fb29941b5bf959a184d9c6727/4506b88b7d720487e10000000a155369.h
- https://help.sap.com/docs/SAP_BUSINESS_ONE/68a2e87fb29941b5bf959a184d9c6727/45071a5bf61941dee10000000a1553f6.h
- https://help.sap.com/docs/SAP_BUSINESS_ONE/f110a154dd0f4c20bf7f3ebca9eeb794/84d62151fbf64b69aec096431539f839.h
- NOTA SOBRE FUENTES NO OFICIALES: dos datos que circulan mucho NO los pude confirmar en la documentacion oficia
