AdemeroHelp

Integrate Paige with the SAP Business One Service Layer

For developers: the Service Layer calls that turn a Paige invoice into an SAP Business One A/P invoice with the PDF attached — log in, upload the PDF to Attachments2, then POST the PurchaseInvoices document with the attachment entry — fed from Paige's SFTP export files or the Paige API.

IntegratorsHalf a day for a developerVerified 2026-09-05

Before you begin

  • SAP Business One with the Service Layer running, a user for the integration, and the attachments folder configured for the Service Layer
  • Somewhere to run code on a schedule
  • Either an SFTP server Paige exports to, or a Paige API key

At the end of this guide you'll have the exact Service Layer calls — and the two ways to get Paige's data into them — to create an A/P invoice with the invoice PDF attached for every invoice Paige finishes.

Getting Paige's data

SourceHowWhen to prefer it
SFTP export filesPaige writes <name>.pdf and <name>.json per document; your job polls the folder and reads the JSON (fields, metadata.document_type, metadata.pdf_file)Simplest; the PDF is already assembled
Paige APIGET …/scanJobs/{id}/documentPages, then …/pages/{pageId}/fieldValues; page images by signed URLYou'd rather query than watch a folder. The API returns page images, not one merged PDF — see Integrate your own system with the Paige API.

The rest assumes you have, per invoice, the field values and the PDF bytes.

Prerequisite: the attachments folder

The Service Layer can only store attachments in the folder configured under Administration > System Initialization > General Settings > Path > Attachments Folder, and the Service Layer process must be able to write there. On a Linux-hosted Service Layer that means the Windows share is mounted; your SAP partner usually sets this up once. Without it, attachment uploads fail.

Log in

http
POST https://<server>:50000/b1s/v2/Login
Content-Type: application/json

{ "CompanyDB": "<database>", "UserName": "paige-integration", "Password": "…" }

Keep the B1SESSION cookie for the calls below; sessions expire after the configured timeout, so re-login on a 401.

The calls

1. Upload the PDF as an attachment

http
POST https://<server>:50000/b1s/v2/Attachments2
Content-Type: multipart/form-data; boundary=…

--…
Content-Disposition: form-data; name="files"; filename="INV-20441.pdf"
Content-Type: application/pdf

<raw PDF bytes>
--…--

What you should see: 201 Created with an AbsoluteEntry — the attachment entry number you'll reference on the invoice.

2. Create the A/P invoice referencing it

http
POST https://<server>:50000/b1s/v2/PurchaseInvoices
Content-Type: application/json

{
  "CardCode": "V00123",
  "DocDate": "2026-08-28",
  "DocDueDate": "2026-09-27",
  "NumAtCard": "INV-20441",
  "DocType": "dDocument_Service",
  "Comments": "Paige – Vendor Invoice",
  "AttachmentEntry": 57,
  "DocumentLines": [
    {
      "AccountCode": "6150",
      "LineTotal": 1284.50,
      "ItemDescription": "Invoice INV-20441"
    }
  ]
}

CardCode is the vendor's business partner code; look it up first with GET …/BusinessPartners?$filter=CardName eq 'Acme Office Supply' if Paige only gives the name. DocType dDocument_Service posts to G/L accounts (AccountCode + LineTotal); for item-based invoices use dDocument_Items with ItemCode, Quantity, and UnitPrice per line, one per row of Paige's line_items table.

What you should see: 201 Created with the new document's DocEntry and DocNum, and the PDF on the invoice's Attachments tab in the SAP client.

Idempotency and errors

  • Before creating, GET …/PurchaseInvoices?$filter=CardCode eq 'V00123' and NumAtCard eq 'INV-20441' and skip if one exists.
  • Paige's values are strings as printed; format dates as YYYY-MM-DD and amounts as numbers.
  • Tax and account errors come back as 400 with SAP's message in the body — usually a G/L account not allowed for the vendor's tax group, or a closed posting period.
  • If you poll SFTP, move processed files to a processed/ subfolder; if you poll the Paige API, record processed page IDs.
  • POST …/Logout when the job finishes.