Sample code for 30+ languages & platforms
Pascal (Lazarus/Delphi)

Send ZATCA Invoice for Clearance

See more ZATCA Examples

Demonstrates how to send a ZATCA invoice for clearance, which is to send the HTTP POST with invoice hash and the signed invoice in base64 format.

Chilkat Pascal (Lazarus/Delphi) Downloads

Pascal (Lazarus/Delphi)
program ChilkatDemo;

// Demonstrates using the Chilkat Pascal wrapper via the C bridge DLL.
// Builds as a console application under Lazarus (FPC) or Delphi.

{$IFDEF FPC}
  {$MODE DELPHI}
{$ENDIF}
{$APPTYPE CONSOLE}

uses
  {$IFDEF UNIX}
  cthreads,
  {$ENDIF}
  SysUtils,
  CkDllLoader,
  Chilkat.Http,
  Chilkat.BinData,
  Chilkat.HttpResponse,
  Chilkat.Xml,
  Chilkat.JsonObject;

// ---------------------------------------------------------------------------

procedure RunDemo;
var
  success: Boolean;
  signedXmlFilePath: string;
  signedXml: TXml;
  invoiceHash: string;
  cbc_UUID: string;
  bd: TBinData;
  base64Invoice: string;
  json: TJsonObject;
  http: THttp;
  resp: THttpResponse;
  statusCode: Integer;
  jsonResp: TJsonObject;

