# ZUC.RO API — ghid pentru integratori și agenți AI

ZUC.RO emite facturi electronice românești (UBL 2.1 / CIUS-RO) și le trimite la ANAF e-Factura (SPV).
Acest ghid este scris ca să poată fi citit direct de un model de limbaj sau de un dezvoltator grăbit.
Specificația completă: <https://zuc.ro/api/docs/openapi.yaml> (OpenAPI 3.1). Documentație interactivă:
<https://zuc.ro/api/docs/>.

## 1. Esențialul

- **Bază:** `https://zuc.ro/api/v1`
- **Auth:** `Authorization: Bearer zuc_…` — cheie generată de utilizator din *Setări Facturi → API*. O cheie = o firmă.
- **Format:** JSON în ambele sensuri (`Content-Type: application/json`), UTF-8, date `YYYY-MM-DD`, sume ca numere (punct decimal), TVA în procente (`21`, `11`, `0`).
- **Plic:** succes `{"success":true,"data":…}`; eroare `{"success":false,"error":"<text>","error_code":"<cod>","errors":{…}}`. Ramifică pe `error_code`.
- **Limită:** 60 cereri/minut per cheie; la `429` respectă `Retry-After`.
- **Retry sigur:** pune `Idempotency-Key: <id-ul comenzii>` pe `POST`; o reîncercare cu aceeași cheie primește răspunsul memorat (`Idempotent-Replayed: true`), nu o a doua factură.
- **Mediu ANAF:** `GET /environments/current` → `env: "test"` sau `"prod"`. În *test* nimic nu are valoare fiscală.

## 2. Reguli pentru un agent AI

1. **Nu apela `POST /invoices/{id}/send-anaf` fără confirmarea explicită a utilizatorului** în mediul de producție. Este un act fiscal ireversibil (corecția se face doar prin storno).
2. Înainte de trimitere, rulează `POST /invoices/{id}/validate` și arată utilizatorului `data.errors` dacă `valid` este `false`.
3. Nu ghici CUI-uri sau adrese. Dacă lipsesc, cere-le. Pentru București, `customer_city_name` este `SECTOR1`…`SECTOR6` și `customer_country_subentity` este `RO-B`.
4. Folosește `GET /clients/search?q=` înainte să creezi un client nou, ca să nu dublezi.
5. La `402 plan_limit_reached` sau `plan_feature_required` oprește-te și explică utilizatorului că trebuie să-și schimbe planul pe <https://zuc.ro/subscription.php>; nu reîncerca.
6. La `424` (ANAF nu răspunde / a respins) poți reîncerca **o dată** după câteva secunde; `send-anaf` este sigur la reîncercare (`409 already_sent` înseamnă că prima a reușit). La timeout pe `POST /invoices`, reia cererea cu **același** `Idempotency-Key`.
7. Nu loga și nu repeta cheia API în răspunsuri.

## 3. Fluxul minim: de la comandă la factură în SPV

```bash
BASE=https://zuc.ro/api/v1
H='Authorization: Bearer zuc_xxx'

# a) profilul de facturare (supplier_id) — ia-l pe cel cu company_id-ul firmei cheii
curl -s -H "$H" $BASE/profiles

# b) factura (clientul se creează din câmpurile customer_* dacă nu există)
curl -s -H "$H" -H 'Content-Type: application/json' -X POST $BASE/invoices -d '{
  "supplier_id": 9,
  "customer_name": "CLIENT DEMO SRL",
  "customer_identifier": "RO12345678",
  "customer_street_name": "Str. Exemplu 10",
  "customer_city_name": "Cluj-Napoca",
  "customer_country_subentity": "RO-CJ",
  "customer_email": "facturi@client-demo.ro",
  "notes": "Comanda #10231",
  "items": [
    {"name": "Tricou bumbac", "quantity": 2, "unit_price": 79.90, "vat_rate": 21, "unit_of_measure": "buc"},
    {"name": "Transport", "quantity": 1, "unit_price": 19.90, "vat_rate": 21, "unit_of_measure": "buc"}
  ]
}'
# → 201 {"success":true,"data":{"id":140,"invoice_series":"DOCS","invoice_number":"455","status":"draft",...}}

# c) validare la ANAF (fără trimitere)
curl -s -H "$H" -X POST $BASE/invoices/140/validate
# → {"success":true,"data":{"valid":true,"errors":[]}}

# d) trimitere în SPV (act fiscal în producție!)
curl -s -H "$H" -X POST $BASE/invoices/140/send-anaf
# → {"success":true,"data":{"index_incarcare":"5035575339","status":"sent","environment":"prod"}}

# e) PDF pentru client
curl -s -H "$H" -o factura.pdf $BASE/invoices/140/pdf
```

