Python SDK · version 0.1

ZATCA integration, simplified.

Create an invoice, send it to ZATCA, read the answer. An open-source Python library that runs inside your application and talks to ZATCA directly — no account with us, no server of ours in between.

  • Open source (MIT)
  • Free to use
  • Direct to ZATCA
  • No ZATCA Tools account
  • Your infrastructure, your data
quickstart.py
from zatca_tools import Zatca

zatca = Zatca("sandbox")
zatca.onboard()  # the sandbox's test credentials, straight from ZATCA — a few seconds

invoice = zatca.create_invoice({
    "number": "INV-1001",
    "type": "simplified",
    "items": [
        {"name": "Product", "quantity": 2, "unit_price": 100},
    ],
})

result = zatca.submit(invoice)

if result.success:
    print("ZATCA says:", result.status)  # REPORTED
    invoice.save_xml("INV-1001.xml")
    invoice.save_pdf("INV-1001.pdf")
else:
    print(result.error.message)
    print(result.error.help_url)

Runs as it is against ZATCA's public sandbox: ZATCA says: REPORTED

Start here · 1 of 3

Install

Python 3.10 or later. One package: invoices, ZATCA, and printed PDFs.

The package is on PyPI; the source is on GitHub.

Terminal
pip install zatca-tools-sdk

Your first invoice

  1. 1. Create a client. Zatca("sandbox") works against ZATCA's public test environment.
  2. 2. Get test credentials. onboard() fetches them from ZATCA's sandbox in a few seconds. There is nothing for you to provide.
  3. 3. Create the invoice. create_invoice() checks it, computes VAT and totals, and signs it — on your machine. Nothing is sent yet.
  4. 4. Send it. submit() sends it to ZATCA and returns ZATCA's answer.
Sending real invoices needs your own certificate from ZATCA instead of the sandbox's. It is one call with a one-time password from the Fatoora portal: Connect to ZATCA.
quickstart.py
from zatca_tools import Zatca

zatca = Zatca("sandbox")
zatca.onboard()  # the sandbox's test credentials, straight from ZATCA — a few seconds

invoice = zatca.create_invoice({
    "number": "INV-1001",
    "type": "simplified",
    "items": [
        {"name": "Product", "quantity": 2, "unit_price": 100},
    ],
})

result = zatca.submit(invoice)

if result.success:
    print("ZATCA says:", result.status)  # REPORTED
    invoice.save_xml("INV-1001.xml")
    invoice.save_pdf("INV-1001.pdf")
else:
    print(result.error.message)
    print(result.error.help_url)
Output
ZATCA says: REPORTED

Reading the result

Three questions, three fields. Did it work? result.success. If not, why? result.error.message. How do I fix it? result.error.help_url — a page that explains the error, on the ZATCA Tools error reference or in this documentation.

success is true only when ZATCA itself reported or cleared the invoice. A dropped connection, a refused certificate and a rejection are all success == False, and status says which — see what to do for each.

result
result.success          # True only when ZATCA reported or cleared the invoice
result.status           # REPORTED · CLEARED · NOT_REPORTED · NOT_CLEARED · NOT_SENT · UNKNOWN · FAILED
result.error.code       # what went wrong: ZATCA's code (BR-KSA-63) or the SDK's own (network_error)
result.error.message    # why, in one sentence
result.error.help_url   # how to fix it: a page on zatcatools.com, built offline
result.warnings         # accepted, but worth fixing — each with its own help_url

Saving the invoice

Keep the XML: it is the e-invoice. The PDF is PDF/A-3 with that XML embedded inside, so the copy a person reads and the copy a system reads travel as one file. Brand it with your logo, colour and footer — printed invoices.

save
invoice.save_xml("INV-1001.xml")   # the signed e-invoice
invoice.save_pdf("INV-1001.pdf")   # PDF/A-3, the XML embedded, ready to hand over

# A standard (B2B) invoice is shared once ZATCA has cleared it — print the result:
result.save_pdf("INV-2001.pdf")    # carries ZATCA's cleared copy

Next steps

How it works

The SDK is a library inside your process, not a service in between. The first two steps run on your servers; only the last arrow leaves them, and it goes to ZATCA.

1
Your application

ERP, POS, store or SaaS — passes a plain dict.

2 · zatca-tools-sdklocal
On your servers
Validate Compute VAT UBL XML Sign (XAdES) Invoice hash QR code PDF/A-3
3 · gw-fatoora.zatca.gov.sa
ZATCA

