ZATCA Sandbox – Confused about Onboarding and CSID Process (PHP Integration)

Hi team,
I’m a developer working with CodeIgniter/PHP and trying to integrate ZATCA’s e-Invoicing system for simplified invoices in Sandbox mode.

I followed the documentation but I’m confused about a few things. Here’s what I’ve done:

  • Registered on the ZATCA Developer Portal
  • Generated a private key and CSR using OpenSSL
  • Called the Compliance CSID API and got a response
  • Tried calling the Production CSID API but got an error

My questions:

  1. How do I get the test Request ID required for the Production CSID API?
  2. I can’t find the EGS Management section in the Developer Portal – where is it?
  3. Do I need to generate a real certificate or just dummy data for Sandbox?
  4. What should I put in the Authorization header when using Reporting API?
  5. Is there a working Postman collection for testing all steps?

Please guide me step by step so I can understand how to complete the Sandbox onboarding process. I’m willing to follow your instructions.

Thanks in advance!


:round_pushpin: Where to Post Questions:

  • ZATCA Developer Portal Help Center or Support Form
  • Postman Community (if testing via Postman)
  • Stack Overflow (tag with zatca, e-invoicing, api)
  • Email ZATCA Support – If no public forum is available

Dear @Ali00032,

Welcome to the Fatoora community portal.

Please note that Sandbox environment is not the actual integration, it’s just an environment where youn can test the APIs behavior without Fatoora portal credentials, for the actual integration you will need a real active VAT number credentials, however, you can find the answers to your questions in order below:

A1: request id is being returned through the compliance CSID API, it will be returned alongside with the needed BinarySecurityToken and the secret, those BinarySecurityToken will be used to perform the compliance checks, which are dummy invoices to be send just to ensure that your system can actually generate compliant tax documents with ZATCA’s requirements.

A2: Yes this is normal, EGS management section will be found on Fatoora portal, not Developer portal, under " list of the onboarded devices"

A3: Sandbox is not the real environment to integrate, you will need a fatoora portal credentials access to integrate to either production or simulation environment to use the real date.

A4: In reporting API, the authorization will be basic auth in terms of username and password, the username will be the binarysecuritytoken and the password will be the secret returned from the production CSID API request (not the compliance CSID API), the production CSID will be for reporting & clearance, while the compliance CSID will be only for the compliance checks phase, but since you are only designing your system to deal with the simplified tax documents, you will not need the clearance API as it’s only for standard tax documents.

A5: No, there are no official published postman collection, instead, you can rely on the API documentation from the developer portal to have a better visibility on the APIs behavior.

Also, I am advising you to go through the manuals in e-invoicing main web page under “educational library”, you will find a comprehensive guidelines.

Regards,

Dear Aturkistani,

I hope you’re well.

I’m experiencing a 400 Bad Request error when attempting to submit my Certificate Signing Request (CSR) through the ZATCA Fatoora Developer Portal.

Here’s what I have tried so far:

Using Fatoora CLI:

shell

fatoora -csr -pem -privateKey my-private-key.pem -generatedCsr my-csr.csr -csrConfig zatca-csr.properties

My zatca-csr.properties file includes:

csr.common.name=TST-87431145-311218730900003
csr.serial.number=1-TST|2-TST|3-088f0539-15ab-4e72-a515-b4b4afa8f74c
csr.organization.identifier=311218730900003
csr.organization.unit.name=Riyadh Branch
csr.organization.name=Al Noor.
csr.country.name=SA
csr.invoice.type=1100
csr.location.address=RRRD2929
csr.industry.business.category=car

Using OpenSSL:
I also tried generating the CSR manually with openssl following your instructions and configuration file:

shell

CopyEdit

openssl req -new -sha256 -key PrivateKey.pem -extensions v3_req -config config.conf -out taxpayer.csr

My config.conf contains:

ini

CopyEdit

[ OIDs ]
certificateTemplateName = 1.3.6.1.4.1.311.20.2

[ req ]
default_bits = 2048
emailAddress = sa.example@example.com
req_extensions = v3_req
x509_extensions = v3_ca
prompt = no
default_md = sha 256
req_extensions = req_ext
distinguished_name = dn

