EGS Units
EGS (E-Invoicing Generation Solution) units represent a single device or branch that issues invoices. Each unit is created in either sandbox or production (based on your account at creation time). Sandbox units only submit to ZATCA sandbox; production units only to ZATCA production. Create a unit to start onboarding: Phase 1 (simplified only) or Phase 2 (full). After compliance check, request production CSID with the ZATCA OTP. Use the returned egs_unit_id in invoice requests (or set it as the default on an API key). Status response includes environment (sandbox | production). EGS units cannot be deleted: they are registered with ZATCA and linked to invoice history for compliance and audit. Sandbox and production EGS units have separate quotas per plan (e.g. Solo: 5 sandbox + 1 production), so using your sandbox quota does not block creating production units.
Create EGS unit
Creates an EGS unit and starts async onboarding (Phase 1 or 2). CSR is generated and ZATCA compliance check runs automatically. Poll the status URL for onboarding progress.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
| unit_name | string | Yes | e.g. Main Branch POS |
| invoice_type | "standard" | "simplified" | "both" | No | Default: simplified |
| otp | string | No | ZATCA OTP for compliance |
| phase | 1 | 2 | No | 1 = Phase 1 (simplified only), 2 = Phase 2 (full) |
Code examples
const res = await fetch('https://api.esnadapi.com/v1/egs', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${apiKey}`,
},
body: JSON.stringify({
unit_name: 'Main Branch POS',
invoice_type: 'simplified',
phase: 2,
otp: 'optional-zatca-otp',
}),
});
const { egs_unit_id, poll_url } = await res.json();Success response (200)
{
"egs_unit_id": "uuid",
"serial_number": "SN-xxx",
"onboarding_status": "pending",
"message": "CSR generated. ZATCA compliance check running automatically.",
"poll_url": "/v1/egs/uuid/status"
}EGS onboarding status
Returns onboarding status, cert expiry, and invoice counter. Poll this after creating an EGS unit until onboarding_status is active.
Code examples
const res = await fetch(`${BASE}/v1/egs/${egsUnitId}/status`, {
headers: { Authorization: `Bearer ${apiKey}` },
});
const status = await res.json();Success response (200)
{
"egs_unit_id": "uuid",
"unit_name": "Main Branch POS",
"environment": "sandbox",
"phase": 2,
"onboarding_status": "active",
"cert_issued_at": "2025-01-15T10:00:00.000Z",
"cert_expires_at": "2026-01-15T10:00:00.000Z",
"days_until_expiry": 330,
"cert_health": "healthy",
"invoice_counter": 0
}Request production CSID (Phase 2)
After compliance check passes, call this with the ZATCA OTP to obtain production CSID. Cert expiry is returned.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
| otp | string | Yes | ZATCA OTP for production CSID |
Code examples
await fetch(`${BASE}/v1/egs/${egsUnitId}/request-production`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${apiKey}`,
},
body: JSON.stringify({ otp: 'zatca-production-otp' }),
});Success response (200)
{
"message": "Production CSID obtained",
"cert_expires_at": "2026-01-15T10:00:00.000Z"
}Renew production CSID
Alias for request-production. Use to renew the production CSID with a new ZATCA OTP.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
| otp | string | Yes | ZATCA OTP for production CSID |
Code examples
await fetch(`${BASE}/v1/egs/${egsUnitId}/renew`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${apiKey}`,
},
body: JSON.stringify({ otp: 'zatca-renewal-otp' }),
});Success response (200)
{
"message": "Production CSID obtained",
"cert_expires_at": "2026-01-15T10:00:00.000Z"
}