Saudi Arabia: request and response examples

Send Saudi standard, simplified and export invoices in GETS and read each response up to ZATCA's result. Start with a sandbox API key and a Saudi company's onboarded source.

Save the request

Save this body as saudi-invoice.json. It is a standard tax invoice from one VAT-registered business to another, with one line at the 15% standard rate. ZATCA clears a standard invoice; see clearance and reporting.

saudi-invoice.jsonjson
{
  "country": "SA",
  "environment": "sandbox",
  "purpose": "invoicing",
  "source": "acme-erp:1.0.0",
  "documentType": { "base": "tax_invoice", "modifiers": [] },
  "payload": {
    "header": {
      "documentType": { "base": "tax_invoice" },
      "documentNumber": "SA-2026-00309",
      "uuid": "3f6c2a9e-8b41-4d7a-9c25-6e1f0b7d4a83",
      "issueDate": "2026-09-30",
      "issueTime": "10:15:00",
      "currency": "SAR",
      "taxCurrency": "SAR"
    },
    "parties": {
      "seller": {
        "name": "Najd Supplies Co.",
        "address": {
          "addressLine1": "King Fahd Road",
          "city": "Riyadh",
          "postalCode": "12345",
          "country": "SA",
          "additionalAddressData": {
            "buildingNumber": "1234",
            "district": "Al Olaya"
          }
        },
        "taxIds": [{ "type": "VAT", "value": "310123456700003" }],
        "registrationNumbers": [{ "type": "CRN", "value": "1010123456" }]
      },
      "buyer": {
        "name": "Riyadh Foods LLC",
        "address": {
          "addressLine1": "Prince Sultan Street",
          "city": "Jeddah",
          "postalCode": "23456",
          "country": "SA",
          "additionalAddressData": {
            "buildingNumber": "4321",
            "district": "Al Rawdah"
          }
        },
        "taxIds": [{ "type": "VAT", "value": "300987654300003" }],
        "registrationNumbers": [{ "type": "CRN", "value": "4030123456" }]
      },
      "delivery": { "deliveries": [{ "actualDeliveryDate": "2026-09-30" }] }
    },
    "lineItems": [
      {
        "id": "1",
        "name": "Office chairs",
        "quantity": 20,
        "unitCode": "PCE",
        "price": { "amount": 250 },
        "lineTaxableValue": 5000,
        "taxCategory": "S",
        "taxRate": 15,
        "taxAmount": 750,
        "lineTotal": 5000,
        "extensions": { "sa_lineRoundingAmount": 5750 }
      }
    ],
    "taxTotals": [
      {
        "taxAmount": 750,
        "taxSubtotals": [
          {
            "taxableAmount": 5000,
            "taxAmount": 750,
            "taxCategory": "S",
            "percent": 15
          }
        ]
      }
    ],
    "totals": {
      "totalLineTaxableAmount": 5000,
      "totalAmountExcludingTax": 5000,
      "totalTaxAmount": 750,
      "totalAmountIncludingTax": 5750,
      "amountDue": 5750
    },
    "extensions": { "sa_icv": "27" }
  }
}

Replace source with the Saudi company’s own name:version, and use an unused documentNumber. Keep environment: "sandbox" with a sandbox key. These values are specific to Saudi Arabia:

  • Document type. The envelope’s documentType decides which rules apply and which ZATCA invoice type is produced. Complyance copies it into payload.header.documentType, replacing any value there, so the two never disagree. An ordinary B2B invoice takes no modifier, so modifiers stays empty.
  • Invoice identity. header.uuid is the invoice’s unique identifier (ZATCA field KSA-1); use a new UUID for every invoice. extensions.sa_icv is the invoice counter value (KSA-16), digits only (BR-KSA-33, BR-KSA-34): the number of the invoice in the sequence your system issues.
  • Issue time. issueTime is hh:mm:ss in Saudi local time, such as 10:15:00, or hh:mm:ssZ in UTC, such as 07:15:00Z (ZATCA rule BR-KSA-70).
  • Currencies. Set taxCurrency to SAR, even when currency is another currency.
  • VAT numbers. A Saudi VAT number has 15 digits and starts and ends with 3 (ZATCA rules BR-KSA-40 and BR-KSA-44). The seller also needs one registration number, such as a CRN (commercial registration number).
  • Addresses. A Saudi address needs a street (addressLine1), a four-digit buildingNumber, a five-digit postalCode, the city, the district and the country.
  • Supply date. parties.delivery.deliveries[].actualDeliveryDate is the date the goods or services were supplied.
  • Line amounts. lineTotal is the line amount before VAT (BT-131). sa_lineRoundingAmount is the line amount including VAT (KSA-12). A standard-rated line uses tax category S; ZATCA rule BR-KSA-84 accepts only 15 or 5 as its rate.
  • What you leave out. Do not send sa_pih, sa_qrCode or sa_digitalSignature. Complyance adds the previous invoice hash, signs the invoice with the company’s cryptographic stamp and adds the QR code; see what is added for you.

