Skip to main content

ZATCA Tools SDK

tests PyPI Python License: MIT

ZATCA e-invoicing for Saudi Arabia, in Python — Fatoora Phase 2 from your own application. Create an invoice, send it to ZATCA, read the answer, and print it as PDF/A-3. By ZATCA Tools.

Free and open source (MIT). Runs inside your application and talks to ZATCA directly: no ZATCA Tools account, no server of ours in between.

Documentation: Start here · Connect to ZATCA · Advanced · ZATCA error reference

A free, open-source Python library for connecting to the Zakat, Tax and Customs Authority (ZATCA) through its Fatoora platform — Phase 2 of Saudi e-invoicing: create and sign invoices with their QR code, clear and report them, and print PDF/A-3 invoices in Arabic and English. It runs inside your system and connects to ZATCA directly. Documentation: zatcatools.com/docs/sdk

Install

Python 3.10+.

pip install zatca-tools-sdk

Your first invoice

Against ZATCA's public sandbox, with nothing to set up:

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)
  • create_invoice() checks the data, computes VAT and totals, builds and signs the XML, and makes the QR code — on your machine. Nothing is sent.
  • submit() sends it to ZATCA: reporting for a simplified invoice, clearance for a standard one. It never raises for the outcome; read the result.

Reading the result

result.success True only when ZATCA reported or cleared the invoice
result.status REPORTED · CLEARED · NOT_REPORTED · NOT_CLEARED (rejected) · NOT_SENT (no connection) · UNKNOWN (no answer: send the same invoice again) · FAILED (ZATCA refused the request, not the invoice)
result.error.code ZATCA's code (BR-KSA-63) or the SDK's own (network_error)
result.error.message why, in one sentence
result.error.help_url the page that explains how to fix it

Help links point into the ZATCA error reference and this SDK's documentation. They are built offline from a list of codes shipped with the SDK, and carry the code and nothing else.

Your own certificate

The sandbox lends everyone a test certificate. To send real invoices, your system needs its own — one call, with a one-time password (OTP) that only the taxpayer can generate on the Fatoora portal:

zatca = Zatca("production", seller={
    "vat_number": "310000000000003",
    "name": "My Company LLC",
    "cr_number": "1010010000",
    "address": {"street": "King Fahd Road", "building_number": "1234", "district": "Al Olaya", "city": "Riyadh", "postal_code": "12345"},
})
credentials = zatca.onboard(otp="123456")

Keep credentials.export() as a secret, and save zatca.chain.to_dict() after every invoice; pass both back on the next start:

zatca = Zatca("production", seller=SELLER, credentials=saved_credentials, chain=saved_chain)

Everything else — environments, what to do with each status, renewal — is in Connect to ZATCA. Run examples/connect.py to see the whole lifecycle.

Printed invoices

save_pdf() writes PDF/A-3 with the signed XML embedded, Arabic and English, validated by veraPDF as PDF/A-3b. Brand it:

zatca = Zatca("sandbox", design={"logo": "logo.png", "accent": "#0F766E", "footer": "Thank you for your business."})

A standard invoice is printed from its result once ZATCA has cleared it (result.save_pdf(...)), so the PDF carries ZATCA's cleared copy.

Your data stays with you

  • create_invoice() and save_pdf() make no network call.
  • Network calls go only to ZATCA (gw-fatoora.zatca.gov.sa): onboard(), renew(), submit() and the advanced calls behind them.
  • Nothing goes to ZATCA Tools — no telemetry, no analytics, no logs.
  • The private key is created on your machine and never sent.

Tests

pip install -e ".[dev]"
pytest                                             # offline
ZATCA_SDK_SANDBOX=1 pytest tests/test_sandbox.py   # live, against ZATCA's public sandbox
ZATCA_SDK_VERAPDF=/path/to/verapdf pytest tests/test_pdf.py -k verapdf

The offline suite compares the SDK, invoice by invoice, with the pipeline the ZATCA Tools platform signs production invoices with — same totals, XML, hash and QR for 17 scenarios, the same settlement for 500 random baskets — and checks every code snippet in the documentation against the real API.

Contributing and security

Issues and pull requests are welcome — see CONTRIBUTING.md. Report vulnerabilities privately: SECURITY.md.

Prefer not to run your own integration? ZATCA Tools is the hosted platform built on the same engine: dashboard, Shopify and WooCommerce integrations, and a REST API.

Licence

MIT — see LICENSE and NOTICE (including the bundled IBM Plex Sans Arabic font, SIL Open Font License, and the ZATCA Tools mark). Independent project; not affiliated with or endorsed by the Zakat, Tax and Customs Authority.

Metadata

Release files for zatca-tools-sdk 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for zatca-tools-sdk 0.1.1
File Size Uploaded
zatca_tools_sdk-0.1.1.tar.gz 409.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for zatca-tools-sdk 0.1.1
File Interpreter ABI Platform
zatca_tools_sdk-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 721.6 kB

Release files / zatca_tools_sdk-0.1.1.tar.gz

Download URL zatca_tools_sdk-0.1.1.tar.gz
Size 409.4 kB
Tags Source
SHA-256 checksum
How to use checksums
895362ef55ca20d2dbe9c89829dc1187ef40cee6798edbbe8fa14aaabbd5a856
BLAKE2b-256 checksum
How to use checksums
5dff87f35505c9e2e253c97ac2acd79ac9c90cceb14b1ac1bfd2b24809a4c481
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 3, 2026.

Transparency log

Release files / zatca_tools_sdk-0.1.1-py3-none-any.whl

Download URL zatca_tools_sdk-0.1.1-py3-none-any.whl
Size 312.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2ff80ebf27e7adb4b060ae6f5dd38bc8022aa424e26e714a324cec05daf5a7af
BLAKE2b-256 checksum
How to use checksums
f1001c2e3fd1531b13303b2d7ce87f7c72c368e3d6f2f679b2e4b13ceeb033fe
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 3, 2026.

Transparency log

Release history Release notifications | RSS feed

0.1.3

2 release files

0.1.2

2 release files

This release

0.1.1 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page