Sample code for 30+ languages & platforms
Tcl

Create ITIDA Signed JSON and Send to ETA (Egypt Tax Authority) Portal

See more Egypt ITIDA Examples

Demonstrates how to create a .p7s signature that fits Egypt's ITIDA requirements where Chilkat automatically does the ITIDA JSON canonicalization. Also shows the code to send to the ETA Portal.

Chilkat Tcl Downloads

Tcl

load ./chilkat.dll

set success 0

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

set crypt [new_CkCrypt2]

CkCrypt2_put_VerboseLogging $crypt 1

set cert [new_CkCert]

CkCert_put_VerboseLogging $cert 1

# Set the smart card PIN, which will be needed for signing.
CkCert_put_SmartCardPin $cert "12345678"

# There are many ways to load the certificate.  
# This example was created for a customer using an ePass2003 USB token.
# Assuming the USB token is the only source of a hardware-based private key..
set success [CkCert_LoadFromSmartcard $cert ""]
if {$success == 0} then {
    puts [CkCert_lastErrorText $cert]
    delete_CkCrypt2 $crypt
    delete_CkCert $cert
    exit
}

# Tell the crypt class to use this cert.
set success [CkCrypt2_SetSigningCert $crypt $cert]
if {$success == 0} then {
    puts [CkCrypt2_lastErrorText $crypt]
    delete_CkCrypt2 $crypt
    delete_CkCert $cert
    exit
}

set cmsOptions [new_CkJsonObject]

# Setting "DigestData" causes OID 1.2.840.113549.1.7.5 (digestData) to be used.
CkJsonObject_UpdateBool $cmsOptions "DigestData" 1
CkJsonObject_UpdateBool $cmsOptions "OmitAlgorithmIdNull" 1

# Indicate that we are passing normal JSON and we want Chilkat do automatically
# do the ITIDA JSON canonicalization:
CkJsonObject_UpdateBool $cmsOptions "CanonicalizeITIDA" 1

CkCrypt2_put_CmsOptions $crypt [CkJsonObject_emit $cmsOptions]

# The CadesEnabled property applies to all methods that create CMS/PKCS7 signatures. 
# To create a CAdES-BES signature, set this property equal to true. 
CkCrypt2_put_CadesEnabled $crypt 1

CkCrypt2_put_HashAlgorithm $crypt "sha256"

set jsonSigningAttrs [new_CkJsonObject]

CkJsonObject_UpdateInt $jsonSigningAttrs "contentType" 1
CkJsonObject_UpdateInt $jsonSigningAttrs "signingTime" 1
CkJsonObject_UpdateInt $jsonSigningAttrs "messageDigest" 1
CkJsonObject_UpdateInt $jsonSigningAttrs "signingCertificateV2" 1
CkCrypt2_put_SigningAttributes $crypt [CkJsonObject_emit $jsonSigningAttrs]

# By default, all the certs in the chain of authentication are included in the signature.
# If desired, we can choose to only include the signing certificate:
CkCrypt2_put_IncludeCertChain $crypt 0

# Pass a JSON document such as the following.  Chilkat will do the ITIDA canonicalization.
# (It is the canonicalized JSON that gets signed.)