[ dn ]
C = SA
OU = test department
O = test company
CN = 127.0.0.1

[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment

[ req_ext ]
certificateTemplateName = ASN1:PRINTABLESTRING:PREZATCA-Code-Signing
subjectAltName = dirName:alt_names

[ alt_names ]
SN = 1-AlNahar|2-AlNaharERP|3-5G6JJ109
UID = 312543537100003
title = 1100
registeredAddress = Jubail 35514, SA-547755497
businessCategory = Air conditioning maintenance

Base64 Conversion:
I base64-encoded the generated CSR and then tried posting it through API, but I received 400 Bad Request each time.


My Question:
Could you please advise me:

➥ If there’s a specific format or field that I’m missing in my CSR?
➥ Why I’m receiving a 400 Bad Request when I submit it through the API or Fatoora CLI?

Any guidance or example configuration you could provide would be greatly appreciated.

Thank you in advance for your help.

Best wishes,

dear @Ali00032 ,

As Sandbox is restricted with static data, please use the default dummy VAT number “399999999900003” in the CSR generation and try again.

If you are willing to onboard with the real VAT, you need to use Fatoora environment’s endpoints.

Regards,

Dear @Aturkistani,

I hope you’re doing well.

I am currently working on generating invoice XMLs in compliance with ZATCA’s requirements. Although my generated XMLs pass the basic XSD validations, I continue to receive the following business rule warning and hash errors:

  • Warning: BR-KSA-EN16931-11
    Invoice line net amount (BT-131) must equal (Invoiced quantity (BT-129) × Item net price (BT-146) / item price base quantity (BT-149)) + Sum of invoice line charge amount (BT-141) - Sum of invoice line allowance amount (BT-136)
  • Errors:
    • invalid-invoice-hash
    • invoiceHash_QRCODE_INVALID

I came across a sample signed invoice (example_invoice.xml) which passes all validations, including the hash and QR code checks. I am very confused about how such invoices are structured and how the hash and signature are correctly calculated.

Could you please guide me on the correct process to generate such an invoice, particularly:

  • How to compute the correct invoice hash and ensure it matches both the API and the QR code.
  • How the invoice line net amount is calculated to avoid the BR-KSA-EN16931-11 warning.
  • Any best practices or tools you recommend for creating valid XML that passes all ZATCA validations.
    {
    “validationResults”: {
    “infoMessages”: [
    {
    “type”: “INFO”,
    “code”: “XSD_ZATCA_VALID”,
    “category”: “XSD validation”,
    “message”: “Complied with UBL 2.1 standards in line with ZATCA specifications”,
    “status”: “PASS”
    }
    ],
    “warningMessages”: [
    {
    “type”: “WARNING”,
    “code”: “BR-KSA-EN16931-11”,
    “category”: “KSA”,
    “message”: “Invoice line net amount (BT-131) must equal (Invoiced quantity (BT-129) * (Item net price (BT-146) / item price base quantity (BT-149))) + Sum of invoice line charge amount (BT-141) - Sum of invoice line allowance amount (BT-136)”,
    “status”: “WARNING”
    }
    ],
    “errorMessages”: [
    {
    “type”: “ERROR”,
    “code”: “invalid-invoice-hash”,
    “category”: “INVOICE_HASHING_ERRORS”,
    “message”: “The invoice hash API body does not match the (calculated) Hash of the XML”,
    “status”: “ERROR”
    },
    {
    “type”: “ERROR”,
    “code”: “invoiceHash_QRCODE_INVALID”,
    “category”: “QRCODE_VALIDATION”,
    “message”: “Invoice xml hash does not match with qr code invoice xml hash”,
    “status”: “ERROR”
    }
    ],
    “status”: “ERROR”
    },
    “reportingStatus”: “NOT_REPORTED”,
    “clearanceStatus”: null,
    “qrSellertStatus”: null,
    “qrBuyertStatus”: null
    }
    i on post man i get this error can you please tell me each and detail steps about it