{"errorCode":"400","errorCategory":"Invalid-CSR","errorMessage":"The provided Certificate Signing Request (CSR) is invalid."}

{“errorCode”:“400”,“errorCategory”:“Invalid-CSR”,“errorMessage”:“The provided Certificate Signing Request (CSR) is invalid.”}

Dear @dalgindy,

To support you better, please provide the below information:

1- Are you using simulation or production environment?

2- Are you generating the CSR through ZATCA’s official SDK? or OpenSSL? or another tool?

3- Are you sending the CSR encoded to base64 in the API’s body?

Thank you in advance.

1 Like

Dear Aturkistani, now i will use Simulation for 1 weak only , because we very close to use production ,
Thank you for your prompt response. Here are the answers to your questions:

1. We are using the simulation environment for testing our integration.

2. We are generating the CSR using OpenSSL with a custom configuration file (Configuration.cnf). We've tried both direct OpenSSL commands and PHP's OpenSSL functions.

3. Yes, we are sending the CSR encoded to base64 in the API's body. We're also making sure to remove all line breaks and spaces from the base64 encoded string before sending it.

Here's our Configuration.cnf file content:

oid_section = OIDs
[ OIDs ]
certificateTemplateName = 1.3.6.1.4.1.311.20.2

[ req ]
default_bits = 2048
emailAddress = info@company.com
req_extensions = v3_req
x509_extensions = v3_ca
prompt = no
default_md = sha256
req_extensions = req_ext
distinguished_name = dn

[ dn ]
C = SA
OU = ABC trading est
O = ABC for IT
CN = 1-ABC