The field reference lists the fields for every document type.

Send the request

Sandbox and production use the same host, https://prod.gets.complyance.io. The "environment": "sandbox" field in the request body is what sends this invoice to sandbox.

Submit a Saudi invoice in sandboxbash
curl --request POST 'https://prod.gets.complyance.io/api/v3/unify' \
  --header "Authorization: Bearer ${COMPLYANCE_API_KEY}" \
  --header 'Content-Type: application/json' \
  --header 'Accept: application/json' \
  --header 'new-api: true' \
  --data @saudi-invoice.json

Read the response

HTTP 200 means the invoice passed validation and was stored. This illustrative response includes a short Base64-encoded XML fragment to show the shape; the actual Base64XML contains the generated invoice, not this fragment.

Validated invoice — HTTP 200json
{
  "documentId": "01K6EXAMPLE00000000000309",
  "documentNumber": "SA-2026-00309",
  "message": "Your invoice was validated and is ready for submission.",
  "Base64XML": "PEludm9pY2U+PElEPlNBLTIwMjYtMDAzMDk8L0lEPjwvSW52b2ljZT4="
}

If the request returns HTTP 422, inspect every entry in errors. This sample shows the response for a request sent without the buyer’s building number. BR-KSA-* codes are ZATCA’s published rule identifiers; the messages in your response can differ.

Incomplete buyer address — HTTP 422json
{
  "documentId": "01K6EXAMPLE00000000000310",
  "documentNumber": "SA-2026-00309",
  "message": "Your invoice could not be validated. Review the errors and try again.",
  "validationStage": "gets",
  "errors": [
    {
      "code": "BR-KSA-63",
      "getsPath": "parties.buyer.address",
      "payloadPath": "parties.buyer.address",
      "message": "If buyer country code is SA, buyer address must contain street, building number, postal code, city, district, and country code.",
      "severity": "error",
      "ruleSet": "sa:tax_invoice"
    }
  ]
}

Correct the field named by getsPath, then send the request again. The Saudi Arabia validation rules list every rule. For 404, confirm your source name and version; for 403, check that the key’s environment matches environment. See Unify errors for other statuses.

Check ZATCA’s result

A 200 is not ZATCA’s answer. Follow the document by documentId, as described in Submit and retrieve, until isTerminal is true. This response is shortened: artifacts and the rest of ZATCA’s answer in government are left out.

Cleared by ZATCA — HTTP 200json
{
  "success": true,
  "data": {
    "documentId": "01K6EXAMPLE00000000000309",
    "documentNumber": "SA-2026-00309",
    "country": "SA",
    "environment": "sandbox",
    "state": "final_valid",
    "isTerminal": true,
    "lastUpdatedAt": "2026-09-30T07:15:09.000Z",
    "errors": [],
    "government": { "status": "CLEARED" },
    "validationResults": {
      "status": "Valid",
      "validationSteps": [
        { "name": "Validation Passed", "status": "Valid", "error": null },
        { "name": "Queue Admitted", "status": "Valid", "error": null },
        {
          "name": "Delivery Processing Started",
          "status": "Valid",
          "error": null
        },
        { "name": "Final Valid", "status": "Valid", "error": null }
      ]
    }
  }
}

state final_valid with government.status CLEARED means ZATCA cleared the standard invoice. WARNED means ZATCA accepted it with warnings, which government lists. REJECTED, with state final_invalid, means ZATCA refused it; read its reasons in government, then correct the invoice and send it as a new document.

Other document types

Each request below is complete and passes Unify’s validation as written. Send it the same way and follow it to its final status.

Simplified invoice (B2C)

A simplified tax invoice is a sale to a consumer. ZATCA does not clear it: Complyance reports it to ZATCA after you send it. ZATCA rule BR-KSA-98 asks for the report within 24 hours of the issue date and time, so send each simplified invoice as soon as you issue it.

