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.

POST/v1/egs

Create EGS unit

Creates an EGS unit and starts async onboarding (Phase 1 or 2). The unit's environment (sandbox or production) is determined by your API key: use a key starting with zatca_test_ for sandbox, zatca_live_ for production. You can pass environment explicitly; it must match the key or the request returns 400 ENVIRONMENT_KEY_MISMATCH. CSR is generated and ZATCA compliance check runs automatically. Poll the status URL for onboarding progress.

Requires API Key (Bearer)

Request body

CreateEgsDto
FieldTypeRequiredDescription
unit_namestringYese.g. Main Branch POS
invoice_type"standard" | "simplified" | "both"NoDefault: simplified
otpstringNoZATCA OTP for compliance (sandbox: e.g. 123345; production: from Fatoora portal)
phase1 | 2No1 = Phase 1 (simplified only), 2 = Phase 2 (full)
environment"sandbox" | "production"NoMust match API key: sandbox for zatca_test_ keys, production for zatca_live_. When omitted, backend uses the key's mode. If provided and mismatched, returns 400 ENVIRONMENT_KEY_MISMATCH.

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',
    environment: 'sandbox',  // optional; must match API key (zatca_test_ → sandbox, zatca_live_ → production)
  }),
});
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"
}
GET/v1/egs/:id/status

EGS onboarding status

Returns onboarding status, cert expiry, and invoice counter. Poll this after creating an EGS unit until onboarding_status is active.

Requires API Key (Bearer)

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
}
POST/v1/egs/:id/request-production

Request production CSID (Phase 2)

After compliance check passes, call this with the ZATCA OTP to obtain production CSID. Cert expiry is returned.

Requires API Key (Bearer)

Request body

RequestProductionDto
FieldTypeRequiredDescription
otpstringYesZATCA 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"
}
POST/v1/egs/:id/renew

Renew production CSID

Alias for request-production. Use to renew the production CSID with a new ZATCA OTP.

Requires API Key (Bearer)

Request body

RequestProductionDto
FieldTypeRequiredDescription
otpstringYesZATCA 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"
}