begin
  success := False;

  //  This example requires the Chilkat API to have been previously unlocked.
  //  See Global Unlock Sample for sample code.

  //  This example will send a POST with HTTP Basic Authentication to 
  //  https://gw-fatoora.zatca.sa/e-invoicing/simulation/invoices/clearance/single

  //  NOTE: At the time of this writing, I don't know for sure if the above URL is correct.
  //  
  //  The body of the POST will contain JSON formatted as such:

  //  {
  //    "summary": "Standard Invoice",
  //    "value": {
  //      "invoiceHash": "PEx8bNFcEMEpHzUVvQntQI6ot8eFqTT/l59b+H1HqX4=",
  //      "uuid": "16e78469-64af-406d-9cfd-895e724198f0",
  //      "invoice": "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPEl....."
  //    }
  //  }

  //  The above JSON is created from the signed XML invoice, such as the following:

  //  *** Look at the above base64 data for the invoiceHash and uuid.  These values are found in the invoice as shown below.
  //  *** We'll write code to load the signed invoice into a Chilkat XML object, grab the invoice hash and the uuid,
  //  *** and then construct the above JSON, which will then be sent in a POST.  (See below...)

  //  <?xml version="1.0" encoding="UTF-8"?>
  //  <Invoice xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2" xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2" xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2" xmlns:ext="urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2"><ext:UBLExtensions>
  //      <ext:UBLExtension>
  //          <ext:ExtensionURI>urn:oasis:names:specification:ubl:dsig:enveloped:xades</ext:ExtensionURI>
  //          <ext:ExtensionContent>
  //              <!-- Please note that the signature values are sample values only -->
  //              <sig:UBLDocumentSignatures xmlns:sig="urn:oasis:names:specification:ubl:schema:xsd:CommonSignatureComponents-2" xmlns:sac="urn:oasis:names:specification:ubl:schema:xsd:SignatureAggregateComponents-2" xmlns:sbc="urn:oasis:names:specification:ubl:schema:xsd:SignatureBasicComponents-2">
  //                  <sac:SignatureInformation>
  //                      <cbc:ID>urn:oasis:names:specification:ubl:signature:1</cbc:ID>
  //                      <sbc:ReferencedSignatureID>urn:oasis:names:specification:ubl:signature:Invoice</sbc:ReferencedSignatureID>
  //                      <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Id="signature">
  //                          <ds:SignedInfo>
  //                              <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2006/12/xml-c14n11"/>
  //                              <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256"/>
  //                              <ds:Reference Id="invoiceSignedData" URI="">
  //                                  <ds:Transforms>
  //                                      <ds:Transform Algorithm="http://www.w3.org/TR/1999/REC-xpath-19991116">
  //                                          <ds:XPath>not(//ancestor-or-self::ext:UBLExtensions)</ds:XPath>
  //                                      </ds:Transform>
  //                                      <ds:Transform Algorithm="http://www.w3.org/TR/1999/REC-xpath-19991116">
  //                                          <ds:XPath>not(//ancestor-or-self::cac:Signature)</ds:XPath>
  //                                      </ds:Transform>
  //                                      <ds:Transform Algorithm="http://www.w3.org/TR/1999/REC-xpath-19991116">
  //                                          <ds:XPath>not(//ancestor-or-self::cac:AdditionalDocumentReference[cbc:ID='QR'])</ds:XPath>
  //                                      </ds:Transform>
  //                                      <ds:Transform Algorithm="http://www.w3.org/2006/12/xml-c14n11"/>
  //                                  </ds:Transforms>
  //                                  <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
  //                                  <ds:DigestValue>PEx8bNFcEMEpHzUVvQntQI6ot8eFqTT/l59b+H1HqX4=</ds:DigestValue>
  //                              </ds:Reference>
  //                              <ds:Reference Type="http://www.w3.org/2000/09/xmldsig#SignatureProperties" URI="#xadesSignedProperties">
  //                                  <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
  //                                  <ds:DigestValue>ZDEyMDUyODJjYzk4MGViNTJhNmYzMGIyZTgxODhkY2JlOWEzNmRiMTFlZTVhMDAxNjk5OTRkYTg3ODhlY2ZiMw==</ds:DigestValue>
  //                              </ds:Reference>
  //                          </ds:SignedInfo>
  //  ...
  //  ...
  //  ...
  //          </ext:ExtensionContent>
  //      </ext:UBLExtension>
  //  </ext:UBLExtensions>
  //      
  //      <cbc:ProfileID>reporting:1.0</cbc:ProfileID>
  //      <cbc:ID>SME00062</cbc:ID>
  //      <cbc:UUID>16e78469-64af-406d-9cfd-895e724198f0</cbc:UUID>
  //      <cbc:IssueDate>2022-03-13</cbc:IssueDate>
  //      <cbc:IssueTime>14:40:40</cbc:IssueTime>
  //      <cbc:InvoiceTypeCode name="0111010">388</cbc:InvoiceTypeCode>
  //  ...
  //  ...
  //  ...
  //      </cac:InvoiceLine>
  //  </Invoice>

  //  -------------------------------------------------------------------
  //  First, let's load our signed XML into a Chilkat XML object so we can get the uuid and invoice hash.
  signedXmlFilePath := 'qa_data/zatca/http_post_clearance/sample_signed_invoice.xml';

  signedXml := TXml.Create;
  success := signedXml.LoadXmlFile(signedXmlFilePath);
  if (success = False) then
    begin
      WriteLn(signedXml.LastErrorText);
      Exit;
    end;

  invoiceHash := signedXml.GetChildContent('ext:UBLExtensions|ext:UBLExtension|ext:ExtensionContent|sig:UBLDocumentSignatures|sac:SignatureInformation|ds:Signature|ds:SignedInfo|ds:Reference[0]|ds:DigestValue');
  WriteLn('invoiceHash: ' + invoiceHash);

  cbc_UUID := signedXml.GetChildContent('cbc:UUID');
  WriteLn('UUID: ' + cbc_UUID);

  //  The Chilkat XML object was used purely for getting the above 2 values.
  //  We must send the EXACT signed XML in base64 format.  Therefore, we should load the signed XML into a Chilkat BinData and get it in base64 single-line format.

  bd := TBinData.Create;
  success := bd.LoadFile(signedXmlFilePath);
  base64Invoice := bd.GetEncoded('base64');

  //  OK, let's build the JSON that will be in the HTTP POST body.
  json := TJsonObject.Create;
  json.UpdateString('summary','Standard Invoice');
  json.UpdateString('value.invoiceHash',invoiceHash);
  json.UpdateString('value.uuid',cbc_UUID);
  json.UpdateString('value.invoice',base64Invoice);

  //  Now create the HTTP object and send the POST.
  http := THttp.Create;

  //  We'll want HTTP basic authentication.
  http.BasicAuth := True;
  http.Login := 'your login';
  http.Password := 'your password';

  resp := THttpResponse.Create;
  success := http.HttpJson('POST','https://gw-fatoora.zatca.sa/e-invoicing/simulation/invoices/clearance/single',json,'application/json',resp);
  if (success = False) then
    begin
      WriteLn(http.LastErrorText);
      Exit;
    end;

  //  Check the response status code.  A 200 or 202 indicates success..
  statusCode := resp.StatusCode;
  WriteLn('Response status code = ' + statusCode);

  //  Examine the response, which is JSON.
  jsonResp := TJsonObject.Create;
  resp.GetBodyJson(jsonResp);
  jsonResp.EmitCompact := False;
  WriteLn('JSON Response:');
  WriteLn(jsonResp.Emit());

  //  Use this online tool to generate parsing code from sample JSON: 
  //  Generate Parsing Code from JSON


  signedXml.Free;
  bd.Free;
  json.Free;
  http.Free;
  resp.Free;
  jsonResp.Free;

end;

// ---------------------------------------------------------------------------

begin

  try
    RunDemo;
  except
    on E: Exception do
      WriteLn('Unhandled exception: ', E.ClassName, ': ', E.Message);
  end;

  WriteLn;
  {$IFDEF MSWINDOWS}
  WriteLn('Press Enter to exit...');
  ReadLn;
  {$ENDIF}
end.