Certificate Public Key Upload (T136)
Upload a certificate public key to the EFRIS system for secure communication and signature verification. This endpoint allows taxpayers to register their certificate files (.crt or .cer format) with URA for authentication purposes. No encryption required for request or response.
Endpoint Overview
| Property | Value |
|---|---|
| Interface Code | T136 |
| Request Encrypted | ❌ No |
| Response Encrypted | ❌ No |
| Request Body | { "fileName": "...", "verifyString": "...", "fileContent": "..." } |
| Response Format | null |
Flow Description
- Client prepares certificate file in
.crtor.cerformat. - Client generates
verifyStringby encrypting filename using TIN (first 10 characters) +yymmddas AES key. - Client encodes certificate content as Base64 string.
- Client submits upload request to EFRIS server.
- Server validates certificate format, fingerprint, and verifyString.
- Server stores certificate for future signature verification.
🔐 Security Note: The
verifyStringmust match the encrypted filename using your TIN + date as the encryption key. Mismatched verifyString will result in rejection.
- PHP
- JavaScript / TypeScript
- Python
try {
// Read certificate file
$certPath = '/path/to/certificate.cer';
$certContent = file_get_contents($certPath);
$certBase64 = base64_encode($certContent);
// Generate verifyString (TIN first 10 + yymmdd as AES key)
$tin = $config['tin'] ?? '1000029771';
$datePart = date('ymd');
$aesKey = substr($tin, 0, 10) . $datePart;
$fileName = 'my_certificate.cer';
$verifyString = hash('md5', $aesKey . $fileName);
// Call T136: Certificate Upload
$response = $client->certificateUpload(
fileName: $fileName,
verifyString: $verifyString,
fileContent: $certBase64
);
echo "✅ Certificate uploaded successfully\n";
echo " File: {$fileName}\n";
} catch (\UraEfrisSdk\Exceptions\APIException $e) {
echo "❌ Upload failed: " . $e->getMessage() . "\n";
echo " Return Code: " . $e->getReturnCode() . "\n";
}
import * as fs from 'fs';
import * as crypto from 'crypto';
try {
// Read certificate file
const certPath = '/path/to/certificate.cer';
const certContent = fs.readFileSync(certPath);
const certBase64 = certContent.toString('base64');
// Generate verifyString (TIN first 10 + yymmdd as AES key)
const tin = config.tin ?? '1000029771';
const datePart = new Date().toISOString().slice(2, 8).replace(/-/g, '');
const aesKey = tin.substring(0, 10) + datePart;
const fileName = 'my_certificate.cer';
const verifyString = crypto
.createHash('md5')
.update(aesKey + fileName)
.digest('hex');
// Call T136: Certificate Upload
await client.certificateUpload(
fileName,
verifyString,
certBase64
);
console.log('✅ Certificate uploaded successfully');
console.log(` File: ${fileName}`);
} catch (error: any) {
console.error(`❌ Upload failed: ${error.message}`);
if (error.returnCode) {
console.error(` Return Code: ${error.returnCode}`);
}
throw error;
}
import base64
import hashlib
from datetime import datetime
try:
# Read certificate file
cert_path = '/path/to/certificate.cer'
with open(cert_path, 'rb') as f:
cert_content = f.read()
cert_base64 = base64.b64encode(cert_content).decode('utf-8')
# Generate verifyString (TIN first 10 + yymmdd as AES key)
tin = config.get("tin", "1000029771")
date_part = datetime.now().strftime('%y%m%d')
aes_key = tin[:10] + date_part
file_name = 'my_certificate.cer'
verify_string = hashlib.md5((aes_key + file_name).encode()).hexdigest()
# Call T136: Certificate Upload
client.certificate_upload(
file_name=file_name,
verify_string=verify_string,
file_content=cert_base64
)
print("✅ Certificate uploaded successfully")
print(f" File: {file_name}")
except Exception as e:
print(f"❌ Upload failed: {e}")
if hasattr(e, "return_code"):
print(f" Return Code: {e.return_code}")
raise
Request Structure
{
"data": {
"content": "",
"signature": "",
"dataDescription": {
"codeType": "0",
"encryptCode": "0",
"zipCode": "0"
}
},
"globalInfo": {
"appId": "AP04",
"version": "1.1.20191201",
"dataExchangeId": "9230489223014123",
"interfaceCode": "T136",
"requestCode": "TP",
"requestTime": "2025-02-19 10:00:00",
"responseCode": "TA",
"userName": "admin",
"deviceMAC": "FFFFFFFFFFFF",
"deviceNo": "TCS9e0df01728335239",
"tin": "1000029771",
"taxpayerID": "1"
}
}
Request Payload (Unencrypted)
{
"fileName": "Certum Trusted NetWork CA 2.cer",
"verifyString": "MDQwNDAxMDcxNVowMzELMAkGA1UEBhMCRU4x",
"fileContent": "MIIDFjCCAf6gAwIBAgIRAKPGAol9CEdpkIoFa8huM6zfj1WEBRxteoo6PH46un4FGj4N6ioIGzVr9G40uhQGdm16ZU+q44XjW2oUnI9w="
}
Response Structure
null
✅ A successful request returns
null. Any errors will be thrown as exceptions with return codes.
Request Fields
| Field | Required | Type | Length | Description |
|---|---|---|---|---|
fileName | ✅ Yes | String | ≤256 | Certificate filename. Must be in .crt or .cer format |
verifyString | ✅ Yes | String | Unlimited | Encrypted filename hash. Generated using TIN (first 10 chars) + yymmdd as AES key |
fileContent | ✅ Yes | String | Unlimited | Certificate file content encoded as Base64 string |
verifyString Generation
verifyString = MD5(TIN[0:10] + yymmdd + fileName)
Example:
- TIN:
1000029771 - Date:
2025-02-19→250219 - AES Key:
1000029771+250219=1000029771250219 - fileName:
my_cert.cer - verifyString:
MD5("1000029771250219my_cert.cer")
Return Codes
| Code | Message | Description |
|---|---|---|
00 | SUCCESS | Certificate uploaded successfully |
99 | Unknown error | Generic server error |
2093 | FileName cannot be empty | Missing filename in request |
2094 | FileName:Byte length cannot be greater than 256! | Filename too long |
2095 | FileContent cannot be empty! | Missing certificate content |
2096 | VerifyString cannot be empty! | Missing verifyString |
2097 | Filename and decryption verifystring must be equal! | verifyString does not match encrypted filename |
2098 | Certificate overdue! | Certificate has expired |
2099 | Duplicate certificate! | Certificate already registered |
2100 | Certificate resolution error! | Invalid certificate format or corrupted file |
2178 | Encryption type does not match! | Encryption algorithm mismatch |
2179 | The key length of the public key should be 2048! | Certificate key must be 2048-bit RSA |
2200 | The certificate has no matching fingerprint. Please upload the fingerprint to tax office first! | Certificate fingerprint not registered with URA |
💡 Tip: Before uploading, ensure your certificate fingerprint is registered with your tax office. Contact URA support if you receive code
2200.
Common Use Cases
-
Initial System Setup
Register your organization's public key certificate during EFRIS integration setup. -
Certificate Renewal
Upload updated certificates before existing ones expire to maintain continuous operation. -
Multi-Device Configuration
Register certificates for multiple fiscal devices under the same taxpayer account. -
Security Audit Compliance
Maintain up-to-date certificates to meet URA security requirements and audit standards. -
Key Rotation
Replace compromised or weak certificates with new 2048-bit RSA certificates.
Integration Checklist
✅ Ensure certificate is in .crt or .cer format
✅ Verify certificate uses 2048-bit RSA key
✅ Generate verifyString using correct TIN + date algorithm
✅ Encode certificate content as Base64 (no line breaks)
✅ Register certificate fingerprint with tax office before upload
✅ Test upload in sandbox environment before production
✅ Store certificate expiry date and set renewal reminders