المطورون

مرجع الواجهة البرمجية: الفواتير

مولَّد من مستند OpenAPI المنشور (الإصدار 1.4.0). https://fatoora.tw.sa/api/v1

GET /invoices

List invoices

الصلاحية المطلوبة invoices:read

Tax invoices only, newest first.

المعاملات

الحقل النوع الوصف
limit integer · query Page size.
cursor string · query meta.pagination.next_cursor of the previous page.
status array<string> · query One or more statuses (status[]=paid&status[]=partial, or comma-separated). overdue is worked out from the due date.
zatca_status array<string: pending, not_submitted, cleared, reported, rejected, retrying, unknown> · query One or more ZATCA statuses.
customer_id integer · query
issue_date_from string (date) · query
issue_date_to string (date) · query
updated_since string (date-time) · query
external_reference string · query
number string · query

الردود

  • 200 A page of invoices.
  • default An error. error.code says which.
POST /invoices

Create an invoice, as a draft or issued at once

الصلاحية المطلوبة invoices:draft

Issues the invoice unless issue is false; issuing also needs the invoices:issue scope. Counts against the plan's monthly invoice allowance. Sending your own external_reference (an order number) makes the call safe to retry: a repeat answers 200 with replayed: true and the invoice already made. A key without invoices:read is told only the invoice's id, number and status. Paid already, through your own payment gateway or till? Send payment and the payment is recorded in the same call, so the invoice arrives paid (or partial). It needs the payments:write scope and an issued invoice; amount defaults to the whole total. If the payment is refused, nothing is created.

المعاملات

الحقل النوع الوصف
Idempotency-Key string · header 8 to 255 visible ASCII characters, unique per operation you mean to perform.

محتوى الطلب application/json

الحقل النوع الوصف
issue_date مطلوب string (date)
due_date string | null (date)
issue boolean | null false creates a draft.
currency string | null Defaults to SAR.
exchange_rate number | null SAR per unit of currency; required for a foreign currency.
locale string | null: ar, en, null
notes string | null
terms string | null
external_reference string | null Your own id for the sale.
source_system string | null
document_discount_type string | null: amount, percent, null
document_discount_value number | null
payment object | null Paid already: recorded with the invoice, which then arrives paid (or partial). Needs payments:write; not with issue: false.
payment.amount number | null Defaults to the invoice total.
payment.method string | null cash (default), bank_transfer, mada, visa_mastercard, apple_pay, stc_pay, cheque, other, or a code the company added.
payment.reference string | null Your gateway transaction id, for example.
payment.paid_on string | null (date) Defaults to today; never later than today.
payment.notes string | null
payment.account_id integer | null The company cash or bank account the money went into.
customer object | null An existing customer by id, or a new one by its details.
customer.id integer | null
customer.name string | null
customer.vat_number string | null
customer.type string | null: individual, business, null Defaults to business with a VAT number, individual without. A Saudi business gets a standard invoice even without a VAT number.
customer.cr_number string | null Commercial registration; 10 digits for a Saudi buyer.
customer.email string | null
customer.phone string | null
customer.address_line1 string | null
customer.address_line2 string | null
customer.building_number string | null National address building number; 4 digits for a Saudi buyer.
customer.additional_number string | null National address additional number; 4 digits for a Saudi buyer.
customer.district string | null
customer.city string | null
customer.country string | null
customer.postal_code string | null
items مطلوب array<object>
items[].description مطلوب string
items[].quantity مطلوب number
items[].unit_price مطلوب number
items[].unit string | null
items[].discount number | null
items[].vat_rate number | null
items[].tax_rate_id integer | null
items[].product_id integer | null
items[].vat_exemption_code string | null
items[].vat_exemption_reason string | null

الردود

  • 201 The invoice was created.
  • 200 A repeat of an external_reference already invoiced.
  • default An error. error.code says which.
curl -X POST https://fatoora.tw.sa/api/v1/invoices \
  -H "Authorization: Bearer wbk_test_xxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
  "issue": false,
  "issue_date": "2026-11-03",
  "customer": {
    "name": "Example Trading Co.",
    "vat_number": "300000000000003",
    "address_line1": "King Fahd Rd",
    "city": "Riyadh",
    "postal_code": "12345",
    "country": "SA"
  },
  "items": [
    { "description": "Consulting", "quantity": 2, "unit_price": 500, "vat_rate": 15 }
  ]
}'
<?php
$response = $client->post('invoices', [
    'json' => [
        'issue'      => false,          // a draft: no legal number, nothing sent to ZATCA
        'issue_date' => '2026-11-03',
        'customer'   => [
            'name'          => 'Example Trading Co.',
            'vat_number'    => '300000000000003',
            'address_line1' => 'King Fahd Rd',
            'city'          => 'Riyadh',
            'postal_code'   => '12345',
            'country'       => 'SA',
        ],
        'items' => [
            ['description' => 'Consulting', 'quantity' => 2, 'unit_price' => 500, 'vat_rate' => 15],
        ],
    ],
    'http_errors' => false,
]);