Reports or clears it, and answers — returned to you as a result.

ZATCA Tools is nowhere on this path: no proxy, no account, no telemetry.

What it does today

Three calls

onboard() once, create_invoice() locally, submit() to ZATCA. The certificate steps, the invoice chain and the choice between reporting and clearance happen inside.

Sandbox in one line

onboard() in the sandbox gets ZATCA's test credentials by itself: a first invoice in under a minute, with nothing to set up.

Clear results

success, status, and an error with a code, a sentence and a help link. Local problems, connection problems and ZATCA's answers are never mixed up.

Signed XML, hash and QR

UBL 2.1 invoices, credit and debit notes, with the XAdES signature, the invoice hash and the QR code ZATCA checks.

Reporting and clearance

Simplified invoices reported, standard ones cleared — with ZATCA's stamped copy returned to you.

Printed invoices

PDF/A-3 with the XML embedded, Arabic and English, your logo and colour. veraPDF passes it as PDF/A-3b.

VAT done right

Standard, zero-rated, exempt and out-of-scope items with their reasons, prices with or without VAT, discounts, rounding the way ZATCA checks it.

Every problem at once

An invoice that cannot be valid is refused before anything is sent, with every field that needs fixing.

Open source, local

MIT licence. Runs in your process; the only network calls go to ZATCA.

Questions developers ask

Is the SDK free?

Yes. It is open source under the MIT licence: free to use, including in commercial products, with no account, no key and no usage limit of ours. ZATCA itself charges nothing for its API.

Do I need a ZATCA Tools account?

No. The SDK talks to ZATCA directly with the certificate ZATCA issues to you. ZATCA Tools is not in the path and never sees your requests.

Does my invoice data pass through your servers?

No. Invoices are built, signed and hashed inside your application and sent from your servers straight to gw-fatoora.zatca.gov.sa. The SDK makes no request to any other host, sends no telemetry and writes no logs. Even the help links on errors are built offline, and carry nothing but the error code.

Do I have to understand CSRs and CSIDs?

No. In the sandbox, zatca.onboard() needs nothing at all. For your own company it needs one thing only you can provide: a one-time password from the Fatoora portal. The key, the CSR, the compliance checks and the certificates are handled inside that call. Connect to ZATCA has the details.

Does it support Phase 2 (integration)?

Yes: onboarding, signed UBL 2.1 invoices, credit and debit notes with the XAdES signature, invoice hash and QR code, reporting of simplified invoices and clearance of standard ones. It has been run end to end against ZATCA's sandbox.

Can it print the invoice?

Yes. save_pdf() writes a PDF/A-3 file with the signed XML embedded in it, in Arabic and English, with your logo, colour and footer. veraPDF, the reference PDF/A checker, passes it as PDF/A-3b.

Can I use it in an ERP or a POS?

Yes — that is what it is for. Each till or server that issues invoices is a unit with its own certificate and its own invoice chain; one client per unit.

Can I use it in production?

The SDK is new (version 0.1). Its arithmetic and XML match the ZATCA Tools platform's, which signs production invoices today, and it passes ZATCA's sandbox end to end. Run it in simulation with your own VAT number before you switch production traffic to it.

How is it different from ZATCA Tools?

The SDK is a library: you build your own integration and keep everything in your infrastructure. ZATCA Tools is the hosted product around the same engine — dashboard, invoice history, Shopify and WooCommerce integrations, a REST API — for teams that would rather not run their own.

How do I report a problem?

Open an issue on GitHub, or write to [email protected], with the SDK version and, if you can, the failing invoice with personal data removed. Security issues privately to [email protected].

Open source

The SDK is published under the MIT licence: use it, change it and ship it in commercial products, keeping the copyright notice. You can read every line that touches your data — and check for yourself that nothing leaves for anywhere but ZATCA.

Issues and pull requests are welcome. Questions: [email protected].

SDK or platform?

ZATCA Tools SDKZATCA Tools platform
What it isA library in your codeA hosted product
Where it runsYour serversOur servers
AccountNoneRequired
PriceFree (MIT)Subscription
Onboarding, signing, reporting, clearanceYesYes
Printed invoices (PDF/A-3)YesYes
Storage of invoices and the chainYours to buildIncluded
Dashboard, invoice history—Included
Shopify, WooCommerce, REST API—Included

Building your own integration? The SDK. Would rather not run one? ZATCA Tools.