Qoyod
Pricing

Knowledge Base

Clearance API on Fatoora: A Developer’s Guide

This is the practical developer guide to calling the Clearance API on the Fatoora platform — the interface every standard tax invoice (B2B) passes through before it is delivered to the buyer as part of Qoyod e-invoicing. We will focus here on the call itself: the endpoint, the required headers, the JSON request body, and the response that returns the cleared invoice along with the validation results. The goal is to implement the integration step by step, from the sandbox environment to production.

Before we begin, let us separate three levels so the concepts do not get mixed up. The conceptual level of clearance is explained on the Clearance in e-invoicingpage, and the full list of available endpoints is documented on the Fatoora platform API endpointspage. This page is different: it is a single applied recipe that walks you through a clearance call from start to finish.

The Zakat, Tax and Customs Authority (ZATCA) issues the e-invoicing requirements, and the Fatoora platform is the technical gateway that receives the invoices. Everything covered here follows the Phase Two (Integration) specification and the UBL 2.1 standard.

What is a clearance call?

Clearance is the process of sending the standard tax invoice to the Fatoora platform before delivering it to the buyer. The Authority validates the invoice, adds its stamp, then returns a cleared copy to you. A standard invoice may not be delivered to the buyer until it comes back cleared. This differs from Reporting, which applies to simplified invoices (B2C) that are delivered immediately and then reported within 24 hours.

In practice, this means every B2B invoice has a synchronous network call. The invoice is sent as Base64-encoded XML, together with the invoice hash (invoiceHash) and the unique identifier (uuid), then you wait for the response. The response is either fully cleared, cleared with warnings, or rejected with errors that must be resolved.

This fundamental difference shapes your system design: the clearance call must complete before the buyer sees the invoice, so it needs careful handling of errors, timeouts, and retries.

The purpose of clearance is for the Authority to verify the validity of the invoice at the moment it is issued, not after a period of time. This reduces manipulation and ensures that every standard invoice in the market has passed an official check and carries a trusted stamp. For the developer, this means the integration is not an optional extra step but a condition for the invoice to be legally valid. A standard invoice that has not gone through clearance is not a valid invoice from the system’s perspective, even if all its fields are complete.

When do you call Clearance and when do you call Reporting?

The rule is simple. If the invoice is standard (for businesses or government entities), call clearance. If it is simplified (for an end consumer), call reporting. Credit and debit notes follow the type of the original invoice: a note on a standard invoice goes through clearance, and a note on a simplified invoice goes through reporting.

When to call Clearance vs Reporting
How to choose the right interface based on the invoice type.
Criterion Clearance (B2B) Reporting (B2C)
Invoice type Standard tax Simplified
Clearance-Status 1 0
Delivery After clearance Immediate, then reported
The standard invoice is passed to clearance, and the simplified one to reporting.

The endpoint and the core requirements

The endpoint for clearing a single invoice is:

POST /invoices/clearance/single

The full endpoint URL is built by combining the Fatoora platform base URL with the path above. The base URL changes between the sandbox (Sandbox) and production environments, so make it a variable in your settings and do not hard-code it.

Before the call you need three items ready:

  • Cryptographic Stamp Identifier (CSID): The identifier you obtained from the Fatoora platform after completing the onboarding path. It is split into a compliance CSID (for testing) and a production CSID (for live invoices).
  • A valid XML invoice: built according to UBL 2.1 and signed with the cryptographic stamp, containing the invoice counter (ICV) and the previous invoice hash (the verification chain).
  • The invoice hash (invoiceHash): the SHA-256 value of the invoice after canonicalization.

An important note about the name: the correct abbreviation is CSID (Cryptographic Stamp Identifier), not any other ordering of the letters. Mixing up the order of the letters is one of the most common integration mistakes.

Obtaining the stamp identifier before the first call

You cannot call clearance before you hold a valid stamp identifier. The path to obtaining it goes through specific steps on the Fatoora platform. You start by generating a Certificate Signing Request (CSR) for the device or establishment, then send it through the Fatoora portal attached to a one-time password (OTP) that the taxpayer obtains from their account.

After that you receive the Compliance CSID. This identifier opens the compliance interfaces for you in the sandbox environment only. You use it to send test invoices covering the required cases: a standard invoice, a simplified invoice, a credit note, and a debit note. Once you pass these checks you receive the Production CSID, which signs every live invoice afterward.

