Send your first invoice

Submit a UAE tax invoice to sandbox with one API request, then check its status. You need a sandbox API key and the source your invoices come from.

Set your key

Set your keybash
export COMPLYANCE_API_KEY='paste-your-sandbox-key'

The examples on this page read the key from COMPLYANCE_API_KEY, so it never appears in your code.

Save the invoice

Save this request body as invoice.json:

invoice.jsonjson
{
  "country": "AE",
  "environment": "sandbox",
  "purpose": "invoicing",
  "source": "acme-erp:1.0.0",
  "documentType": {
    "base": "tax_invoice",
    "modifiers": []
  },
  "payload": {
    "header": {
      "documentType": {
        "base": "tax_invoice"
      },
      "documentNumber": "INV-2026-000184",
      "issueDate": "2026-09-18",
      "currency": "AED",
      "dueDate": "2026-10-18"
    },
    "parties": {
      "seller": {
        "name": "Acme Trading LLC",
        "address": {
          "country": "AE",
          "city": "Dubai",
          "addressLine1": "12 Harbour Road",
          "stateOrProvince": "Dubai"
        },
        "taxIds": [
          {
            "type": "VAT",
            "value": "100012345600003"
          }
        ],
        "registrationNumbers": [
          {
            "type": "CRN",
            "value": "CN-1234567"
          }
        ],
        "peppolId": "100012345600003"
      },
      "buyer": {
        "name": "Gulf Retail FZ-LLC",
        "address": {
          "country": "AE",
          "addressLine1": "48 Market Street",
          "city": "Dubai",
          "stateOrProvince": "Dubai"
        },
        "taxIds": [
          {
            "type": "VAT",
            "value": "100012345600004"
          }
        ],
        "peppolId": "100012345600004"
      }
    },
    "lineItems": [
      {
        "id": "1",
        "name": "Cloud subscription — Business plan",
        "quantity": 20,
        "unitCode": "PCE",
        "taxAmount": 100,
        "lineTaxableValue": 2000,
        "taxCategory": "S",
        "taxRate": 5,
        "price": {
          "amount": 100,
          "grossPrice": 100
        }
      }
    ],
    "payment": {
      "paymentMeans": [
        {
          "paymentMeansCode": "PAYMENT_TO_BANK_ACCOUNT"
        }
      ]
    },
    "totals": {
      "totalAmountExcludingTax": 2000,
      "totalAmountIncludingTax": 2100,
      "amountDue": 2100,
      "totalLineTaxableAmount": 2000,
      "totalTaxAmount": 100
    },
    "extensions": {
      "peppol_seller_peppolIdScheme": "0235",
      "peppol_buyer_peppolIdScheme": "0235"
    }
  }
}

Change two values before you send it:

  • source: your own source. The sample acme-erp:1.0.0 is not in your workspace.
  • documentNumber: a number you have not sent before.

environment must match your key, so keep sandbox with a sandbox key. country and documentType decide which payload fields are required. The payload is the invoice itself, in GETS, the Complyance standard invoice format.

Send it

Submit the invoicebash
curl --request POST 'https://prod.gets.complyance.io/api/v3/unify' \
  --header "Authorization: Bearer ${COMPLYANCE_API_KEY}" \
  --header 'Content-Type: application/json' \
  --header 'Accept: application/json' \
  --header 'new-api: true' \
  --data @invoice.json

Send new-api: true with every submission. Without it, the request is read in the earlier format.

To try it in your browser first, open Submit a document in the API playground. It builds this request for any country and sends it to sandbox.

Read the response

You should see HTTP 200:

Invoice validated — HTTP 200json
{
  "documentId": "01K5EXAMPLE00000000000142",
  "documentNumber": "INV-2026-000184",
  "message": "Your invoice was validated and is ready for submission.",
  "Base64XML": "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4…"
}

200 means the invoice passed validation and was stored. Delivery to the tax authority or the Peppol network continues after the response. Base64XML is the e-invoice that was produced, Base64-encoded.

Save the documentId. You need it to check the status.

Check the status

Check the statusbash
export DOCUMENT_ID='01K5EXAMPLE00000000000142'

curl "https://prod.gets.complyance.io/api/v3/documents/${DOCUMENT_ID}?type=sales" \
  --header "Authorization: Bearer ${COMPLYANCE_API_KEY}" \
  --header 'Accept: application/json'
Invoice accepted — HTTP 200json
{
  "success": true,
  "data": {
    "documentId": "01K5EXAMPLE00000000000142",
    "documentNumber": "INV-2026-000184",
    "country": "AE",
    "environment": "sandbox",
    "state": "final_valid",
    "isTerminal": true,
    "lastUpdatedAt": "2026-09-22T10:00:04.000Z",
    "errors": [],
    "government": {
      "status": "APPROVED"
    },
    "validationResults": {
      "status": "Valid",
      "validationSteps": [
        {
          "name": "schema",
          "status": "Valid",
          "error": null
        }
      ]
    }
  }
}

While isTerminal is false, the invoice is still being processed, so check again later. final_valid means it was accepted as compliant. In the Invoice Portal, it shows as Compliant.

If something goes wrong

401 with {"error": "Unauthorized"}: the key is missing, invalid, revoked or expired. Check that COMPLYANCE_API_KEY is set in the shell you send from.

403 with permission_denied: the key belongs to a different environment from environment. Use a sandbox key with sandbox.

404: the source is not in your workspace. Check its name and version.

422 with GETS-HEAD-010: the documentNumber was already sent. Change it and send the invoice again.

Any other 422: the invoice failed validation. Each entry in errors names the field in GETS (getsPath) and in your request (payloadPath), and the rule it broke. Fix the field, then send the invoice again with a new documentNumber.

Next step

See which fields your own invoices need in the field reference. Each country’s guide then covers its onboarding, rules and examples: United Arab Emirates, Saudi Arabia, Malaysia, Oman, Belgium and Germany.

Last updated