saudi-simplified-invoice.jsonjson
{
  "country": "SA",
  "environment": "sandbox",
  "purpose": "invoicing",
  "source": "acme-erp:1.0.0",
  "documentType": { "base": "simplified_invoice", "modifiers": [] },
  "payload": {
    "header": {
      "documentType": { "base": "simplified_invoice" },
      "documentNumber": "SA-2026-S-01187",
      "uuid": "8d1f6c3a-2b7e-4f95-a0c4-5e9b3d72f1a6",
      "issueDate": "2026-09-30",
      "issueTime": "16:42:10",
      "currency": "SAR",
      "taxCurrency": "SAR"
    },
    "parties": {
      "seller": {
        "name": "Najd Supplies Co.",
        "address": {
          "addressLine1": "King Fahd Road",
          "city": "Riyadh",
          "postalCode": "12345",
          "country": "SA",
          "additionalAddressData": {
            "buildingNumber": "1234",
            "district": "Al Olaya"
          }
        },
        "taxIds": [{ "type": "VAT", "value": "310123456700003" }],
        "registrationNumbers": [{ "type": "CRN", "value": "1010123456" }]
      },
      "buyer": {
        "name": "Retail customer",
        "registrationNumbers": [{ "type": "OTH", "value": "CUST-55021" }]
      }
    },
    "lineItems": [
      {
        "id": "1",
        "name": "Desk lamp",
        "quantity": 2,
        "unitCode": "PCE",
        "price": { "amount": 120 },
        "lineTaxableValue": 240,
        "taxCategory": "S",
        "taxRate": 15,
        "taxAmount": 36,
        "lineTotal": 240,
        "extensions": { "sa_lineRoundingAmount": 276 }
      }
    ],
    "taxTotals": [
      {
        "taxAmount": 36,
        "taxSubtotals": [
          {
            "taxableAmount": 240,
            "taxAmount": 36,
            "taxCategory": "S",
            "percent": 15
          }
        ]
      }
    ],
    "totals": {
      "totalLineTaxableAmount": 240,
      "totalAmountExcludingTax": 240,
      "totalTaxAmount": 36,
      "totalAmountIncludingTax": 276,
      "amountDue": 276
    },
    "extensions": { "sa_icv": "1187" }
  }
}
  • documentType.base is simplified_invoice.
  • The buyer needs no VAT number, but Unify asks for a buyer identifier (BR-KSA-14). Send the customer’s identifier in registrationNumbers with one of the schemes the rule lists, such as OTH.
  • Unify’s response can carry warnings for the QR code (BR-KSA-27) and the cryptographic stamp (BR-KSA-60). Complyance adds both before the invoice reaches ZATCA, so you do not need to act on them.

When ZATCA has received the report, the document’s government.status is REPORTED and state is final_valid.

Export invoice

An export invoice is a zero-rated sale to a buyer outside Saudi Arabia. Add the export modifier, use tax category Z at 0, and give the exemption reason code and text in the tax breakdown. The buyer has no Saudi VAT number, so send another buyer identifier (BR-KSA-81). An export invoice also needs header.exchangeRate; when the invoice is in SAR, the rate is 1.

saudi-export-invoice.jsonjson
{
  "country": "SA",
  "environment": "sandbox",
  "purpose": "invoicing",
  "source": "acme-erp:1.0.0",
  "documentType": { "base": "tax_invoice", "modifiers": ["export"] },
  "payload": {
    "header": {
      "documentType": { "base": "tax_invoice", "modifiers": ["export"] },
      "documentNumber": "SA-2026-E-00072",
      "uuid": "5b9e0d47-1c6a-4e2f-8b3d-7a4c9f12e608",
      "issueDate": "2026-09-30",
      "issueTime": "10:15:00",
      "currency": "SAR",
      "taxCurrency": "SAR",
      "exchangeRate": { "rate": 1, "sourceCurrency": "SAR", "targetCurrency": "SAR" }
    },
    "parties": {
      "seller": {
        "name": "Najd Supplies Co.",
        "address": {
          "addressLine1": "King Fahd Road",
          "city": "Riyadh",
          "postalCode": "12345",
          "country": "SA",
          "additionalAddressData": {
            "buildingNumber": "1234",
            "district": "Al Olaya"
          }
        },
        "taxIds": [{ "type": "VAT", "value": "310123456700003" }],
        "registrationNumbers": [{ "type": "CRN", "value": "1010123456" }]
      },
      "buyer": {
        "name": "Gulf Retail FZE",
        "address": {
          "addressLine1": "Sheikh Zayed Road",
          "city": "Dubai",
          "postalCode": "00000",
          "country": "AE"
        },
        "registrationNumbers": [{ "type": "OTH", "value": "DXB-CL-884213" }]
      },
      "delivery": { "deliveries": [{ "actualDeliveryDate": "2026-09-30" }] }
    },
    "lineItems": [
      {
        "id": "1",
        "name": "Office chairs",
        "quantity": 20,
        "unitCode": "PCE",
        "price": { "amount": 250 },
        "lineTaxableValue": 5000,
        "taxCategory": "Z",
        "taxRate": 0,
        "taxAmount": 0,
        "lineTotal": 5000,
        "extensions": { "sa_lineRoundingAmount": 5000 }
      }
    ],
    "taxTotals": [
      {
        "taxAmount": 0,
        "taxSubtotals": [
          {
            "taxableAmount": 5000,
            "taxAmount": 0,
            "taxCategory": "Z",
            "percent": 0,
            "taxExemptionReasonCode": "VATEX-SA-32",
            "taxExemptionReason": "Export of goods"
          }
        ]
      }
    ],
    "totals": {
      "totalLineTaxableAmount": 5000,
      "totalAmountExcludingTax": 5000,
      "totalTaxAmount": 0,
      "totalAmountIncludingTax": 5000,
      "amountDue": 5000
    },
    "extensions": { "sa_icv": "28" }
  }
}

ZATCA clears an export invoice like any standard invoice: government.status is CLEARED when it is accepted.

Last updated