#       {
#          "issuer":{
#             "address":{
#                "branchID":"0",
#                "country":"EG",
#                "regionCity":"Cairo",
#                "postalCode":"",
#                "buildingNumber":"0",
#                "street":"123rd Street",
#                "governate":"GOVERNATE"
#             },
#             "type":"B",
#             "id":"209999899",
#             "name":"Xyz SAE"
#          },
#          "receiver":{
#             "address":{
#                "country":"EG",
#                "regionCity":"CAIRO",
#                "postalCode":"11435",
#                "buildingNumber":"0",
#                "street":"Autostrad Road Abc",
#                "governate":"GOVERNATE"
#             },
#             "type":"B",
#             "id":"999999999",
#             "name":"XYZ EGYPT FOR TRADE"
#          },
#          "documentType":"I",
#          "documentTypeVersion":"1.0",
#          "dateTimeIssued":"2020-11-15T11:04:53Z",
#          "taxpayerActivityCode":"1073",
#          "internalID":"ZZZZ999",
#          "purchaseOrderReference":"2009199918",
#          "salesOrderReference":"",
#          "payment":{
#             "bankName":"",
#             "bankAddress":"",
#             "bankAccountNo":"",
#             "bankAccountIBAN":"",
#             "swiftCode":"",
#             "terms":""
#          },
#          "delivery":{
#             "approach":"",
#             "packaging":"",
#             "dateValidity":"",
#             "exportPort":"",
#             "countryOfOrigin":"EG",
#             "grossWeight":0,
#             "netWeight":0,
#             "terms":""
#          },
#          "invoiceLines":[
#             {
#                "description":"CDM Widget 48GX99X12BA",
#                "itemType":"GS1",
#                "itemCode":"7622213335056",
#                "unitType":"CS",
#                "quantity":1.00,
#                "unitValue":{
#                   "currencySold":"EGP",
#                   "amountEGP":588.67,
#                   "amountSold":0,
#                   "currencyExchangeRate":0
#                },
#                "salesTotal":588.67,
#                "total":603.97,
#                "valueDifference":0,
#                "totalTaxableFees":0,
#                "netTotal":529.8,
#                "itemsDiscount":0,
#                "discount":{
#                   "rate":10.00,
#                   "amount":58.87
#                },
#                "taxableItems":[
#                   {
#                      "taxType":"T1",
#                      "amount":74.17,
#                      "subType":"No sub",
#                      "rate":14.00
#                   }
#                ],
#                "internalCode":"9099994"
#             }
#          ],
#          "totalSales":588.67,
#          "totalSalesAmount":588.67,
#          "totalDiscountAmount":58.87,
#          "netAmount":529.80,
#          "taxTotals":[
#             {
#                "taxType":"T1",
#                "amount":74.17
#             }
#          ],
#          "extraDiscountAmount":0,
#          "totalItemsDiscountAmount":0,
#          "totalAmount":603.97,
#       }

# Build the above JSON..

# Use this online tool to generate code from sample JSON: 
# Generate Code to Create JSON

set json [new_CkJsonObject]

