Greece Fiscalization Guide
What is Greek fiscalization?
Greece operates myDATA (My Digital Accounting and Tax Application), run by AADE (Independent Authority for Public Revenue). Every B2B and B2C invoice must be transmitted to AADE; AADE returns a MARK (Unique Registration Number) which becomes the legal identifier of the invoice.
In plain English: Greece transmits invoices to AADE in JSON or XML and gets back a MARK. There's no client certificate — authentication uses an AADE-issued user id plus an Azure APIM subscription key. Some merchants use a single-leg flow (Type A), others need a second classification leg (Type B).
Zyntem builds the myDATA invoice envelope, transmits over HTTPS to mydatapi.aade.gr, parses the response, and surfaces the MARK as fiscal_id_upstream. Type A vs Type B is configured per location.
How it works
Greece's flow is synchronous-MARK with asynchronous classification:
- Your POS creates a transaction via
POST /v1/transactions. - Zyntem assembles the myDATA
<invoice>envelope (UBL-derived AADE schema). - Zyntem sends it to
/SendInvoiceswith theaade-user-idand subscription-key headers. - AADE responds synchronously with the MARK.
- The transaction returns with
fiscal_id=series-number(issuer-side) andfiscal_id_upstream= MARK. - Type B only: Zyntem follows up with
/SendIncomeClassification(the issuer's classification leg). The counterpart's expense classification arrives passively from their accounting software.
Type A vs Type B (configured per location):
- Type A — single-leg sync MARK. Classification is embedded in the invoice envelope. Common for B2C retail and simple B2B services.
- Type B — two-leg flow: SendInvoices → MARK, then SendIncomeClassification. Common for B2B with itemized expense classifications.
A single AFM may issue both kinds against different series, so document_class is configured per location.
Country config fields
The country_config object for Greek locations:
| Field | Type | Required | Description |
|---|---|---|---|
afm | string | Yes | 9-digit Greek tax id (Αριθμός Φορολογικού Μητρώου). |
branch | integer | Yes | AADE branch id (0 = primary establishment). |
legal_name | string | Yes | Legal name (printed on the invoice and used in counterpart matching). |
aade_user_id | string | Yes | Per-merchant aade-user-id header value (issued by AADE at onboarding). |
subscription_key | string | Yes | Azure APIM subscription key (sealed at registration). |
env | string | Yes | sandbox, production, provider_sandbox, or provider_production. |
document_class | string | Yes | TypeA (single-leg) or TypeB (two-leg). |
default_series | string | Yes | Default series (must be unique per (afm, year, branch)). |
Configuration example
curl -X POST https://api.zyntem.dev/v1/locations \
-H "Content-Type: application/json" \
-H "Authorization: Bearer zyn_test_abc123def456..." \
-d '{
"name": "Athens Store",
"country": "GR",
"address": "Ermou 1, 105 63 Athens",
"country_config": {
"afm": "094149139",
"branch": 0,
"legal_name": "Zyntem Hellas Ι.Κ.Ε.",
"aade_user_id": "zyntem-hellas",
"subscription_key": "<sealed>",
"env": "production",
"document_class": "TypeA",
"default_series": "A"
}
}'
Creating a transaction
Example: A EUR 50 retail sale at an Athens store.
curl -X POST https://api.zyntem.dev/v1/transactions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer zyn_test_abc123def456..." \
-d '{
"location_id": "loc_abc123",
"type": "sale",
"amount": 5000,
"currency": "EUR",
"line_items": [
{
"description": "Souvenir scarf",
"quantity": 1,
"unit_price": 4032,
"vat_rate": 2400
}
]
}'
Response
{
"id": "txn_abc123",
"status": "success",
"fiscal_id": "A-12345",
"fiscal_id_upstream": "400001234567890",
"country": "GR",
"created_at": "2026-03-15T14:30:22Z"
}
fiscal_id is the issuer-side series-number. fiscal_id_upstream is the AADE-assigned MARK and is what regulators reference.
Submission window
myDATA requires real-time transmission for B2C and end-of-day batched transmission for B2B (current rules; future tightens to 24 hours under provider channel). Zyntem submits per transaction by default; configure batch mode via the location settings if your scale requires it.
Sandbox access
The ERP sandbox is at mydataapidev.aade.gr (Ocp-Apim-Subscription-Key header). Sandbox routing is automatic with a test API key. Subscription keys are obtained from mydata-dev.azure-api.net/portal — typical onboarding is 2–3 days.
Offline-grace behaviour
AADE returns the MARK synchronously on the ERP path, so the receipt-print path performs the authority round-trip while the customer waits. Zyntem applies a 5-second timeout per attempt (longer than HR/SI to absorb the heavier myDATA payload + provider-channel hop). If AADE is unreachable or the response times out, the receipt still prints under the regulator-mandated offline-mode flow:
- The receipt carries the locally-computed series-number identifier and is annotated with the regulator-mandated offline label so the customer's copy is unambiguous.
- The transaction is recorded as
offline_pendingand Zyntem retries the AADE submission in the background through the offline-grace window defined by Greek law (tier-dependent — up to 1 month for the largest tier; Zyntem applies a conservative 7-day default and surfaces tier-aware resolution as a per-merchant configuration rollout). - On a successful retry, the MARK is populated (
fiscal_id_upstream) and atransaction.late_authority_confirmedwebhook fires. - If the grace window expires without success, the row transitions to
failed_offline_grace_expiredand a webhook fires for human triage.
The FIM (cash-register hardware) path has its own offline-mode rules defined by the device firmware and is out of scope for this guide.
There are no merchant-facing knobs for the ERP-path offline-grace flow — the timeout, label, and grace window are fixed by regulation and tier. ISVs do not need to implement fallback logic in their application; Zyntem owns the full state machine.
Error handling
When AADE rejects an invoice, error.category distinguishes:
transient— network blip or AADE 5xx. Zyntem retries automatically.regulatory_reject—RejectedClientstatus witherror.authority_codecarrying the validation-error code (e.g.400series). Correct the invoice and re-issue.permanent— schema mismatch (e.g. wrongvatCategory, missingbranch). Surface to operator.duplicate_as_success— re-submitted invoice already accepted under this MARK. Treated as success.
myDATA also has a "quarantined-with-warnings" outcome — Zyntem reports this as success but surfaces the warning codes in the transaction's response_payload.warnings.
See the Error handling guide for the full taxonomy.
Receipt presentation
render_hints on the transaction response tells your POS exactly what to
print and where. You do not need to read the AADE myDATA regulation —
the hints are the contract.
key | When present | Placement | Mandatory | Kind |
|---|---|---|---|---|
mark | Online (sync submit succeeded) | footer_bottom | Yes | text |
uid | Online | footer_bottom | Yes | text |
auth_code | Online | footer_bottom | Yes | text |
qr | Online | footer_right | Yes | qr_url (AADE verification URL) |
late_transmission_label | Offline-grace fallback | footer_top | Yes | text |
All AADE-side items are authority-returned — at transaction-creation time
they are absent. Zyntem's runtime appends them once SendInvoices returns
successfully (typically within the 5-second sync timeout). On timeout or
authority outage the runtime appends the late_transmission_label instead
and retries through the offline-grace window.
Example printed receipt (online)
══════════════════════════════════════
Επιχείρηση Α.Ε.
ΑΦΜ: 094149139
══════════════════════════════════════
Espresso 2,50 €
──────────────────────────────────────
ΣΥΝΟΛΟ 2,50 €
══════════════════════════════════════
ΜΑΡΚ: 400000123456789
UID: 1A2B3C4D5E6F
AUTH: abc123def456
┌──────────┐
│ ▓░▓░░▓░ │
│ ░▓░▓▓░▓ │
└──────────┘
Example printed receipt (offline-grace)
══════════════════════════════════════
ΕΚΠΡΟΘΕΣΜΗ ΔΙΑΒΙΒΑΣΗ
Επιχείρηση Α.Ε.
ΑΦΜ: 094149139
══════════════════════════════════════
Espresso 2,50 €
──────────────────────────────────────
ΣΥΝΟΛΟ 2,50 €
══════════════════════════════════════
(MARK / UID / AUTH added on retransmission)
The offline-grace window is tier-dependent (up to 1 month for some merchants); ISVs do not need to compute it — Zyntem retries through the applicable window automatically.
meta schema (Greece)
No additional meta keys at this time. The qr value is the AADE
verification URL containing the MARK and signature.