An important practical point: every device, branch, or environment needs its own stamp identifier. Do not share a single identifier across multiple branches, because the invoice hash chain and the invoice counter are tied to the device. Mixing identifiers breaks the chain and causes consecutive invoice rejections.

The difference between the sandbox and production environments

The Fatoora platform runs in two completely separate environments. The sandbox (Sandbox) is dedicated to testing the integration with non-real invoices, and the compliance identifier works only there. The production environment receives real invoices, and the production identifier works only there. Each environment has a different base URL.

The common mistake here is that the developer builds their integration with the compliance identifier and then forgets it in production, so all invoices are rejected. Make the base URL and the stamp identifier variables in the settings, and switch them together when moving to production. Do not hard-code either of them.

The required headers (Headers)

A clearance call often fails because of a missing or wrong header, before it even reaches the invoice content validation. These three headers are mandatory:

Header Value Purpose
Authorization Basic {Base64(CSID:secret)} Authenticates your identity using the cryptographic stamp identifier.
Accept-Version V2 Specifies the interface version. Phase Two uses V2.
Clearance-Status 1 Requests the actual clearance. The value 1 means perform clearance.
Content-Type application/json The request body in JSON format.
Accept-Language ar or en The language of warning and error messages in the response (optional).

Header Authorization It follows the standard Basic scheme: you take the cryptographic stamp identifier and its secret, join them with a colon, encode the result in Base64, then prefix it with the word Basic. The Clearance-Status header distinguishes a full clearance request from validation only, so make sure to pass the value 1 in production.

Example of the complete headers

POST /invoices/clearance/single HTTP/1.1
Host: gw-fatoora.zatca.gov.sa
Authorization: Basic VFNUMDIxMjM0NTY3ODk6c2VjcmV0X3ZhbHVl
Accept-Version: V2
Clearance-Status: 1
Content-Type: application/json
Accept-Language: ar

The value in the authorization header above is just an illustrative Base64-encoded example. Replace it with your actual cryptographic stamp identifier value.

The request body (Request Body)

The request body is a JSON object with three mandatory fields. Each field has a specific role in the validation process:

{
  "invoiceHash": "NWZlY2ViNjZmZmM4NmYzOGQ5NTI3ODZjNmQ2OTZjNzk=",
  "uuid": "3cf5ee18-ee25-44ea-a444-2c37ba7f28be",
  "invoice": "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4..."
}

Detail of each field:

  • invoiceHash: The invoice hash, which is a SHA-256 value computed on the XML copy after canonicalization according to the approved canonicalization rules. Any small difference in the content changes the hash, so compute it on the exact final signed copy.
  • uuid: The unique invoice identifier in UUID version 4 format. It must match the identifier inside the invoice itself. Reusing it across different invoices causes rejection.
  • invoice: The full XML invoice after Base64 encoding. This is the actual content that the Authority will validate and stamp.

The order does not matter in JSON, but all three fields must be present. The absence of any of them returns a request-structure error before the invoice content validation begins.

The fields of the clearance request body
The three fields in the Clearance request body.
Request body

invoiceHash: SHA-256 hash of the invoice

uuid: the unique invoice identifier

invoice: the invoice in Base64 encoding (XML)

The invoice is sent Base64-encoded together with its hash and identifier.

How do you build the encoded invoice field?

The steps in order: build the XML invoice according to UBL 2.1, add the invoice counter and the previous invoice hash, sign the invoice with the cryptographic stamp, compute the SHA-256 hash on the canonicalized copy, then Base64-encode the final XML. The result is the value of the invoicefield, and the hash is the value of the invoiceHash.

field. Mind the order: sign first, then compute the hash, then encode. Reversing the order produces a hash that does not match the sent content, so the invoice is rejected.

The most important fields inside the standard XML invoice

The invoice you send for clearance is not ordinary XML, but a UBL 2.1 structure containing mandatory fields that the Authority validates. Knowing them helps you read the reason for any rejection quickly:

  • Invoice counter (ICV): a sequential ascending number across every invoice issued from the device. It may not be repeated, nor may a value in the sequence be skipped.
  • Previous invoice hash: a value that links the current invoice to the one before it in a verification chain. The first invoice uses a starting value defined in the specification.
  • The unique identifier (UUID): inside the XML itself, and it must match the value of the uuid field in the request body.
  • The cryptographic stamp: an ECDSA signature using the stamp identifier, added within the signature section of the invoice.
  • The QR code (QR): in TLV format, Base64-encoded, containing the seller, invoice, and signature data.
  • Identification numbers: the seller’s and buyer’s tax number and the commercial registration, each in its defined format and length.