$body = json_decode((string) $response->getBody(), true);
if ($body['ok']) {
    echo $body['data']['invoice']['number']; // DRAFT-… until it is issued
} else {
    echo $body['error']['code'];
}
const res = await fetch("https://fatoora.tw.sa/api/v1/invoices", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.WONDERFATOORA_API_KEY}`,
    "Content-Type": "application/json",
    Accept: "application/json",
  },
  body: JSON.stringify({
    issue: false, // a draft: no legal number, nothing sent to ZATCA
    issue_date: "2026-11-03",
    customer: {
      name: "Example Trading Co.",
      vat_number: "300000000000003",
      address_line1: "King Fahd Rd",
      city: "Riyadh",
      postal_code: "12345",
      country: "SA",
    },
    items: [{ description: "Consulting", quantity: 2, unit_price: 500, vat_rate: 15 }],
  }),
});

const body = await res.json();
if (!body.ok) throw new Error(`${body.error.code}: ${body.error.message}`);
console.log(body.data.invoice.id, body.data.invoice.number);
res = requests.post(
    "https://fatoora.tw.sa/api/v1/invoices",
    headers={
        "Authorization": f"Bearer {os.environ['WONDERFATOORA_API_KEY']}",
        "Accept": "application/json",
    },
    json={
        "issue": False,  # a draft: no legal number, nothing sent to ZATCA
        "issue_date": "2026-11-03",
        "customer": {
            "name": "Example Trading Co.",
            "vat_number": "300000000000003",
            "address_line1": "King Fahd Rd",
            "city": "Riyadh",
            "postal_code": "12345",
            "country": "SA",
        },
        "items": [
            {"description": "Consulting", "quantity": 2, "unit_price": 500, "vat_rate": 15}
        ],
    },
    timeout=30,
)
body = res.json()
print(res.status_code, body["data"]["invoice"]["number"] if body["ok"] else body["error"])
GET /invoices/{invoice}

Get an invoice

الصلاحية المطلوبة invoices:read

المعاملات

الحقل النوع الوصف
invoice مطلوب integer · path

الردود

  • 200 The invoice.
  • default An error. error.code says which.
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"])
GET /invoices/{invoice}/status

Where an invoice stands

الصلاحية المطلوبة invoices:read

Its status, payments and ZATCA status, without its lines. Made for polling.

المعاملات

الحقل النوع الوصف
invoice مطلوب integer · path

الردود

  • 200 The status.
  • default An error. error.code says which.
POST /invoices/{invoice}/validate

Check whether a draft can be issued

الصلاحية المطلوبة invoices:draft

Runs every check issuing runs, and changes nothing.

المعاملات

الحقل النوع الوصف
invoice مطلوب integer · path

الردود

  • 200 Whether it can be issued, and what is missing.
  • default An error. error.code says which.
POST /invoices/{invoice}/issue

Issue a draft

الصلاحية المطلوبة invoices:issue

Gives the draft its tax-invoice number and QR and, for a company linked to ZATCA, submits it. Irreversible: an issued invoice is corrected with a credit or debit note. An invoice already issued answers 200 with already_issued: true.

المعاملات

الحقل النوع الوصف
invoice مطلوب integer · path
Idempotency-Key string · header 8 to 255 visible ASCII characters, unique per operation you mean to perform.

الردود

  • 200 The issued invoice.
  • default An error. error.code says which.
GET /invoices/{invoice}/pdf

Download the invoice PDF

الصلاحية المطلوبة invoices:download

A standard invoice ZATCA has not cleared yet prints without a QR and is marked as not yet valid.

المعاملات

الحقل النوع الوصف
invoice مطلوب integer · path

الردود

  • 200 The PDF.
  • default An error. error.code says which.
GET /invoices/{invoice}/xml

Download the legal XML

الصلاحية المطلوبة invoices:download

The document ZATCA holds: the cleared XML of a standard invoice, the signed XML of a simplified one. document_not_available (409) until there is one; xml_not_applicable (404) for a company not linked to ZATCA.

المعاملات

الحقل النوع الوصف
invoice مطلوب integer · path

الردود

  • 200 The XML.
  • default An error. error.code says which.
GET /invoices/{invoice}/payments

Customer payments of an invoice

الصلاحية المطلوبة invoices:read

المعاملات

الحقل النوع الوصف
invoice مطلوب integer · path

الردود

  • 200 The payments, oldest first, and the invoice balance.
  • default An error. error.code says which.
POST /invoices/{invoice}/payments

Record a customer payment on an issued invoice

الصلاحية المطلوبة payments:write

For money received after the invoice was made (a bank transfer, a late confirmation from your gateway). Never more than the balance still owed (payment_exceeds_balance), never on a draft, cancelled or refunded invoice (invoice_not_payable). Paid before the invoice was made? Send payment with POST /invoices instead.

المعاملات

الحقل النوع الوصف
invoice مطلوب integer · path
Idempotency-Key string · header 8 to 255 visible ASCII characters, unique per operation you mean to perform.

محتوى الطلب application/json

الحقل النوع الوصف
amount مطلوب number In the invoice currency; at most the balance.
method string | null cash (default), bank_transfer, mada, visa_mastercard, apple_pay, stc_pay, cheque, other, or a code the company added.
reference string | null
paid_on string | null (date) Defaults to today; never later than today.
notes string | null
account_id integer | null The company cash or bank account the money went into.

الردود

  • 201 The payment and the invoice new balance.
  • default An error. error.code says which.

العودة إلى مرجع الواجهة البرمجية

جاهز للبدء؟

الوصول إلى الواجهة البرمجية ضمن باقات: الأعمال والمؤسسات. أنشئ مفتاحًا من الإعدادات ← مفاتيح API وأرسل أول طلب خلال دقائق.