Batch Invoice Upload (T129)
Upload multiple invoices in a single request to improve throughput and reduce network overhead. This endpoint wraps multiple T109 Invoice Upload payloads into a single encrypted batch request.
Endpoint Overview
| Property | Value |
|---|---|
| Interface Code | T129 |
| Request Encrypted | ✅ Yes |
| Response Encrypted | ✅ Yes |
| Request Body | Array of { invoiceContent, invoiceSignature } |
| Response Format | Array of { invoiceContent, invoiceReturnCode, invoiceReturnMessage } |
Flow Description
- Client constructs an array of invoice payloads (same structure as T109).
- Client signs each invoice payload individually.
- Client wraps payloads into a batch request (
invoiceContent+invoiceSignature). - Client sends encrypted batch request to server.
- Server processes each invoice independently.
- Server returns an array of results, where each item corresponds to the input invoice order.
- Client checks
invoiceReturnCodefor each item to identify successes or failures.
⚡ Performance Tip: Use batch upload for high-volume scenarios (e.g., end-of-day reconciliation, bulk imports). However, respect server limits on batch size to avoid timeouts.
- PHP
- JavaScript / TypeScript
- Python
try {
// Construct array of invoice payloads (same structure as T109)
$invoices = [
[
'sellerDetails' => [ /* ... */ ],
'basicInformation' => [ /* ... */ ],
'buyerDetails' => [ /* ... */ ],
'goodsDetails' => [ /* ... */ ],
'taxDetails' => [ /* ... */ ],
'summary' => [ /* ... */ ],
'payWay' => [ /* ... */ ]
],
// Add more invoices...
];
// Call T129: Batch Upload
$response = $client->fiscaliseBatchInvoices($invoices);
$results = $response['data']['content'] ?? $response;
if (is_array($results)) {
foreach ($results as $index => $result) {
$code = $result['invoiceReturnCode'] ?? '99';
$msg = $result['invoiceReturnMessage'] ?? 'Unknown';
if ($code === '00') {
echo "✅ Invoice #{$index} uploaded successfully\n";
} else {
echo "❌ Invoice #{$index} failed: {$code} - {$msg}\n";
}
}
}
} catch (\UraEfrisSdk\Exceptions\APIException $e) {
echo "❌ Batch upload failed: " . $e->getMessage() . "\n";
echo " Return Code: " . $e->getReturnCode() . "\n";
}
try {
// Construct array of invoice payloads (same structure as T109)
const invoices = [
{
sellerDetails: { /* ... */ },
basicInformation: { /* ... */ },
buyerDetails: { /* ... */ },
goodsDetails: [ /* ... */ ],
taxDetails: [ /* ... */ ],
summary: { /* ... */ },
payWay: [ /* ... */ ]
},
// Add more invoices...
];
// Call T129: Batch Upload
const response = await client.fiscaliseBatchInvoices(invoices);
const results = response?.data?.content ?? response;
if (Array.isArray(results)) {
results.forEach((result: any, index: number) => {
const code = result.invoiceReturnCode ?? '99';
const msg = result.invoiceReturnMessage ?? 'Unknown';
if (code === '00') {
console.log(`✅ Invoice #${index} uploaded successfully`);
} else {
console.error(`❌ Invoice #${index} failed: ${code} - ${msg}`);
}
});
}
} catch (error: any) {
console.error(`❌ Batch upload failed: ${error.message}`);
if (error.returnCode) {
console.error(` Return Code: ${error.returnCode}`);
}
throw error;
}
try:
# Construct array of invoice payloads (same structure as T109)
invoices = [
{
"sellerDetails": { /* ... */ },
"basicInformation": { /* ... */ },
"buyerDetails": { /* ... */ },
"goodsDetails": [ /* ... */ ],
"taxDetails": [ /* ... */ ],
"summary": { /* ... */ },
"payWay": [ /* ... */ ]
},
# Add more invoices...
]
# Call T129: Batch Upload
response = client.fiscalise_batch_invoices(invoices)
results = response.get("data", {}).get("content", response)
if isinstance(results, list):
for index, result in enumerate(results):
code = result.get("invoiceReturnCode", "99")
msg = result.get("invoiceReturnMessage", "Unknown")
if code == "00":
print(f"✅ Invoice #{index} uploaded successfully")
else:
print(f"❌ Invoice #{index} failed: {code} - {msg}")
except Exception as e:
print(f"❌ Batch upload failed: {e}")
if hasattr(e, "return_code"):
print(f" Return Code: {e.return_code}")
raise
Request Structure
{
"data": {
"content": "BASE64_ENCRYPTED_BATCH_PAYLOAD",
"signature": "JKQWJK34K32JJEK2JQWJ5678",
"dataDescription": {
"codeType": "1",
"encryptCode": "2",
"zipCode": "0"
}
},
"globalInfo": {
"interfaceCode": "T129",
"appId": "AP04",
"version": "1.1.20191201",
"tin": "1000029771",
"deviceNo": "TCS9e0df01728335239",
"taxpayerID": "1"
}
}
Inner Batch Payload (Decrypted)
[
{
"invoiceContent": "{ T109_REQUEST_JSON }",
"invoiceSignature": "SIGNATURE_FOR_INVOICE_1"
},
{
"invoiceContent": "{ T109_REQUEST_JSON }",
"invoiceSignature": "SIGNATURE_FOR_INVOICE_2"
}
]
Request Fields
| Field | Required | Type | Description |
|---|---|---|---|
invoiceContent | ✅ Yes | String | Plaintext JSON payload of a T109 Invoice Upload request |
invoiceSignature | ✅ Yes | String | Digital signature for the corresponding invoiceContent |
🔐 Note: The SDK handles the inner signing and outer encryption automatically. Users typically pass an array of invoice objects (same as T109) to the
fiscaliseBatchInvoicesmethod.
Response Structure
{
"data": {
"content": [
{
"invoiceContent": "{ T109_RESPONSE_JSON }",
"invoiceReturnCode": "00",
"invoiceReturnMessage": "SUCCESS"
},
{
"invoiceContent": "{ T109_RESPONSE_JSON }",
"invoiceReturnCode": "1040",
"invoiceReturnMessage": "Invoice number already exists"
}
]
},
"globalInfo": {
"interfaceCode": "T129",
"returnStateInfo": {
"returnCode": "00",
"returnMessage": "SUCCESS"
}
}
}
Response Fields
| Field | Required | Type | Description |
|---|---|---|---|
invoiceContent | ✅ Yes | String | Plaintext JSON payload of the T109 response (contains invoiceNo, qrCode, etc.) |
invoiceReturnCode | ✅ Yes | String | Individual invoice return code (e.g., 00, 1040, 1316) |
invoiceReturnMessage | ✅ Yes | String | Human-readable message for the individual invoice result |
Return Codes
Batch-Level Codes (Outer Envelope)
| Code | Message | Description |
|---|---|---|
00 | SUCCESS | Batch request processed successfully |
99 | Unknown error | Generic server error |
1610 | invoiceContent cannot be empty! | One or more batch items missing content |
1611 | invoiceSignature cannot be empty! | One or more batch items missing signature |
1612 | Invoice upload quantity cannot be greater than xx! | Batch size exceeds server limit |
1613 | Batch upload has problematic invoices... | Some invoices failed; check inner invoiceReturnCode |
Invoice-Level Codes (Inner invoiceReturnCode)
See T109 Return Codes for detailed invoice-specific errors.
| Code | Message | Description |
|---|---|---|
00 | SUCCESS | Individual invoice uploaded successfully |
1040 | Invoice number already exists | Duplicate invoice number detected |
1316 | goodsDetails-->total:Multiply the quantity... | Calculation error in goods details |
1342 | taxDetails-->:'netAmount' plus 'taxAmount'... | Tax calculation mismatch |
1600 | Inventory shortage | Insufficient stock for goods |
2075 | Invoice amount exceeds the maximum limit! | Exceeds maxGrossAmount from T103 |
💡 Tip: A batch request can return
00at the envelope level even if individual invoices fail. Always iterate through the response array and check eachinvoiceReturnCode.
Common Use Cases
-
High-Volume Retail
Upload end-of-day sales summaries or bulk transactions from POS systems in a single API call. -
Offline Sync
When reconnecting after offline mode, upload queued invoices in batches to reduce connection overhead. -
Data Migration
Migrate historical invoice data from legacy systems to EFRIS efficiently. -
Error Isolation
Identify specific failed invoices within a batch without halting the entire upload process.
Integration Checklist
✅ Validate each invoice payload (T109 structure) before adding to batch
✅ Ensure batch size does not exceed server limits (check return code 1612)
✅ Iterate through response array to handle partial failures
✅ Log individual invoiceReturnCode for audit trails
✅ Retry failed invoices individually (do not retry entire batch)