Any flaw in these fields shows up in the validation results with a clear error or warning code. This is why it is useful to read the message code rather than settle for its text, because the code refers you directly to the rule that was broken in the Authority’s specification.

The response on successful clearance

On successful clearance, the Fatoora platform returns the status code 200 with an object containing the cleared invoice and the validation results. The cleared invoice carries the Authority’s stamp, and it is the copy delivered to the buyer:

HTTP/1.1 200 OK
Content-Type: application/json

{
  "validationResults": {
    "infoMessages": [
      {
        "type": "INFO",
        "code": "XSD_ZATCA_VALID",
        "category": "XSD validation",
        "message": "Complied with UBL 2.1 standards in line with ZATCA specifications",
        "status": "PASS"
      }
    ],
    "warningMessages": [],
    "errorMessages": [],
    "status": "PASS"
  },
  "clearanceStatus": "CLEARED",
  "clearedInvoice": "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZ..."
}

The two most important fields here:

  • clearedInvoice: The cleared invoice in Base64 format. Decode it to get the final XML signed by the Authority. This is the official copy delivered to the buyer and stored.
  • clearanceStatus: The clearance status. The value CLEARED means full clearance success. Any other value requires reviewing the validation results.

The validationResults object summarizes the validation results in three lists: informational messages, warnings, and errors, along with a general status field. On full clearance the warnings and errors lists are empty and the status is PASS.

Reading warnings and errors

Not every successful response is completely empty. An invoice may be cleared with warnings, and it may be rejected with errors. Distinguishing between them is the basis for building a reliable system.

Clearance with warnings

A warning does not prevent clearance, but it points to something that should be fixed in the future. The status remains PASS and it returns clearanceStatus with the value CLEARED, but the warningMessages list carries the details:

{
  "validationResults": {
    "warningMessages": [
      {
        "type": "WARNING",
        "code": "BR-KSA-F-06",
        "category": "KSA",
        "message": "The seller address must contain a valid additional number",
        "status": "WARNING"
      }
    ],
    "errorMessages": [],
    "status": "PASS"
  },
  "clearanceStatus": "CLEARED"
}

Address warnings because they may turn into errors in later updates of the specification. Log the warning code and its message so your team can handle it without re-calling.

Rejection with errors

When there is an actual error, clearance fails. The status is ERROR and the errorMessages list is populated, and no cleared invoice is returned:

HTTP/1.1 400 Bad Request
Content-Type: application/json

{
  "validationResults": {
    "warningMessages": [],
    "errorMessages": [
      {
        "type": "ERROR",
        "code": "BR-KSA-F-04",
        "category": "KSA",
        "message": "Invoice hash does not match the submitted invoice",
        "status": "ERROR"
      }
    ],
    "status": "ERROR"
  },
  "clearanceStatus": "NOT_CLEARED"
}

The golden rule: do not deliver the invoice to the buyer unless it comes back clearanceStatus with the value CLEARED. On rejection, correct the cause stated in the error code and its message, rebuild the invoice, then call again.

The three clearance response cases
What each response from the Clearance API means.
Result Action
CLEARED The invoice is cleared and delivered
CLEARED with a warning Cleared with notes for correction
NOT_CLEARED Rejected: correct and resend
The invoice is only delivered to the buyer in the CLEARED state.

Common error codes and their causes

Cause Action
The invoice hash does not match the sent content Recompute SHA-256 on the final canonicalized copy after signing.
A duplicate uuid, or one that does not match what is in the invoice Generate a new unique UUID and make it match the identifier inside the XML.
An identification number in the wrong format (commercial registration, tax number) Check the number’s length and prefix before sending.
A wrong Authorization header or an expired stamp identifier Rebuild the Basic encoding and make sure the stamp identifier is valid.
The invoice counter or the hash chain is out of sequence Make sure the ICV sequence and the previous invoice hash link are correct.

Common integration mistakes and how to avoid them

