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

مكتبة بايثون مجانية ومفتوحة المصدر للربط مع هيئة الزكاة والضريبة والجمارك (منصة فاتورة)، المرحلة الثانية من الفوترة الإلكترونية: إنشاء الفاتورة وتوقيعها ورمز QR، والتخليص والإبلاغ، وفاتورة PDF/A-3 بالعربي والإنجليزي. تعمل داخل نظامك وتتصل بالهيئة مباشرة. التوثيق: 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.0

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.0
File Size Uploaded
zatca_tools_sdk-0.1.0.tar.gz 409.6 kB Details

Built distribution (wheel)

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

Total release size: 722.0 kB

Release files / zatca_tools_sdk-0.1.0.tar.gz

Download URL zatca_tools_sdk-0.1.0.tar.gz
Size 409.6 kB
Tags Source
SHA-256 checksum
How to use checksums
4a1ec9a3ea983a1fba8b11e5a12f333b73b92dc3fe9f56dbc4dc02fbb2a029b7
BLAKE2b-256 checksum
How to use checksums
34b3ad6019a4715d943cdaaa57199365512339dcb2f6ed52e449b2c43efa6028
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.0-py3-none-any.whl

Download URL zatca_tools_sdk-0.1.0-py3-none-any.whl
Size 312.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
7279981f3d8ffa320826a181ddb563f707bc3802e512f718993e7be1850bb7b5
BLAKE2b-256 checksum
How to use checksums
c15ca2ad0173a726d9395223820daebcd49c63f4398c806d8cde6ab69132b897
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

0.1.1

2 release files

This release

0.1.0 This release

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