ZATCA Phase 2 integration: requirements, sandbox and a step-by-step guide

This guide takes you from the first ZATCA sandbox call to the first legal invoice in production, following the exact flow Matheel's engine runs against ZATCA's gateways.

What is ZATCA Phase 2?

ZATCA Phase 2 (the Integration Phase) requires a Saudi taxpayer's e-invoicing system to send every e-invoice to ZATCA's Fatoora platform. Standard (B2B) tax invoices are cleared by ZATCA before they reach the buyer; simplified (B2C) invoices are reported within 24 hours. Phase 1 (Generation) started on 4 December 2021; Phase 2 started on 1 January 2023 and applies to taxpayers in waves that ZATCA announces. Check whether your business is in wave 25.

ZATCA Phase 2 requirements

Matheel does all of this in one request. The steps below are the path from zero to production.

  1. Know the three environments

    ZATCA runs three gateways, each with its own CSID; a certificate from one does not work in another:

    • Developer portal (sandbox): for testing. It accepts a published test OTP. Free on Matheel.
    • Simulation (simulation): the taxpayer's real details and an OTP from their account, no legal effect.
    • Production (production): legal invoices; needs a device plan.
  2. File a ZATCA sandbox invoice without a CSID

    See a real answer before onboarding anything: send "environment": "sandbox" with no seller and no csid, and Matheel files it on the developer portal as a shared test taxpayer. Or press the button on the home page.

    curl https://matheel.app/api/v1/invoices -H "Authorization: Bearer $MATHEEL_KEY" \
      -H "Content-Type: application/json" \
      -d '{"environment":"sandbox","invoice":{"type":"simplified","counter":1,"uuid":"…","number":"INV-1",
           "line_items":[{"name":"Coffee","quantity":2,"price":"50.00"}],
           "subtotal":"100.00","vat_amount":"15.00","total":"115.00"}}'
  3. Prepare the taxpayer's details

    Most onboarding rejections come from seller data. Get it right once:

    • VAT number: 15 digits, starting and ending with 3.
    • Legal name in Arabic and the commercial registration number (CRN).
    • The full national address: street, building number (4 digits), district, city, postal code (5 digits). A missing address gives BR-KSA-09 and BR-KSA-37.
  4. Get an OTP from the Fatoora portal

    For simulation and production, the taxpayer logs in to fatoora.zatca.gov.sa, chooses to onboard a new solution unit, and copies the OTP. It expires quickly, so use it right away. The developer portal needs no OTP: Matheel uses the test value.

    The CSID is issued in the taxpayer's own name, so you cannot get one for a customer without the OTP from their account. Plan this step with your first customer early.

  5. Onboard the device (CSID) in one call

    By hand it is four steps: a CSR with a secp256k1 key, a compliance CSID in exchange for the OTP, six compliance checks (invoice, credit note and debit note, standard and simplified), then the production CSID. On Matheel it is one request:

    curl https://matheel.app/api/v1/onboarding -H "Authorization: Bearer $MATHEEL_KEY" \
      -H "Content-Type: application/json" \
      -d '{"environment":"simulation","otp":"123456","seller":{"vat_number":"3…3","legal_name_ar":"…","crn":"…",
           "address":{"street":"…","building_number":"1234","district":"…","city":"Riyadh","postal_code":"12211"}}}'

    You get back a csid with private_key, binary_security_token and secret. Store them safely: Matheel keeps none of it, and you send them with every invoice.

  6. Keep the invoice chain per device

    Each device (EGS) has a chain: a counter (ICV) that goes up by one per invoice, and the hash of the last accepted invoice (PIH) sent with the next one.

    • Advance the counter and store the hash only after a 200.
    • A rejected invoice does not consume a number: fix it and resend with the same counter, or you get BR-KSA-16.
    • Resending the same uuid is billed once.
  7. File invoices and archive the XML

    Each invoice goes to POST /api/v1/invoices with seller and csid. The response carries:

    • invoice_xml: the stamped legal document. Archive it.
    • qr: print it on the invoice.
    • invoice_hash: for the next invoice.
    • warnings and errors: ZATCA's own text. A warning does not block acceptance; an error returns 422.

Clearance vs reporting

Standard (B2B, standard): needs the buyer's VAT number and address, and is cleared: ZATCA stamps it before it reaches the buyer. Simplified (B2C, simplified): needs no buyer details and is reported within 24 hours of issue. Matheel picks the path from type.

Start at step two, right now

A real invoice on ZATCA's developer portal, no certificate and no key.

Try an invoice or read the API reference →