After dozens of integrations, the same mistakes recur. Avoiding them saves you hours of debugging:

  • Mixing testing and production: the compliance stamp identifier works only with the test endpoints, and the production identifier only with the production endpoints. Do not mix them.
  • Computing the hash before signing: the hash is computed on the final signed copy. Computing it before signing produces a value that does not match the sent content.
  • Forgetting Accept-Version: a missing header or a wrong value returns an unsupported-version error.
  • Ignoring warnings: today’s warning may become tomorrow’s error. Address it early.
  • Not handling the timeout: the clearance call is synchronous. Set a reasonable timeout and retry on expiry or on server code 502 or 504.
  • Mismatch of the unique identifier between the request and the invoice: the uuid value in the request body must match the identifier inside the XML exactly. Any difference causes rejection.

Before moving to production, test all cases in the sandbox: an invoice that succeeds, an invoice that returns a warning, and an invoice that is rejected with an error. Make sure your system reads the three fields (clearanceStatus, status, and the lists) and behaves correctly in each case. An integration that only handles success and ignores warnings and errors will stumble at the first real invoice that goes off the expected path. Make reading the validation results a core part of the logic, not a later addition.

Also remember that the Fatoora platform is the final reference for verification. Any system sends what the user builds, and the Authority is the one that validates and stamps. No local check substitutes for the actual clearance call.

Retrying and handling interruptions

Because the clearance call is synchronous and precedes invoice delivery, you must handle network interruptions carefully. If the timeout expires or server code 502, 503, or 504 comes back, the invoice has not been cleared yet and the same request can be retried.

The critical rule here: keep the unique identifier and the invoice hash constant between attempts. Do not generate a new uuid when resending the same invoice, because that makes it look like a different invoice. Resend the exact same request body verbatim. This protects the counter sequence and the chain from breaking.

Set a reasonable timeout for each call, and cap the number of attempts (for example, three attempts with increasing intervals). If it keeps failing after that, park the invoice in a queue for manual handling instead of flooding the platform with repeated requests.

Credit and debit notes in clearance

The clearance path is not limited to sales invoices. The credit note (for a refund or partial cancellation) and the debit note (for an additional charge) follow the type of the original invoice. If the note is linked to a standard invoice, it also goes through clearance via the same endpoint and with the same headers.

The difference is that the note carries a reference to the original invoice within its structure. Make sure this reference is correct, because a note without a valid original invoice is rejected. As for notes linked to simplified invoices, they are reported and not cleared, exactly like the simplified parent invoice.

This synchronous integration requires discipline in the order of operations and in storing copies. The only official copy is the clearedInvoice returned by the Authority, and any local copy before clearance is not considered an approved invoice.

Security and performance considerations in production

The cryptographic stamp identifier and its secret are sensitive data. Store them in a secure secrets vault, not in the code and not in exposed configuration files. Any leak of these values allows invoices to be signed in your establishment’s name.

On the performance side, the clearance call is synchronous and adds latency to each invoice. Design the user interface so it does not freeze while waiting for the response. Show a processing state, and display the invoice as soon as it comes back cleared. In bulk-issuance cases, distribute the calls in reasonable batches instead of sending thousands of requests at once.

For each call, log the invoice identifier, the response code, and the clearance status, along with the codes of any warnings or errors. This log is essential for auditing and for tracing any rejection, and it shortens the time to resolve issues when reviewing an old invoice. Keep the cleared copy (clearedInvoice) for the statutory retention period for tax records.

How Qoyod helps you with clearance integration

Qoyod is an accounting system compliant with Phase Two of e-invoicing, and it handles the details of the clearance call so you do not build them yourself from scratch. Here is specifically what Qoyod does on this path:

  • Generates the XML invoice to the UBL 2.1 standard with the QR code, the cryptographic stamp, and the invoice hash chain, ready for clearance without hand-crafting the XML.
  • Manages the cryptographic stamp identifier (CSID) for each branch or device through the Fatoora platform onboarding path, so you do not deal manually with certificate signing requests.
  • Validates the format of identification numbers in real time (the commercial registration as a 10-digit number, the tax number as 10 digits starting with 3, and others) on entry in the establishment settings, customer files, and invoices, catching one of the most common causes of warnings before sending.
  • Embeds the XML inside a PDF/A-3 file automatically in sales invoices and debit notes, so you get a single file containing both the display format and the XML format, while a standalone XML download button remains available.
  • Manages both clearance and reporting states so it sends standard invoices (B2B) to clearance and simplified invoices (B2C) to reporting within 24 hours without you manually choosing the correct path.

