PHP SDK
Send invoices to Complyance from a PHP application: first a sample payload to build your mapping, then real invoices from the same source. You need PHP 7.4 or later, Composer and an API key.
Install
composer require io.complyance/unify-sdk:3.0.11Version 3.0.11 is a stable release. Run the command from your project directory, then load Composer’s autoloader in your code.
Configure the SDK
Configure the SDK once, when your application starts.
<?php
require __DIR__ . '/vendor/autoload.php';
use ComplyanceSDK\GETSUnifySDK;
use ComplyanceSDK\Models\SDKConfig;
use ComplyanceSDK\Enums\Environment;
$config = new SDKConfig(
getenv('COMPLYANCE_API_KEY'),
Environment::from(Environment::SANDBOX)
);
GETSUnifySDK::configure($config);
// The source this application sends as, and its version.
$sourceName = 'acme-erp';
$sourceVersion = '1.0';- The environment must match the key. Use
Environment::SANDBOXwith a sandbox key. When you go live, useEnvironment::PRODUCTIONwith a production key. $sourceNameand$sourceVersionname the source: the system that sends invoices to Complyance. Send the same pair in every call. When you go live, the source must be registered in your workspace. See Manage sources and their links.- Never write the key into your code. If
COMPLYANCE_API_KEYis not set, the SDK cannot send anything.
Send a sample payload for mapping
Your system has its own names for invoice fields. Before Complyance can turn your invoices into e-invoices, you build a mapping from your fields to GETS, the Complyance standard invoice format. To start, send one invoice as your system produces it, with the purpose MAPPING. Complyance stores it for mapping and does not validate it or send it anywhere.
use ComplyanceSDK\Enums\Country;
use ComplyanceSDK\Enums\Mode;
use ComplyanceSDK\Enums\Operation;
use ComplyanceSDK\Enums\Purpose;
use ComplyanceSDK\Models\GetsDocumentType;
// Your invoice, in your system's own field names.
$payload = [
'invoice_number' => 'INV-2026-0142',
'issue_date' => '2026-09-30',
'currency' => 'AED',
'seller' => ['name' => 'Acme Trading LLC', 'trn' => '100000000000003'],
'buyer' => ['name' => 'Gulf Office Supplies LLC', 'trn' => '100000000000017'],
'lines' => [
['description' => 'Office chair', 'quantity' => 10, 'unit_price' => 500.00, 'vat_rate' => 5],
],
'total' => 5250.00,
];
$documentType = GetsDocumentType::builder()
->base('tax_invoice')
->build();
$raw = GETSUnifySDK::pushToUnifyWithDocumentType(
$sourceName,
$sourceVersion,
$documentType,
Country::from(Country::AE),
Operation::from(Operation::SINGLE),
Mode::from(Mode::DOCUMENTS),
Purpose::from(Purpose::MAPPING),
$payload,
null,
true
);
$response = json_decode($raw, true);
echo $response['message'];The last argument, true, sends the request in the current Unify format, so the response matches the Unify API reference. Pass it in every call on this page.
You should see:
{
"message": "Payload saved for mapping."
}Next, open the Integration engine in the Developer portal and create an integration. At Payload Selection, choose the payload you sent. Map its fields, test the result, and link the integration to your source. See Create an integration and Map your fields to GETS.
Submit an invoice
Once the integration is tested and linked to your source, send invoices with the purpose INVOICING. Use the same source name and version, and the same payload shape you mapped. Complyance converts the invoice with your mapping, validates it, and continues delivery to the tax authority or the Peppol network.
$documentType = GetsDocumentType::builder()
->base('tax_invoice')
->build();
$raw = GETSUnifySDK::pushToUnifyWithDocumentType(
$sourceName,
$sourceVersion,
$documentType,
Country::from(Country::AE),
Operation::from(Operation::SINGLE),
Mode::from(Mode::DOCUMENTS),
Purpose::from(Purpose::INVOICING),
$payload,
null,
true
);
$response = json_decode($raw, true);
$documentId = $response['documentId'];
echo $response['message'];The document type is the GETS document type: a base such as tax_invoice or credit_note, plus modifiers that describe the transaction. For an export invoice, add ->modifiers(['export']) before ->build(). Modifiers can change which fields are required. The fields each combination needs are in the field reference.
You should see:
{
"documentId": "01K5EXAMPLE00000000000142",
"documentNumber": "INV-2026-0142",
"message": "Your invoice was validated and is ready for submission.",
"Base64XML": "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4…"
}The invoice passed validation and was stored. Save the documentId; you need it to check the status. Base64XML is the e-invoice that was produced, Base64-encoded. Every field is described in Submit and retrieve.
Run your invoices in sandbox, and through the testbed, until they pass. Then switch to a production key and Environment::PRODUCTION.
Check a document’s status
Delivery continues after the response. Follow it with the documentId:
$status = GETSUnifySDK::getDocumentStatus($documentId);
echo $status['data']['state'];{
"success": true,
"data": {
"documentId": "01K5EXAMPLE00000000000142",
"documentNumber": "INV-2026-0142",
"country": "AE",
"environment": "sandbox",
"state": "final_valid",
"isTerminal": true,
"errors": []
}
}While isTerminal is false, the invoice is still being processed, so check again later. final_valid means it was accepted as compliant. final_invalid or rejected means it was not; errors says why. To be told when the status changes instead of asking, use webhooks.
Retrieve purchase invoices
To read invoices your suppliers sent you, call the API directly with the same key: Get a purchase invoice by its documentId, or List purchase invoices for a date range, one page at a time.
Handle errors
When Complyance refuses a request, the call throws ComplyanceSDK\Exceptions\SDKException. Read the HTTP status and the response body from its error detail:
use ComplyanceSDK\Exceptions\SDKException;
try {
$raw = GETSUnifySDK::pushToUnifyWithDocumentType(/* as above */);
} catch (SDKException $e) {
$detail = $e->getErrorDetail();
$httpStatus = $detail->getContextValue('httpStatus');
$body = json_decode((string) $detail->getContextValue('responseBody'), true);
if ($httpStatus === 422) {
foreach ($body['errors'] ?? [] as $error) {
echo $error['payloadPath'] . ': ' . $error['message'] . "\n";
}
}
}The SDK retries rate limits and server errors on its own. If server errors continue while you submit an invoice, the call returns an object instead of a JSON string, and its getStatus() is queued: the invoice has not been validated yet, so do not record it as sent.
401: the API key is missing, invalid, revoked or expired. Check that COMPLYANCE_API_KEY is set where your application runs.
403: the key belongs to a different environment. Use a sandbox key with Environment::SANDBOX, and a production key with Environment::PRODUCTION.
422: the invoice failed validation. Each entry in errors names the field in your payload (payloadPath), the field in GETS (getsPath) and the rule it broke. Fix every one, then send the invoice again. With GETS-HEAD-010, the invoice number was already sent: use a new one.
Every status and what to do about it is in Errors.
Next, check which fields your invoices need in the field reference.
Last updated