[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment

[req_ext]
certificateTemplateName = ASN1:PRINTABLESTRING:PREZATCA-Code-Signing
subjectAltName = dirName:alt_names

[alt_names]
SN = 1-Device|2-777|3-100001
UID = 3XXXXXXXXX00003
title = 1100
registeredAddress = Saudi Arabia
businessCategory = Technology

We're using the following command to generate the CSR:
openssl req -new -sha256 -key privateKey.pem -extensions v3_req -config Configuration.cnf -out taxpayer.csr

Could you please advise if there's anything incorrect in our configuration or approach?

Thank you for your assistance.

Best regards,

Subject: Follow-up on Invalid-CSR Error - Sharing Code Implementation Details

Dear ZATCA Support Team,

Thank you for your previous response regarding our CSR validation issue. I'd like to share our corrected implementation and seek your guidance.

## 1. Our Configuration.cnf file:

```plaintext
oid_section = OIDs
[ OIDs ]
certificateTemplateName = 1.3.6.1.4.1.311.20.2

[ req ]
default_bits = 2048
emailAddress = info@company.com
req_extensions = v3_req
x509_extensions = v3_ca
prompt = no
default_md = sha256
req_extensions = req_ext
distinguished_name = dn

[ dn ]
C = SA
OU = altall alawal trading est
O = altall alawal for IT
CN = 1-altall alawal

[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment

[req_ext]
certificateTemplateName = ASN1:PRINTABLESTRING:PREZATCA-Code-Signing
subjectAltName = dirName:alt_names

[alt_names]
SN = 1-Device|2-777|3-100001
UID = 3XXXXXXXXX00003
title = 1100
registeredAddress = Saudi Arabia
businessCategory = Technology
2. Our CSR Generation Process:
We're using OpenSSL commands directly to generate the CSR:

bash


# 1. Generate private key using secp256k1
openssl ecparam -name secp256k1 -genkey -noout -out privateKey.pem

# 2. Generate CSR using our configuration file
openssl req -new -sha256 -key privateKey.pem -extensions v3_req -config Configuration.cnf -out taxpayer.csr
3. Compliance Certificate Request Code:
php


public function requestCompliance(Request $request)
{
$request->validate([
'otp' => 'required|string|size:6'
]);

try {
$csrPath = storage_path('app/zatca/taxpayer.csr');
if (!file_exists($csrPath)) {
throw new Exception('CSR not found');
}

// Read CSR content and encode to Base64
$csrContent = file_get_contents($csrPath);
$csrBase64 = str_replace(["\r", "\n", " "], '', base64_encode($csrContent));

// Send request to ZATCA
...26 lines truncated. Use the buttons above to view or insert the full code.

Questions:
Is our Configuration.cnf file structure correct, particularly the DN and alt_names sections?

Should we be using any specific values for:

SN (Serial Number format)
UID (Tax Number format)
title (Invoice types: 1100)
Are we correctly using secp256k1 for the private key generation?

Is there anything specific we need to include in the CSR that we might be missing?

We appreciate your assistance in identifying any issues in our implementation.

Diyaa ElGindy

هل يمكن لفريق الدعم المحترم المساعدة في حل المشاكل الخاصة بخطوات طلب شهادة الامتثال ؟
هل يمكن الحصول على ايميل للتواصل بشكل افضل ؟

*** هام جدا : من المؤكد ان وجود فريق دعم متفاعل ومتجاوب بسلاسة مع مشاكل الانظمة فإن هذا الامر يسهل الربط
ولذلك أطلب رجاءا أن يكون فيه 3 صفحات اساسية على الاقل واحد مثلا بالبايثون
وأخرى بـ Php وثالثة Laravel فهذه الثلاثة يكون في كل صفحة مثال بالكود كسورس كود عن جميع
الخطوات من بداية الربط الى الحصول على التقارير بشكل آلي

  • واتوقع طلب كهذا اذا تم رفعه الى السادة الأفاضل المسئولين - سوف يرحبون بالفكرة دون أي تأخير -
    خاصة وأن هذا فقط سوف يتم بأمر من السادة المسئولين الى فريق الدعم المحترمين بانشاء هذه الصفحات
  • فعندئذ يمكن للمبرمجين مثلي استعمال الكود واختصار الكثير جدا جدا من الوقت -
    كما أنها تعتبر إضافة قوية جدا تستحقها الهيئة الموقرة - هيئة الزكاة والضريبة والجمارك
    ضياء الجندي

السلام عليكم ورحمة الله وبركاته

أسعد الله مسائك صديقي, وأهلا بك في منصتنا

لضمان تقديم الدعم الشامل المعتاد, يرجى التكرم بمشاركة كافة الخطوات المتبعة مع ارفاق بعض الصور لإستجابة ال API
الى البريد الإلكتروني أدناه

البريد الإلكتروني: sp_support@zatca.gov.sa

شكرا,
إبراهيم داوود.

Dear Aturkistani

Thank you for your prompt response. Please find below the detailed information about our implementation:

Environment: Simulation
CSR Generation: OpenSSL
CSR Encoding: Yes, using base64 in API body
Current Implementation Details:

XML Document Structure (Standard_Invoice.xml example):

cbc:ProfileIDreporting:1.0</cbc:ProfileID>
cbc:ID{{DOCUMENT_ID}}</cbc:ID>
cbc:UUID{{UUID}}</cbc:UUID>
cbc:IssueDate{{ISSUE_DATE}}</cbc:IssueDate>
cbc:IssueTime{{ISSUE_TIME}}</cbc:IssueTime>
<cbc:InvoiceTypeCode name=“0100000”>388</cbc:InvoiceTypeCode>
Processing Code (ZatcaController.php):

private function processComplianceDocumentsAutomatically($certificate)
{
try {
$documents = [
[
‘type’ => ‘standard_invoice’,
‘name’ => ‘Standard Tax Invoice’,
‘filename’ => ‘Standard_Invoice.xml’
],
// … other documents
];

foreach ($documents as $document) {
// Read XML content
$xmlPath = resource_path(‘views/backend/zatca/compliance/documents/’ . $document[‘filename’]);
$xmlContent = file_get_contents($xmlPath);

// Generate dynamic values
$documentId = ‘SME’ . date(‘Ymd-His’);
$uuid = (string) \Illuminate\Support\Str::uuid();
$currentDate = date(‘Y-m-d’);
$currentTime = date(‘H:i:s’);

// Save document info to database
$zatcaDocument = new \App\Models\ZatcaDocument();
$zatcaDocument->document_id = $documentId;
$zatcaDocument->uuid = $uuid;
$zatcaDocument->type = $document[‘type’];
$zatcaDocument->save();

// Replace placeholders in XML
$xmlContent = str_replace(
[‘{{DOCUMENT_ID}}’, ‘{{UUID}}’, ‘{{ISSUE_DATE}}’, ‘{{ISSUE_TIME}}’],
[$documentId, $uuid, $currentDate, $currentTime],
$xmlContent
);

// Save modified XML
$unsignedPath = storage_path(‘app/zatca/temp/’ . $document[‘filename’]);
$signedPath = storage_path(‘app/zatca/temp/signed_’ . $document[‘filename’]);
file_put_contents($unsignedPath, $xmlContent);

// Sign the document
$signResult = $this->zatcaService->signUnsignedXmlFile($unsignedPath, $signedPath);

// Send to ZATCA API
$authorizationHeader = 'Basic ’ . base64_encode($certificate->certificate_content . ‘:’ . $certificate->secret);
$sendResult = $this->zatcaService->startOnboarding(
$signedPath,
$uuid,
$authorizationHeader,
‘simulation’
);
}
} catch (\Exception $e) {
Log::error('Error processing documents: ’ . $e->getMessage());
}
}

Database Structure (zatca_documents table):

CREATE TABLE zatca_documents (
id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
document_id varchar(255) NOT NULL,
uuid char(36) NOT NULL,
type varchar(255) NOT NULL,
status varchar(255) DEFAULT ‘pending’,
response text,
created_at timestamp NULL DEFAULT NULL,
updated_at timestamp NULL DEFAULT NULL,
PRIMARY KEY (id)
);

API Call Example:

public function startOnboarding($signedXmlPath, $uuid, $authorizationHeader, $portalType)
{
$apiUrl = $portalType === ‘simulation’
? ‘https://gw-fatoora.zatca.gov.sa/e-invoicing/simulation/compliance
: ‘https://gw-fatoora.zatca.gov.sa/e-invoicing/core/compliance’;

try {
$response = Http::withHeaders([
‘Authorization’ => $authorizationHeader,
‘Accept’ => ‘application/json’,
‘Accept-Version’ => ‘V2’,
‘Content-Type’ => ‘application/json’,
])->post($apiUrl, [
‘uuid’ => $uuid,
‘invoice’ => base64_encode(file_get_contents($signedXmlPath))
]);

return [
‘success’ => $response->successful(),
‘status_code’ => $response->status(),
‘message’ => $response->json()[‘message’] ?? null,
‘data’ => $response->json()
];
} catch (\Exception $e) {
return [
‘success’ => false,
‘message’ => $e->getMessage()
];
}
}

The error we consistently receive for all documents is:

UUID ERROR (Code: INVOICE_UUID_VALIDATION, Category: MISSING_UUID_IN_INVOICE)
We have verified that:

The UUID is being generated correctly using Laravel’s Str::uuid()
The same UUID is used in both the XML document and API request
The UUID follows the standard format (8-4-4-4-12 characters)
The UUID element is placed correctly in the XML structure
Could you please:

Confirm if our implementation approach is correct?
Provide any specific requirements for UUID handling that we might be missing?
Share an example of a correctly formatted XML document with UUID?

Thank you for your assistance.

Diyaa El-Gindy
0505297507

Dear Aturkistani

Thank you for your prompt response. Please find below the information you requested:

We are using the simulation environment for testing our compliance documents.

We are generating the CSR through OpenSSL directly. We have successfully generated the CSR and received the compliance certificate (CCSID).

Yes, we are sending the CSR encoded in base64 format in the API’s body as required.

The issue we’re facing now is specifically with the UUID validation when submitting the six compliance documents. All documents are being rejected with the error:

UUID ERROR (Code: INVOICE_UUID_VALIDATION, Category: MISSING_UUID_IN_INVOICE)
We have verified that:

Each XML document contains a UUID element in the correct position (after the ID element)
The UUID follows the standard format (8-4-4-4-12 characters)
We’re using the same UUID value in both the XML document and the API request
Could you please provide specific guidance on the UUID requirements for compliance documents? Is there any specific format or validation rule we might be missing?

فاتورة ضريبية قياسية | فشل | UUID ERROR (Code: INVOICE_UUID_VALIDATION, Category: MISSING_UUID_IN_INVOICE) |

  • | - | - |
    standard_credit_note | فشل | UUID ERROR (Code: INVOICE_UUID_VALIDATION, Category: MISSING_UUID_IN_INVOICE) |

Thank you for your assistance

(Attachment Standard_Invoice.xml is missing)

Dear Aturkistani

Thank you for your prompt response. Please find below the information you requested:

We are using the simulation environment for testing our compliance documents.

We are generating the CSR through OpenSSL directly. We have successfully generated the CSR and received the compliance certificate (CCSID).

Yes, we are sending the CSR encoded in base64 format in the API’s body as required.

The issue we’re facing now is specifically with the UUID validation when submitting the six compliance documents. All documents are being rejected with the error:

UUID ERROR (Code: INVOICE_UUID_VALIDATION, Category: MISSING_UUID_IN_INVOICE)
We have verified that:

Each XML document contains a UUID element in the correct position (after the ID element)
The UUID follows the standard format (8-4-4-4-12 characters)
We’re using the same UUID value in both the XML document and the API request
Could you please provide specific guidance on the UUID requirements for compliance documents? Is there any specific format or validation rule we might be missing?

Thank you for your assistance

dear @dalgindy ,

the UUID must be unique for each tax document submission, please ensure that the UUID is being placed in the correct tag, there are 2 tags with the name “UUID” inside the XML invoice, to make sure that the submitted tax XML doucment includes the “UUID” correctly, check on the following:

1- Navigate to xpather.com

2- paste the XML document as-is in the website

3- paste this value as-is in the xpath field:

/[local-name()=‘Invoice’]/[local-name()=‘UUID’]

4- check on the findings, then, you will have 2 scenraios:

  • First Scenario: you don’t find the correct UUID, that means the UUID value is placed inside the incorrect tag.
  • Second Scenario: You find teh UUID tag, then, please share the “dummy” XML invoice here to check.

Regards,

The invoice hash API body does not match the (calculated) Hash of the XML (Code: invalid-invoice-hash), Schema validation failed; XML does not comply with UBL 2.1 standards in line with ZATCA specifications. ERROR: org.xml.sax.SAXParseException; lineNumber: 195; columnNumber: 63; cvc-complex-type.2.4.a: Invalid content was found starting with element ‘{“XML-Signature Syntax and Processing”:Signature}’. One of ‘{“urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2”:InvoiceLine}’ is expected. (Code: XSD_ZATCA_INVALID), [BR-CUSTOM-VALIDATION-01] - يجب ألا يتطابق رقم تسجيل ضريبة القيمة المضافة للبائع أو رقم تسجيل ضريبة القيمة المضافة لمجموعة البائع (BT-31) للفاتورة مع رقم تسجيل ضريبة القيمة المضافة للمشتري (BT-48). (Code: BR-CUSTOM-VALIDATION-01)

Dear Aturkistani |

  • |

Thank you for your guidance regarding the UUID issue. I’ve checked our XML documents using the xpather.com tool as you suggested, and I found that we need to make adjustments to ensure the UUID is placed correctly.

I’ve made the following changes to our implementation:

  1. Ensured that the UUID is placed directly under the Invoice element with the correct namespace:
    cbc:UUIDunique-uuid-value</cbc:UUID>

  2. Implemented a mechanism to generate a unique UUID for each tax document submission

  3. Updated our XML signing process to maintain the correct structure and placement of all elements

I’m attaching a sample XML document that shows these changes. Could you please review it and confirm if the UUID placement is now correct?

Additionally, we’re still experiencing the following errors when submitting documents:

  • “The invoice hash API body does not match the (calculated) Hash of the XML”
  • “Invalid content was found starting with element ‘Signature’. One of ‘InvoiceLine’ is expected.”
  • “يجب ألا يتطابق رقم تسجيل ضريبة القيمة المضافة للبائع مع رقم تسجيل ضريبة القيمة المضافة للمشتري”

We’re working on addressing these issues as well. Any additional guidance would be greatly appreciated.

Thank you for your assistance.

Best regards,

Diyaa

| Aturkistani
April 30 |

  • | - |

dear @dalgindy ,

the UUID must be unique for each tax document submission, please ensure that the UUID is being placed in the correct tag, there are 2 tags with the name “UUID” inside the XML invoice, to make sure that the submitted tax XML doucment includes the “UUID” correctly, check on the following:

1- Navigate to xpather.com

2- paste the XML document as-is in the website

3- paste this value as-is in the xpath field:

/[local-name()=‘Invoice’]/[local-name()=‘UUID’]

4- check on the findings, then, you will have 2 scenraios:

  • First Scenario: you don’t find the correct UUID, that means the UUID value is placed inside the incorrect tag.
  • Second Scenario: You find teh UUID tag, then, please share the “dummy” XML invoice here to check.

Regards,

The invoice hash API body does not match the (calculated) Hash of the XML (Code: invalid-invoice-hash, Category: INVOICE_HASHING_ERRORS)