Qoyod’s technical team is available for support 24 hours a day, all week long, so if you face a rejection or a warning whose cause you do not know, you will find someone to help you read it.

The full lifecycle of a clearance call

Let us gather the steps into a single sequence you apply to every standard invoice:

  • 1) Build: Create the XML invoice according to UBL 2.1 with the invoice counter and the previous invoice hash.
  • 2) Sign: Sign the invoice with the cryptographic stamp linked to the stamp identifier.
  • 3) Hash and encode: Compute SHA-256 on the canonicalized copy, then Base64-encode the XML.
  • 4) Call: Send a POST to the clearance endpoint with the three headers and the JSON body.
  • 5) Read: Inspect clearanceStatus and the validation results. On CLEARED, extract clearedInvoice.
  • 6) Deliver: Deliver the cleared invoice to the buyer and store it.

Any stumble in a step must halt the step that follows it. Do not deliver an invoice that has not been cleared, and do not store an unstamped copy as if it were official.

Linking this page to the rest of the developer hub

If you want the full theoretical picture of the clearance concept and its place in the invoice journey, start from the Clearance in e-invoicingpage. And if you want to explore the rest of the interfaces available on the Fatoora platform (compliance, reporting, certificate management), see the Fatoora platform API endpointspage. These three pages together cover both the theoretical and the applied sides.

Start today

Try Phase-Two-compliant invoicing in Qoyod

Let Qoyod handle building the invoice, signing it, and calling clearance on your behalf, and issue your standard invoices cleared by the Authority without writing a single line of integration.

Start your free trial now

Frequently asked questions

What is the difference between a clearance call and a reporting call?

Clearance is for standard invoices (B2B) and requires sending the invoice to the Authority before delivering it to the buyer and obtaining a stamped copy. Reporting is for simplified invoices (B2C) and is done after the invoice is delivered to the buyer, within 24 hours. The two endpoints are different, and so is the timing of the call.

What does the Clearance-Status value in the header mean?

The value 1 requests the actual clearance to be performed. The Authority uses it to distinguish a full clearance request from other scenarios. In production, always pass the value 1 for standard invoices.

Why is the invoice rejected with a hash-mismatch message?

The most common reason is computing the SHA-256 hash on a copy different from the content actually sent. Make sure you compute the hash on the final XML copy after signing and canonicalization, and that you send the same copy in the invoice field.

Must a new uuid be generated for each invoice?

Yes. The unique identifier must be unique for each invoice and must match the identifier embedded inside the XML itself. Repeating the identifier or its mismatch with the invoice causes rejection.

What is the difference between the compliance stamp identifier and the production one?

The compliance identifier (Compliance CSID) is used in the sandbox environment to complete compliance checks on test invoices. The production identifier (Production CSID) is used in the live environment to sign every actual invoice. Each environment has its own identifier and endpoints.

What do I do if the connection drops during a clearance call?

If the timeout expires or server code 502, 503, or 504 comes back, the invoice has not been cleared and the same request can be resent without changing the unique identifier or the hash. Keep the request body constant between attempts, cap the number of attempts with increasing intervals, then move the invoice to a manual-handling queue if it keeps failing.

Should I send credit and debit notes to clearance as well?

Yes, if they are linked to a standard invoice. The note follows the type of its original invoice: a note on a standard invoice goes through clearance via the same endpoint, and a note on a simplified invoice is reported and not cleared. Make sure the reference to the original invoice inside the note is correct.

Does Qoyod handle the clearance call on my behalf?

Yes. Qoyod builds the invoice to the UBL 2.1 standard, signs it, computes the hash, and calls clearance automatically for standard invoices, then stores the cleared copy. You do not need to write a manual integration with the Fatoora platform.

Guides

Continue your learning journey

Explore the rest of Qoyod’s guides, or start applying what you’ve learned.

Live webinars hosted by the Qoyod team to help you use the software easily and answer your questions.

Discover Qoyod’s latest updates, ongoing improvements, and new features in one place.

Our team is ready to help you and provide instant support for any issue you face, around the clock.