CkJsonObject_UpdateString $json "issuer.address.branchID" "0"
CkJsonObject_UpdateString $json "issuer.address.country" "EG"
CkJsonObject_UpdateString $json "issuer.address.regionCity" "Cairo"
CkJsonObject_UpdateString $json "issuer.address.postalCode" ""
CkJsonObject_UpdateString $json "issuer.address.buildingNumber" "0"
CkJsonObject_UpdateString $json "issuer.address.street" "123rd Street"
CkJsonObject_UpdateString $json "issuer.address.governate" "GOVERNATE"
CkJsonObject_UpdateString $json "issuer.type" "B"
CkJsonObject_UpdateString $json "issuer.id" "209999899"
CkJsonObject_UpdateString $json "issuer.name" "Xyz SAE"
CkJsonObject_UpdateString $json "receiver.address.country" "EG"
CkJsonObject_UpdateString $json "receiver.address.regionCity" "CAIRO"
CkJsonObject_UpdateString $json "receiver.address.postalCode" "11435"
CkJsonObject_UpdateString $json "receiver.address.buildingNumber" "0"
CkJsonObject_UpdateString $json "receiver.address.street" "Autostrad Road Abc"
CkJsonObject_UpdateString $json "receiver.address.governate" "GOVERNATE"
CkJsonObject_UpdateString $json "receiver.type" "B"
CkJsonObject_UpdateString $json "receiver.id" "999999999"
CkJsonObject_UpdateString $json "receiver.name" "XYZ EGYPT FOR TRADE"
CkJsonObject_UpdateString $json "documentType" "I"
CkJsonObject_UpdateString $json "documentTypeVersion" "1.0"
CkJsonObject_UpdateString $json "dateTimeIssued" "2020-11-15T11:04:53Z"
CkJsonObject_UpdateString $json "taxpayerActivityCode" "1073"
CkJsonObject_UpdateString $json "internalID" "ZZZZ999"
CkJsonObject_UpdateString $json "purchaseOrderReference" "2009199918"
CkJsonObject_UpdateString $json "salesOrderReference" ""
CkJsonObject_UpdateString $json "payment.bankName" ""
CkJsonObject_UpdateString $json "payment.bankAddress" ""
CkJsonObject_UpdateString $json "payment.bankAccountNo" ""
CkJsonObject_UpdateString $json "payment.bankAccountIBAN" ""
CkJsonObject_UpdateString $json "payment.swiftCode" ""
CkJsonObject_UpdateString $json "payment.terms" ""
CkJsonObject_UpdateString $json "delivery.approach" ""
CkJsonObject_UpdateString $json "delivery.packaging" ""
CkJsonObject_UpdateString $json "delivery.dateValidity" ""
CkJsonObject_UpdateString $json "delivery.exportPort" ""
CkJsonObject_UpdateString $json "delivery.countryOfOrigin" "EG"
CkJsonObject_UpdateInt $json "delivery.grossWeight" 0
CkJsonObject_UpdateInt $json "delivery.netWeight" 0
CkJsonObject_UpdateString $json "delivery.terms" ""
CkJsonObject_UpdateString $json "invoiceLines[0].description" "CDM Widget 48GX99X12BA"
CkJsonObject_UpdateString $json "invoiceLines[0].itemType" "GS1"
CkJsonObject_UpdateString $json "invoiceLines[0].itemCode" "7622213335056"
CkJsonObject_UpdateString $json "invoiceLines[0].unitType" "CS"
CkJsonObject_UpdateNumber $json "invoiceLines[0].quantity" "1.00"
CkJsonObject_UpdateString $json "invoiceLines[0].unitValue.currencySold" "EGP"
CkJsonObject_UpdateNumber $json "invoiceLines[0].unitValue.amountEGP" "588.67"
CkJsonObject_UpdateInt $json "invoiceLines[0].unitValue.amountSold" 0
CkJsonObject_UpdateInt $json "invoiceLines[0].unitValue.currencyExchangeRate" 0
CkJsonObject_UpdateNumber $json "invoiceLines[0].salesTotal" "588.67"
CkJsonObject_UpdateNumber $json "invoiceLines[0].total" "603.97"
CkJsonObject_UpdateInt $json "invoiceLines[0].valueDifference" 0
CkJsonObject_UpdateInt $json "invoiceLines[0].totalTaxableFees" 0
CkJsonObject_UpdateNumber $json "invoiceLines[0].netTotal" "529.8"
CkJsonObject_UpdateInt $json "invoiceLines[0].itemsDiscount" 0
CkJsonObject_UpdateNumber $json "invoiceLines[0].discount.rate" "10.00"
CkJsonObject_UpdateNumber $json "invoiceLines[0].discount.amount" "58.87"
CkJsonObject_UpdateString $json "invoiceLines[0].taxableItems[0].taxType" "T1"
CkJsonObject_UpdateNumber $json "invoiceLines[0].taxableItems[0].amount" "74.17"
CkJsonObject_UpdateString $json "invoiceLines[0].taxableItems[0].subType" "No sub"
CkJsonObject_UpdateNumber $json "invoiceLines[0].taxableItems[0].rate" "14.00"
CkJsonObject_UpdateString $json "invoiceLines[0].internalCode" "9099994"
CkJsonObject_UpdateNumber $json "totalSales" "588.67"
CkJsonObject_UpdateNumber $json "totalSalesAmount" "588.67"
CkJsonObject_UpdateNumber $json "totalDiscountAmount" "58.87"
CkJsonObject_UpdateNumber $json "netAmount" "529.80"
CkJsonObject_UpdateString $json "taxTotals[0].taxType" "T1"
CkJsonObject_UpdateNumber $json "taxTotals[0].amount" "74.17"
CkJsonObject_UpdateInt $json "extraDiscountAmount" 0
CkJsonObject_UpdateInt $json "totalItemsDiscountAmount" 0
CkJsonObject_UpdateNumber $json "totalAmount" "603.97"

CkJsonObject_put_EmitCompact $json 1
set jsonToSign [CkJsonObject_emit $json]

# Create the CAdES-BES signature.
CkCrypt2_put_EncodingMode $crypt "base64"

# Make sure we sign the utf-8 byte representation of the JSON string
CkCrypt2_put_Charset $crypt "utf-8"

set sigBase64 [CkCrypt2_signStringENC $crypt $jsonToSign]
if {[CkCrypt2_get_LastMethodSuccess $crypt] == 0} then {
    puts [CkCrypt2_lastErrorText $crypt]
    delete_CkCrypt2 $crypt
    delete_CkCert $cert
    delete_CkJsonObject $cmsOptions
    delete_CkJsonObject $jsonSigningAttrs
    delete_CkJsonObject $json
    exit
}

puts "Base64 signature:"
puts "$sigBase64"

# Insert the base64 signature into the JSON to be sent
CkJsonObject_UpdateString $json "signatures[0].signatureType" "I"
CkJsonObject_UpdateString $json "signatures[0].value" $sigBase64

