curl --request POST \
--url https://api.invopop.com/apps/gov-sa/v1/entry/{silo_entry_id}/otp \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"invoice_type": "1100",
"branch_name": "Head Office",
"business_category": "Retail",
"otp": "123456"
}
'import requests
url = "https://api.invopop.com/apps/gov-sa/v1/entry/{silo_entry_id}/otp"
payload = {
"invoice_type": "1100",
"branch_name": "Head Office",
"business_category": "Retail",
"otp": "123456"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
invoice_type: '1100',
branch_name: 'Head Office',
business_category: 'Retail',
otp: '123456'
})
};
fetch('https://api.invopop.com/apps/gov-sa/v1/entry/{silo_entry_id}/otp', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.invopop.com/apps/gov-sa/v1/entry/{silo_entry_id}/otp",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'invoice_type' => '1100',
'branch_name' => 'Head Office',
'business_category' => 'Retail',
'otp' => '123456'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.invopop.com/apps/gov-sa/v1/entry/{silo_entry_id}/otp"
payload := strings.NewReader("{\n \"invoice_type\": \"1100\",\n \"branch_name\": \"Head Office\",\n \"business_category\": \"Retail\",\n \"otp\": \"123456\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.invopop.com/apps/gov-sa/v1/entry/{silo_entry_id}/otp")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"invoice_type\": \"1100\",\n \"branch_name\": \"Head Office\",\n \"business_category\": \"Retail\",\n \"otp\": \"123456\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.invopop.com/apps/gov-sa/v1/entry/{silo_entry_id}/otp")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"invoice_type\": \"1100\",\n \"branch_name\": \"Head Office\",\n \"business_category\": \"Retail\",\n \"otp\": \"123456\"\n}"
response = http.request(request)
puts response.read_body{
"error": "invalid OTP"
}{
"error": "missing enrollment"
}{
"error": "access denied"
}{
"error": "no registration for this silo entry, run gov-sa.register first"
}{
"error": "party is already registered"
}{
"error": "requesting compliance CSID"
}{
"error": "internal server error"
}Submit OTP
Submit the One Time Password (OTP) generated in the ZATCA Fatoora portal.
curl --request POST \
--url https://api.invopop.com/apps/gov-sa/v1/entry/{silo_entry_id}/otp \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"invoice_type": "1100",
"branch_name": "Head Office",
"business_category": "Retail",
"otp": "123456"
}
'import requests
url = "https://api.invopop.com/apps/gov-sa/v1/entry/{silo_entry_id}/otp"
payload = {
"invoice_type": "1100",
"branch_name": "Head Office",
"business_category": "Retail",
"otp": "123456"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
invoice_type: '1100',
branch_name: 'Head Office',
business_category: 'Retail',
otp: '123456'
})
};
fetch('https://api.invopop.com/apps/gov-sa/v1/entry/{silo_entry_id}/otp', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.invopop.com/apps/gov-sa/v1/entry/{silo_entry_id}/otp",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'invoice_type' => '1100',
'branch_name' => 'Head Office',
'business_category' => 'Retail',
'otp' => '123456'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.invopop.com/apps/gov-sa/v1/entry/{silo_entry_id}/otp"
payload := strings.NewReader("{\n \"invoice_type\": \"1100\",\n \"branch_name\": \"Head Office\",\n \"business_category\": \"Retail\",\n \"otp\": \"123456\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.invopop.com/apps/gov-sa/v1/entry/{silo_entry_id}/otp")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"invoice_type\": \"1100\",\n \"branch_name\": \"Head Office\",\n \"business_category\": \"Retail\",\n \"otp\": \"123456\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.invopop.com/apps/gov-sa/v1/entry/{silo_entry_id}/otp")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"invoice_type\": \"1100\",\n \"branch_name\": \"Head Office\",\n \"business_category\": \"Retail\",\n \"otp\": \"123456\"\n}"
response = http.request(request)
puts response.read_body{
"error": "invalid OTP"
}{
"error": "missing enrollment"
}{
"error": "access denied"
}{
"error": "no registration for this silo entry, run gov-sa.register first"
}{
"error": "party is already registered"
}{
"error": "requesting compliance CSID"
}{
"error": "internal server error"
}org.Party silo entry, which Register Party validates before publishing the onboarding link. The resulting credentials are stored securely and the queued registration task is poked so the workflow can continue.
404 when the silo entry has no registration and 409 when the party already holds a Compliance CSID, rather than issuing a second set of certificates. The OTP is short-lived, so generate it in the portal immediately before calling this endpoint.Authorizations
Authenticate using a valid Invopop enrollment token in the Bearer
scheme.
Example: Authorization: Bearer <token>
Path Parameters
ID of the org.Party silo entry being onboarded.
"5b45453c-cdd0-11ed-afa1-0242ac120002"
Body
Which invoice transactions the CSID is requested for, encoded as ZATCA's 4-digit functionality map.
1000— standard tax invoices only.0100— simplified invoices only.1100— both standard and simplified invoices.
1000, 0100, 1100 "1100"
Name of the branch or organizational unit the certificate is issued for. In case of VAT Groups, this field should contain the 10-digit TIN number of the individual group member.
"Head Office"
Business category or industry of the supplier.
"Retail"
6-digit One-Time Password generated in the ZATCA Fatoora portal for the registering device. Valid only for a short period.
"123456"
Response
OTP accepted, Compliance CSID obtained and credentials stored.
Was this page helpful?