## 4. Coduri de eroare pe care merită să le tratezi

| `error_code` | HTTP | Ce faci |
|---|---|---|
| `unauthorized` | 401 | cheia e greșită/revocată — cere una nouă utilizatorului |
| `forbidden` | 403 | cheia nu are permisiunea (presetul *Viewer* nu poate crea) |
| `plan_limit_reached` | 402 | limita lunară de facturi; nu reîncerca |
| `plan_feature_required` | 402 | funcția (ex. email) cere plan superior |
| `invalid_supplier` / `invalid_customer` | 422 | id-ul nu e al firmei cheii — recitește `/profiles` sau `/clients` |
| `validation_failed` | 422 | vezi `errors` (per câmp, ex. `items.0.unit_price`) |
| `anaf_validation_failed` | 422 | validatorul ANAF a respins XML-ul; `errors` are mesajele lui |
| `anaf_token_missing` / `anaf_environment_missing` | 409 | utilizatorul trebuie să se autorizeze la ANAF pe <https://zuc.ro/auth/auth_anaf.php> |
| `already_sent` | 409 | factura e deja în SPV; `index_incarcare` e în răspuns |
| `invoice_sent` | 409 | nu se mai editează; fă `POST /invoices/{id}/storno` |
| `already_stornoed` | 409 | factura are deja un storno; `storno_id` e în răspuns — nu mai crea altul |
| `invalid_storno_target` | 422 | un storno nu se stornează |
| `anaf_rejected` / `anaf_network_error` | 424 | ANAF a respins uploadul sau nu răspunde; `anaf_response` are XML-ul brut |
| `rate_limited` | 429 | așteaptă `Retry-After` secunde |

## 5. Corecții

- **Storno:** `POST /invoices/{id}/storno` creează o factură cu cantități negative (draft). Dacă originalul e în SPV, trimite și stornoul cu `send-anaf`. O factură are un singur storno (`409 already_stornoed` îți dă `storno_id`).
- **Marcare plătită:** `PATCH /invoices/{id}/status` cu `{"status":"paid"}`.
- **Ștergere:** doar pentru drafturi care nu au ajuns la ANAF.

## 6. Ce **nu** face API-ul (încă)

- Nu are webhook-uri; verifică statusul cu `GET /invoices/{id}` (`anaf_synced`, `efactura_id`, `status`).
- Nu expune chitanțe/încasări și nici facturile primite ca PDF (doar lista `GET /anaf/invoices`).

## 7. Folosire ca *tool* într-un agent

Descrierea de tool recomandată (OpenAI Actions / Claude tool-use / orice framework care importă OpenAPI):
importă `https://zuc.ro/api/docs/openapi.yaml`, autentificare *Bearer* cu cheia utilizatorului, și marchează
`POST /invoices/{id}/send-anaf`, `DELETE /invoices/{id}`, `DELETE /account` ca operații care cer confirmare umană.

Prompt de sistem sugerat pentru agent:

> Ești asistentul de facturare al firmei. Folosește API-ul ZUC.RO pentru a crea facturi din datele comenzii.
> Verifică întotdeauna clientul existent cu `/clients/search` înainte de a crea unul nou. Rulează `/validate`
> și arată erorile. Nu trimite la ANAF (`/send-anaf`) decât după ce utilizatorul confirmă explicit, și spune-i
> mediul curent (test/prod) înainte. Nu inventa date fiscale.