# Wrap the JSON in  {"documents":[ ... ]}
set sbToSend [new_CkStringBuilder]

CkStringBuilder_Append $sbToSend "{\"documents\":["
CkStringBuilder_Append $sbToSend [CkJsonObject_emit $json]
CkStringBuilder_Append $sbToSend "]}"

# ------------------------------------------------------------------------
# Get an access token using our client ID and client secret key
set clientId "abc999ff-1234"
set clientSecretKey "123fff22-1234-abcd"

set http [new_CkHttp]

# Causes the Authorization: Basic header to be added..
CkHttp_put_Login $http $clientId
CkHttp_put_Password $http $clientSecretKey
CkHttp_put_BasicAuth $http 1

set req [new_CkHttpRequest]

CkHttpRequest_put_HttpVerb $req "POST"
CkHttpRequest_put_Path $req "/connect/token"
CkHttpRequest_put_ContentType $req "application/x-www-form-urlencoded"
CkHttpRequest_AddParam $req "grant_type" "client_credentials"
CkHttpRequest_AddHeader $req "Connection" "close"

CkHttp_put_Accept $http "application/json"

set resp [new_CkHttpResponse]

set success [CkHttp_HttpReq $http "https://id.preprod.eta.gov.eg/connect/token" $req $resp]
if {$success == 0} then {
    puts [CkHttp_lastErrorText $http]
    delete_CkCrypt2 $crypt
    delete_CkCert $cert
    delete_CkJsonObject $cmsOptions
    delete_CkJsonObject $jsonSigningAttrs
    delete_CkJsonObject $json
    delete_CkStringBuilder $sbToSend
    delete_CkHttp $http
    delete_CkHttpRequest $req
    delete_CkHttpResponse $resp
    exit
}

CkHttp_CloseAllConnections $http

puts "Response status code: [CkHttpResponse_get_StatusCode $resp]"
puts "Response body:"
puts [CkHttpResponse_bodyStr $resp]

if {[CkHttpResponse_get_StatusCode $resp] != 200} then {
    puts "Failed."
    delete_CkCrypt2 $crypt
    delete_CkCert $cert
    delete_CkJsonObject $cmsOptions
    delete_CkJsonObject $jsonSigningAttrs
    delete_CkJsonObject $json
    delete_CkStringBuilder $sbToSend
    delete_CkHttp $http
    delete_CkHttpRequest $req
    delete_CkHttpResponse $resp
    exit
}

set jsonToken [new_CkJsonObject]

set success [CkJsonObject_Load $jsonToken [CkHttpResponse_bodyStr $resp]]

set accessToken [CkJsonObject_stringOf $jsonToken "access_token"]
puts "access_token = $accessToken"

# ------------------------------------------------------------------------
# Submit the signed JSON to the ETA (Egypt Tax Authority) Portal

# No longer sending basic authentication...
CkHttp_put_Login $http ""
CkHttp_put_Password $http ""
CkHttp_put_BasicAuth $http 0

# Setting the AuthToken property causes the "Authorization: Bearer <token>" header to be added to each request.
CkHttp_put_AuthToken $http $accessToken

set jsonStr [CkStringBuilder_getAsString $sbToSend]
set url "https://api.preprod.invoicing.eta.gov.eg/api/v1/documentsubmissions"
set success [CkHttp_HttpStr $http "POST" $url $jsonStr "utf-8" "application/json; charset=utf-8" $resp]
if {$success == 0} then {
    puts [CkHttp_lastErrorText $http]
    delete_CkCrypt2 $crypt
    delete_CkCert $cert
    delete_CkJsonObject $cmsOptions
    delete_CkJsonObject $jsonSigningAttrs
    delete_CkJsonObject $json
    delete_CkStringBuilder $sbToSend
    delete_CkHttp $http
    delete_CkHttpRequest $req
    delete_CkHttpResponse $resp
    delete_CkJsonObject $jsonToken
    exit
}

puts "Response status code: [CkHttpResponse_get_StatusCode $resp]"
puts "Response body:"
puts [CkHttpResponse_bodyStr $resp]

delete_CkCrypt2 $crypt
delete_CkCert $cert
delete_CkJsonObject $cmsOptions
delete_CkJsonObject $jsonSigningAttrs
delete_CkJsonObject $json
delete_CkStringBuilder $sbToSend
delete_CkHttp $http
delete_CkHttpRequest $req
delete_CkHttpResponse $resp
delete_CkJsonObject $jsonToken