Developers Use cases

ZATCA Phase 2 integration through an API

How clearance and reporting work in ZATCA Phase 2, and how to meet them from your own software by issuing invoices through the WonderFatoora API.

Phase 2 in brief

Phase 1 (generation, from December 2021) required electronic invoices with a QR code. Phase 2 (integration) is rolled out to taxpayers in waves and connects invoicing software to ZATCA:

Invoice type Typical buyer ZATCA flow When
Standard tax invoice A VAT-registered business Clearance Before the invoice is given to the buyer
Simplified tax invoice A consumer Reporting Within 24 hours of issue

Credit and debit notes follow the type of the invoice they correct.

What WonderFatoora does

  • Links your company to ZATCA once, in the dashboard, with the one-time password from the Fatoora portal.
  • Decides the invoice type: a buyer with a valid Saudi VAT number, or an export, gives a standard invoice; no buyer, or a buyer without one, gives a simplified invoice, within the invoice types your company is set up for.
  • Submits and tracks every issued invoice, retries temporary failures, and shows ZATCA's own messages when an invoice is rejected.
  • Holds a standard invoice back from the buyer until it is cleared, so the buyer never receives an uncleared document.

What your integration does

  1. Create the invoice with POST /invoices and an external_reference.
  2. Read zatca in the response: deliverable says whether to send it now.
  3. If it is not deliverable yet, read the invoice again with a backoff until it is, or until its status is rejected.
  4. On rejected, show errors (ZATCA's messages) to whoever fixes the data in the dashboard.
curl https://fatoora.tw.sa/api/v1/invoices/1024 \
  -H "Authorization: Bearer wbk_test_xxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Accept: application/json"
<?php
$response = $client->get('invoices/1024', ['http_errors' => false]);
$invoice = json_decode((string) $response->getBody(), true)['data']['invoice'] ?? null;

if ($invoice && $invoice['zatca']['deliverable']) {
    // Safe to hand to the buyer: send $invoice['public_url'].
}
const res = await fetch("https://fatoora.tw.sa/api/v1/invoices/1024", {
  headers: {
    Authorization: `Bearer ${process.env.WONDERFATOORA_API_KEY}`,
    Accept: "application/json",
  },
});
const { ok, data, error } = await res.json();
if (ok && data.invoice.zatca.deliverable) {
  // Safe to hand to the buyer: data.invoice.public_url
}
res = requests.get(
    "https://fatoora.tw.sa/api/v1/invoices/1024",
    headers={"Authorization": f"Bearer {os.environ['WONDERFATOORA_API_KEY']}",
             "Accept": "application/json"},
    timeout=30,
)
invoice = res.json().get("data", {}).get("invoice")
if invoice and invoice["zatca"]["deliverable"]:
    print(invoice["public_url"])

Data your invoices need

  • Seller: your VAT number and national address, completed once in the company profile.
  • Standard invoices: the buyer's VAT number and full national address (street, 4-digit building number, district, city, 5-digit postal code). Create such buyers with POST /customers or in the dashboard, and send their id. See Customers.
  • Zero-rated or exempt lines: a ZATCA reason code in vat_exemption_code.
  • Foreign currency: an exchange rate to SAR, so VAT can be stated in SAR.
Phase 2 waves and dates are set by ZATCA. Check zatca.gov.sa for the dates that apply to your business.

Ready to build?

API access is part of the Business and Enterprise plans. Create a key in Settings → API keys and make your first call in minutes.