Panama e-invoicing from SAP Business One: NUC-JSON field mapping and DGI rejections
By Zain Abbas, Kodenova · Updated
To issue a Panama electronic invoice (Factura Electrónica, FE) from SAP Business One through the Digifact PAC, you send one NUC-JSON document per invoice or credit memo. Most of the data already sits in OINV, INV1, OCRD and OITM. What SAP B1 does not have out of the box is the receiver type, the RUC check digit (DV), the location code (CodUbi) and the CPBS item code, so those become user fields. The PAC answers with a CUFE, an authorisation protocol and a QR URL, which you write back to the document.
This guide is the mapping I use in my SAP Business One add-on for Panama. It was tested on 27 October 2026 in an SAP B1 10 company on SQL Server against the Digifact sandbox: 34 scenarios, from a 7 % consumer invoice to a 105-line invoice, exports, zona franca, credit notes and cancellations. For the commercial overview, see Panama e-invoicing for SAP Business One.
How does the flow from SAP Business One to the DGI work?
- The user adds an A/R invoice (object 13) or A/R credit memo (object 14) in SAP B1 as usual.
- The add-on reads the document, checks the DGI rules it can check locally, and builds the NUC-JSON.
- It posts the JSON to Digifact (
/api/v2/transform/nuc_json, query paramsTAXID,FORMAT,USERNAME). Digifact turns it into the DGI XML, signs it and gets the authorisation. - The answer carries the CUFE, the protocol, the authorisation date and the QR URL. The add-on writes them to user fields on
OINV/ORINand attaches the XML and PDF to the document.
Two design decisions saved me the most trouble:
- One registry row per document (a user table,
@FE_PA_DOC, keyed13-<DocEntry>or14-<DocEntry>). Two workstations that add documents at the same time can never send the same invoice twice. - Query before resend. If the send timed out, the add-on first asks Digifact whether that NumeroDF already exists, and only then sends again. In the test, pressing “Reintentar” on an already authorised invoice returned the same CUFE and sent nothing.
Which SAP B1 fields map to which NUC-JSON fields?
The NUC-JSON is case-sensitive. Buyer.TaxID works, buyer.taxid does not. Many values go in lists of { "Name": ..., "Value": ... } objects rather than plain properties, which is the first thing that trips people coming from Guatemala FEL or El Salvador DTE.
| NUC-JSON field | What it is | Where it comes from in SAP B1 |
|---|---|---|
Header.DocType | 01 invoice, 03 export, 04/06 credit note, 05/07 debit note, 08, 09, 10 | Object type (13/14), DocSubType = 'DN' for debit notes, plus a document UDF for 02/08/09/10 |
Header.IssuedDateTime | Issue date and time, 2026-10-27T14:23:00-05:00 | Taken at send time and stored in a UDF (U_FE_FechaEmi). Credit notes need it later |
AdditionalIssueDocInfo → NumeroDF | 10-digit fiscal number, zero padded, never restarts | Own counter per billing point. Do not reuse DocNum blindly if you have several series |
PtoFactDF | Billing point, 3 digits, not 000 | Add-on setting |
CodigoSeguridad | Random 9 digits, part of the CUFE, not equal to NumeroDF | Generated per document |
Seller.TaxID, TaxIDType, DigitoVerificador | Issuer RUC, 1 natural / 2 jurídico, DV | Add-on settings (one company, one RUC) |
Seller.BranchInfo.Code | 0000 head office, 0001+ branches | Add-on setting |
Buyer.TaxID | RUC, or CF for consumidor final, or EXTRANJERO | OCRD.LicTradNum |
TipoReceptor | 01 contribuyente, 02 consumidor final, 03 gobierno, 04 extranjero | BP UDF U_FE_TipoRec |
Buyer.TaxIDType / DigitoVerificador | Natural or jurídico, DV of the RUC | BP UDFs U_FE_TipoRuc, U_FE_DV |
CodUbi | Province-district-corregimiento code | BP UDF U_FE_CodUbi |
Buyer.Name, email, phone | Receiver name and contact | OCRD.CardName, E_Mail, Phone1 |
Items[].Description, Qty | Line text and quantity | INV1.Dscription, Quantity |
Items[].Price | Unit price before discount | INV1.PriceBefDi |
Discounts.Discount[].Amount | Discount per unit in balboas, not a percentage | PriceBefDi - Price |
Codes → CodCPBSabr / CodCPBScmp | CPBS goods and services code (2 and 4 digits) | Item UDF U_FE_CPBS on OITM |
Taxes.Tax[].Code | ITBMS 00 = 0 %, 01 = 7 %, 02 = 10 %, 03 = 15 % | From INV1.VatPrcnt |
Taxes.Tax[].Amount | Tax amount of the line | INV1.VatSum (or VatSumFrgn) |
Totals.TotalItem | Line total with tax | LineTotal + VatSum |
Payments | Type 02 without credit terms; with credit terms type 01 plus a PLAZO line with the due date | OCTG days of GroupNum, DocDueDate |
Two details from testing that the spec does not make obvious:
- Line amounts, not header amounts. Build every total from the lines and let the header be their sum. I had zero mismatches across multi-rate invoices (0, 7 and 10 % on one document) and a 105-line invoice by rounding each line to two decimals first, then adding.
- Foreign currency companies. If the company’s local currency is not USD,
DocTotal,LineTotalandVatSumare in local currency. The e-invoice must carry the document currency, so readDocTotalFC,TotalFrgnandVatSumFrgninstead. My test company had GBP as local currency, which is how this showed up.
Which user fields do you need in SAP Business One?
Inputs (the user or the BP master fills them): U_FE_TipoRec, U_FE_TipoRuc, U_FE_DV, U_FE_CodUbi on OCRD; U_FE_CPBS on OITM; U_FE_Incoterm, U_FE_PuertoEmb and U_FE_TipoDoc on the document.
Outputs (written by the add-on on OINV and ORIN): status, CUFE, protocol, authorisation date, QR URL, NumeroDF, issue date/time sent, error text, attempts, and the cancel reason. The QR URL is about 560 characters, so it needs a memo field, not a 254-character alphanumeric one.
Many clients already have their own fields for RUC type or DV from a previous localization. My settings screen lets you point each key to an existing field instead of creating a duplicate. Whatever you do, create the fields through the DI API or the UI, never with ALTER TABLE.
Before go-live I run this check. It lists the master data that will be refused before anything reaches the PAC. SQL Server version first:
-- Customers that will fail: contribuyente/gobierno without RUC, DV or location code
SELECT C.CardCode, C.CardName, C.LicTradNum, C.U_FE_TipoRec, C.U_FE_DV, C.U_FE_CodUbi
FROM OCRD C
WHERE C.CardType = 'C'
AND ISNULL(C.U_FE_TipoRec, '01') IN ('01', '03')
AND (ISNULL(C.LicTradNum, '') = '' OR ISNULL(C.U_FE_DV, '') = '' OR ISNULL(C.U_FE_CodUbi, '') = '');
-- Items sold in the last 90 days without a CPBS code
SELECT DISTINCT L.ItemCode, I.ItemName
FROM INV1 L
INNER JOIN OINV H ON H.DocEntry = L.DocEntry
INNER JOIN OITM I ON I.ItemCode = L.ItemCode
WHERE H.DocDate >= DATEADD(DAY, -90, GETDATE())
AND ISNULL(I.U_FE_CPBS, '') = '';
SAP HANA version (quoted identifiers, IFNULL, ADD_DAYS):
SELECT C."CardCode", C."CardName", C."LicTradNum", C."U_FE_TipoRec", C."U_FE_DV", C."U_FE_CodUbi"
FROM "OCRD" C
WHERE C."CardType" = 'C'
AND IFNULL(C."U_FE_TipoRec", '01') IN ('01', '03')
AND (IFNULL(C."LicTradNum", '') = '' OR IFNULL(C."U_FE_DV", '') = '' OR IFNULL(C."U_FE_CodUbi", '') = '');
SELECT DISTINCT L."ItemCode", I."ItemName"
FROM "INV1" L
INNER JOIN "OINV" H ON H."DocEntry" = L."DocEntry"
INNER JOIN "OITM" I ON I."ItemCode" = L."ItemCode"
WHERE H."DocDate" >= ADD_DAYS(CURRENT_DATE, -90)
AND IFNULL(I."U_FE_CPBS", '') = '';
If you only have SQL Server queries today, the SQL to HANA converter handles most of the dialect changes.
How do credit notes reference the original invoice?
A credit memo in SAP B1 that is based on an invoice (RIN1.BaseType = 13, BaseEntry = <invoice DocEntry>) becomes DGI type 04. It must carry three values in AdditionalInfo: the issuer name (NombEmRef), the issue date/time of the original e-invoice (FechaDFRef) and its CUFE (CUFERef). That is why the issue time must be stored when the invoice is sent. You cannot rebuild it later from DocDate.
A credit memo without a base document, or based on an invoice from before your go-live date, is a generic note, type 06, with no reference.
The DGI rules that bit hardest, all of which I now check in SAP before sending:
| DGI rule | What it means | Check in SAP B1 |
|---|---|---|
| 1710 | The note must have the same receiver as the invoice | Take the buyer from the JSON that was sent for the invoice, not from today’s BP master data |
| 1711 | Credit note larger than the invoice | Compare with the base invoice total |
| 1714 | Note issued more than 180 days after the invoice | DocDate of note vs invoice |
| 1717 | All credits exceed invoice + debit notes | Sum the authorised notes already linked through RIN1/INV1 base lines |
| 1718 | Note against a cancelled (anulada) invoice | Status of the base invoice |
| 1720 | Referenced invoice has no stored issue date/time | The FechaEmi field of the invoice |
A credit note on a base invoice that is not authorised yet is not an error. My add-on holds it until the invoice has its CUFE, then sends it.
What causes the most common Panama FE rejections?
From the sandbox tests, in the order I hit them:
- Government receiver (03) with a normal RUC. Rule 1604: the RUC must be in the DGI table of government entities (Tabla 30). If the customer is not on that list, use receiver type 01. After correcting the RUC, a simple retry authorised the same invoice.
- Consumidor final with a legal-entity RUC. Rule 1621: a jurídico RUC (
TaxIDType2) cannot be receiver type 02. - Export or foreign operation without INCOTERM. For types 03 and 10 the sandbox answered that the delivery conditions (
CondEntr) were missing. Put the INCOTERM in a document UDF and send it inAdditionalInfo. - The
<character in an item description. One test invoice came back “XSLT failed” because of a<in the line text. Escape or replace it before sending.ñ,á,&,"and>were all accepted, including a customer called “Compañía Ñandú & Hijos”. - Document-level discount.
OINV.DiscSumhas no clean place in the item structure. My add-on blocks a document that still has a header discount and asks for line discounts instead. The same header-discount problem distorts sales reports too, see why SAP B1 sales totals do not match.
How do you cancel (anular) an e-invoice from SAP Business One?
Cancellation goes to Digifact’s CancelFePA endpoint with the issuer RUC, the CUFE, a reason (Motivo) and the user. Two things I measured on the test environment:
- Right after authorisation, the cancel fails with
{"Codigo":9019,"Anulado":false,"Mensaje":"Anulacion incorrecta. Verifique si el CUFE pertenece a una FE existente"}. Three to eight minutes later the same call was accepted. My add-on retries once a minute instead of showing the user an error. - Short reasons fail with the same 9019. Twenty characters or fewer were always refused, 25 or more always accepted, although the DGI technical sheet allows 15 to 1000. I enforce a 25-character minimum in the form.
In SAP B1, Data > Cancel on an authorised invoice should cancel at the DGI first. If the DGI refuses, block the SAP cancellation, otherwise SAP shows the invoice as cancelled while the DGI still counts it as valid. An invoice that never reached the DGI can be cancelled in SAP directly.
If you are building this as an add-on yourself, the event handling, packaging and DI posting patterns are in my SAP Business One add-on development guide, and the fields of the tables above are in the SAP B1 table reference.
What is still open?
Contingency mode (TipoEmision 02/04) and currencies other than USD are not in my add-on yet. Debit notes (05 and 07) were authorised on the sandbox, but a company with UK localization cannot post them from the DI API (DocumentSubType = DN is refused), so test those in a company with Panama or Latin America localization.
If you run SAP Business One in Panama and need FE through Digifact, tell me about your setup. I have done the same kind of integration for Guatemala FEL, El Salvador DTE, Ecuador SRI and Saudi ZATCA.
Sources
Related services
Frequently asked questions
Do I need a PAC to issue electronic invoices from SAP Business One in Panama?
For an ERP integration, yes in practice. SAP Business One does not talk to the DGI directly. The document goes to a PAC (Proveedor de Autorización Calificado), which validates it, authorises it and passes it to the DGI. My add-on uses the Digifact PAC and its NUC-JSON API.
Which SAP Business One documents become which DGI document types?
An A/R invoice is type 01 (or 03 export, 08 zona franca, 09 reembolso, 10 operación extranjera when you set it). An A/R credit memo that is based on an e-invoiced invoice is 04; without a referenced invoice it is 06. Debit notes are 05 and 07.
Why does the DGI refuse to cancel an invoice I just issued?
On the Digifact test environment, CancelFePA answered code 9019 for a few minutes after authorisation, and also whenever the reason (Motivo) was 20 characters or shorter. Waiting about 3 minutes and writing a reason of 25 characters or more worked every time.
Ready to get started?
Tell us what you need. You get a clear technical answer, a fixed scope and a price, usually within 24 hours.
