# FirmeAPI.ro — API Achiziții Publice SICAP: ghid de implementare pentru agenți AI

> Acest document e scris pentru agenți AI de programare (Claude Code, Cursor, Copilot, Codex, ChatGPT etc.).
> Conține tot ce trebuie pentru o integrare completă, fără întrebări suplimentare către utilizator.
> Versiunea pentru oameni: https://www.firmeapi.ro/info-api/achizitii-publice-sicap

Șapte endpoint-uri pentru achizițiile publice din SICAP (e-licitatie.ro): ce contracte câștigă o firmă, ce cumpără o autoritate, notificările de atribuire și achizițiile directe, cu filtre după CPV, valoare și dată.

## 0. Ce trebuie să livrezi

Integrează în aplicația utilizatorului API-ul de achiziții publice SICAP FirmeAPI.ro, cap-coadă:

1. **Configurare** — cheia API citită din variabila de mediu `FIRMEAPI_KEY`; adaug-o în `.env.example` (sau echivalent) cu valoare goală. Nu scrie cheia în cod și nu o trimite niciodată în browser.
2. **Client API** — un modul/serviciu în backend cu câte o metodă pentru fiecare endpoint (`sicapFirma`, `sicapAutoritate`, `sicapAtribuiri`, `sicapAchizitii`, `sicapFurnizorAtribuiri`, `sicapFurnizorAchizitii`, `sicapAutoritateAchizitii`), cu tipurile răspunsurilor, tratarea erorilor (secțiunea 4) și reîncercări doar unde e permis.
3. **Cache** — rezultatele păstrate pe cheia cererii (de exemplu 24 de ore pentru datele unei firme). Fiecare cerere reușită consumă credite.
4. **Logica de domeniu** — regulile din secțiunea 5, într-un singur loc, nu împrăștiate prin interfață.
5. **Interfață** (dacă aplicația are UI) — afișarea datelor și a mesajelor de eroare; câmpurile `null` apar ca „nedeclarat” sau „—”, nu ca 0.
6. **Teste** — cu răspunsuri simulate din acest ghid (mock HTTP), care acoperă cazurile din secțiunea 8.

Respectă convențiile proiectului existent (limbaj, framework, structură de foldere, client HTTP deja folosit).

## 1. Autentificare și cereri

- Bază URL: `https://www.firmeapi.ro/api/v1`
- Header de autentificare: `X-API-KEY: <cheie>` (alternativ `Authorization: Bearer <cheie>`).
- Cheia se creează din contul FirmeAPI, pagina „Chei API”.
- Trimite `Accept: application/json`. Răspunsurile sunt JSON UTF-8; datele calendaristice au formatul `YYYY-MM-DD`.
- Timeout recomandat: 30 s.

## 2. Endpoint-urile

### 2.1 Profil SICAP al unei firme — `GET /sicap/{cui}`

Cost: **10 credite** per cerere reușită (2xx). Erorile nu se taxează.

Dacă firma e furnizor și/sau autoritate contractantă, statisticile atribuirilor și ale achizițiilor directe câștigate, rata de câștig și legăturile către listele complete.

| Parametru | Unde | Tip | Obligatoriu | Descriere |
|---|---|---|---|---|
| `cui` | cale | integer | da | CUI-ul firmei (sau entity_id-ul SICAP). Ex.: `12345678`. |

Exemplu: `GET https://www.firmeapi.ro/api/v1/sicap/12345678`

Răspuns 200 (date fictive, aceeași formă ca răspunsul real):

```json
{
    "success": true,
    "cui": "12345678",
    "este_furnizor": true,
    "este_autoritate_contractanta": false,
    "furnizor": {
        "entity_id": 100210917,
        "denumire": "EXEMPLU CONSTRUCT S.R.L.",
        "cui": "12345678",
        "adresa": "Str. Exemplu Nr. 15",
        "localitate": "Cluj-Napoca",
        "judet": "Cluj",
        "cod_postal": "400001",
        "telefon": "+40756000000",
        "email": "contact@exemplu.ro",
        "website": null
    },
    "autoritate": null,
    "statistici_atribuiri": {
        "total_atribuiri": 247,
        "valoare_totala_castigata": 4287642.5,
        "valoare_ultimele_12_luni": 1240000,
        "autoritati_distincte": 38,
        "categorii_cpv_distincte": 12,
        "categorii_cpv": [
            {
                "cod": "45233142-6",
                "nr_contracte": 89
            },
            {
                "cod": "45262500-6",
                "nr_contracte": 42
            }
        ],
        "contracte_in_alte_categorii": 0,
        "prima_atribuire": "2018-05-14",
        "ultima_atribuire": "2026-07-28",
        "top_autoritati": [
            {
                "entity_id": 4321,
                "cui": "4305857",
                "denumire": "COMUNA EXEMPLU",
                "localitate": "Exemplu",
                "judet": "Cluj",
                "nr_contracte": 31,
                "valoare_totala": 866028.34
            }
        ],
        "evolutie_anuala": [
            {
                "an": "2025",
                "nr_contracte": 44,
                "valoare_totala": 890553.43
            }
        ],
        "tipuri_contract": [
            {
                "tip": "Furnizare",
                "nr_contracte": 47446,
                "valoare_totala": 1441187383.04
            },
            {
                "tip": "Servicii",
                "nr_contracte": 254,
                "valoare_totala": 191842.74
            }
        ],
        "geografie_contracte": {
            "top_judete": [
                {
                    "judet": "Bucuresti",
                    "nr_contracte": 17533,
                    "valoare_totala": 9783103.14
                },
                {
                    "judet": "Timis",
                    "nr_contracte": 5190,
                    "valoare_totala": 1666208.94
                }
            ],
            "nota": "Repartizarea contractelor pe județe (agregat din județul autorității contractante)."
        },
        "statistici_valorice": {
            "valoare_minima_contract": 0.02,
            "valoare_maxima_contract": 1415244288,
            "valoare_medie_contract": 17359,
            "valoare_mediana_contract": 9800,
            "contracte_peste_100k": 7,
            "contracte_peste_1M": 0
        },
        "finantare": {
            "fonduri_ue_valoare": 254891,
            "fonduri_ue_contracte": 147,
            "fonduri_ue_procent": 12.4,
            "bugetar_valoare": 1441276196.76,
            "bugetar_contracte": 47623,
            "bugetar_procent": 87.6
        }
    },
    "statistici_achizitii_directe": {
        "total_achizitii": 612,
        "valoare_totala": 2444039229.75,
        "valoare_ultimele_12_luni": 85964755.07,
        "autoritati_distincte": 11269,
        "categorii_cpv_distincte": 2884,
        "categorii_cpv": [
            {
                "cod": "44423000-1",
                "nr_achizitii": 189175
            },
            {
                "cod": "44411000-4",
                "nr_achizitii": 19482
            }
        ],
        "achizitii_in_alte_categorii": 1241,
        "prima_achizitie": "2008-09-09T06:32:53.000Z",
        "ultima_achizitie": "2026-10-26T13:51:12.000Z",
        "top_autoritati": [
            {
                "entity_id": 1021,
                "cui": "11054545",
                "denumire": "SNTFC ,,CFR CALATORI\" SA",
                "localitate": "Bucuresti",
                "judet": "Bucuresti",
                "nr_achizitii": 8013,
                "valoare_totala": 5784410.79
            },
            {
                "entity_id": 2811,
                "cui": "4187255",
                "denumire": "INSPECTORATUL DE POLITIE JUDETEAN BACAU",
                "localitate": "Bacau",
                "judet": "Bacau",
                "nr_achizitii": 5441,
                "valoare_totala": 1114178.36
            }
        ],
        "evolutie_anuala": [
            {
                "an": "2008",
                "nr_achizitii": 705,
                "valoare_totala": 187504.92
            },
            {
                "an": "2009",
                "nr_achizitii": 2998,
                "valoare_totala": 980932.28
            }
        ],
        "tipuri_contract": [
            {
                "tip": "Furnizare",
                "nr_achizitii": 484125,
                "valoare_totala": 2156273398.09
            },
            {
                "tip": "Servicii",
                "nr_achizitii": 9395,
                "valoare_totala": 21117801.22
            }
        ],
        "geografie_contracte": {
            "top_judete": [
                {
                    "judet": "Bucuresti",
                    "nr_achizitii": 57000,
                    "valoare_totala": 43042545.11
                },
                {
                    "judet": "Bacau",
                    "nr_achizitii": 47407,
                    "valoare_totala": 25645169.32
                }
            ],
            "nota": "Repartizarea achizițiilor pe județe (agregat din județul autorității contractante)."
        },
        "statistici_valorice": {
            "valoare_minima_contract": -193.29,
            "valoare_maxima_contract": 1465948288,
            "valoare_medie_contract": 3474.8,
            "valoare_mediana_contract": 346.68,
            "contracte_peste_100k": 140,
            "contracte_peste_1M": 30
        },
        "finantare": {
            "fonduri_ue_valoare": 9165824.49,
            "fonduri_ue_contracte": 2962,
            "fonduri_ue_procent": 0.38,
            "bugetar_valoare": 2434873405.27,
            "bugetar_contracte": 707733,
            "bugetar_procent": 99.62
        }
    },
    "win_rate": {
        "id": 11056,
        "name": "EXEMPLU PERSOANĂ",
        "cui": "RO 2816464",
        "participantType": "Ofertant",
        "participantTypeId": 3,
        "participantStatus": 2,
        "participantEntityState": "Inregistrat",
        "retrievedTimestamp": "2026-10-26T02:12:57.0031021+02:00",
        "registration": {
            "registrationTimestamp": "2007-02-23T10:53:02+02:00",
            "invalidationTimestamp": null,
            "legalRepresentative": "EXEMPLU PERSOANĂ"
        },
        "address": {
            "city": "Bacau",
            "county": "Bacau",
            "contactPerson": "EXEMPLU PERSOANĂ",
            "address": "Strada: Tolstoi Alexei, nr. 8, Sector: -, Judet: Bacau, Localitate: Bacau, Cod postal: 600093",
            "postalCode": "600093",
            "phone": "0212345678",
            "fax": "0212345678",
            "website": null
        },
        "notices": null,
        "supplierProceduresInfo": [
            {
                "participantQuality": "Castigator",
                "directAcquisition": 478761,
                "requestForQuotation": 0,
                "openBids": 11,
                "restrictedBids": 0,
                "eBids": 0,
                "simplifiedProcedureBids": 9,
                "total": 20
            },
            {
                "participantQuality": "Participant",
                "directAcquisition": 17280,
                "requestForQuotation": 0,
                "openBids": 16,
                "restrictedBids": 0,
                "eBids": 0,
                "simplifiedProcedureBids": 17,
                "total": 33
            }
        ],
        "catalog": {
            "published": 739048,
            "valid": 368895,
            "notExpired": 758303,
            "awardedDirectAcquisitions": 0
        },
        "caProceduresOngoing": null,
        "caProceduresAwarded": null,
        "caProceduresCancelled": null,
        "entityId": 11056,
        "legalRepresentative": "EXEMPLU PERSOANĂ",
        "contactPerson": "EXEMPLU PERSOANĂ",
        "registrationTimestamp": "2007-02-23T10:53:02+02:00",
        "invalidationTimestamp": null
    },
    "toate_atribuirile": {
        "total_disponibile": 247,
        "vezi_toate": "https://www.firmeapi.ro/api/v1/sicap/furnizor/100210917/atribuiri",
        "cost_per_rezultat": 5
    },
    "toate_achizitiile_directe_castigate": {
        "vezi_toate": "https://www.firmeapi.ro/api/v1/sicap/furnizor/100210917/achizitii",
        "cost_per_rezultat": 5,
        "nota": "Achizițiile directe câștigate (fără licitație formală) — complementar cu atribuirile."
    },
    "toate_achizitiile_ca_autoritate": null
}
```

| Câmp | Tip | Descriere |
|---|---|---|
| `success` | boolean | true la răspunsurile reușite. |
| `cui` | string | CUI-ul cerut. |
| `este_furnizor · este_autoritate_contractanta` | boolean | Rolurile firmei în SICAP. |
| `furnizor` | object \| null | entity_id, denumire, cui, adresa, localitate, judet, cod_postal, telefon, email, website. null dacă firma nu e furnizor. |
| `autoritate` | object \| null | Aceleași date, când firma e și autoritate contractantă. |
| `statistici_atribuiri.total_atribuiri · valoare_totala_castigata · valoare_ultimele_12_luni` | number | Numărul contractelor câștigate prin atribuire, valoarea lor totală și valoarea din ultimele 12 luni. |
| `statistici_atribuiri.autoritati_distincte · categorii_cpv_distincte · contracte_in_alte_categorii` | integer | Câte autorități și câte categorii CPV distincte; câte contracte nu intră în categoriile afișate. |
| `statistici_atribuiri.prima_atribuire · ultima_atribuire` | date | Prima și ultima atribuire. |
| `statistici_atribuiri.categorii_cpv[]` | array | cod, nr_contracte. |
| `statistici_atribuiri.top_autoritati[]` | array | entity_id, cui, denumire, localitate, judet, nr_contracte, valoare_totala. |
| `statistici_atribuiri.evolutie_anuala[] · tipuri_contract[]` | array | Pe ani (an) și pe tipuri (tip): nr_contracte, valoare_totala. |
| `statistici_atribuiri.geografie_contracte.top_judete[] · nota` | mixed | Repartizarea contractelor pe județul autorității: judet, nr_contracte, valoare_totala. |
| `statistici_atribuiri.statistici_valorice` | object | valoare_minima_contract, valoare_maxima_contract, valoare_medie_contract, valoare_mediana_contract, contracte_peste_100k, contracte_peste_1M. |
| `statistici_atribuiri.finantare` | object | fonduri_ue_valoare, fonduri_ue_contracte, fonduri_ue_procent, bugetar_valoare, bugetar_contracte, bugetar_procent. |
| `statistici_achizitii_directe` | object | Aceeași structură pentru achizițiile directe câștigate, cu total_achizitii, valoare_totala, prima_achizitie, ultima_achizitie, nr_achizitii în loc de nr_contracte. |
| `win_rate` | object | Profilul de participant din SICAP, așa cum îl publică sistemul (câmpuri în engleză): supplierProceduresInfo[] cu participările pe tip de procedură, catalog, registration. |
| `toate_atribuirile · toate_achizitiile_directe_castigate · toate_achizitiile_ca_autoritate` | object | total_disponibile, vezi_toate (adresa listei complete), cost_per_rezultat. |

### 2.2 Profilul unei autorități contractante — `GET /sicap/autoritate/{cui}`

Cost: **10 credite** per cerere reușită (2xx). Erorile nu se taxează.

Datele autorității și statisticile achizițiilor făcute: categorii, furnizori principali, evoluție, finanțare.

| Parametru | Unde | Tip | Obligatoriu | Descriere |
|---|---|---|---|---|
| `cui` | cale | integer | da | CUI-ul instituției (sau entity_id-ul SICAP). Ex.: `4305857`. |

Exemplu: `GET https://www.firmeapi.ro/api/v1/sicap/autoritate/4305857`

Răspuns 200 (date fictive, aceeași formă ca răspunsul real):

```json
{
    "success": true,
    "cui": "4305857",
    "entity_id": 4321,
    "autoritate": {
        "entity_id": 4321,
        "denumire": "COMUNA EXEMPLU",
        "cui": "4305857",
        "adresa": "Str. Principală 1",
        "localitate": "Exemplu",
        "judet": "Cluj",
        "este_utilitate": false,
        "telefon": "0264000000",
        "email": "primaria@exemplu.ro",
        "website": null
    },
    "statistici_achizitii": {
        "total_achizitii": 1830,
        "valoare_totala": 274223200.77,
        "furnizori_distincti": 854,
        "categorii_cpv_distincte": 1000,
        "categorii_cpv": [
            {
                "cod": "30192000-1",
                "nr_achizitii": 210
            }
        ],
        "achizitii_in_alte_categorii": 0,
        "top_furnizori": [
            {
                "entity_id": 100210917,
                "cui": "12345678",
                "denumire": "EXEMPLU CONSTRUCT S.R.L.",
                "localitate": "Floresti",
                "judet": "Cluj",
                "nr_achizitii": 31,
                "valoare_totala": 3276553.8
            }
        ],
        "evolutie_anuala": [
            {
                "an": "2008",
                "nr_achizitii": 115,
                "valoare_totala": 383895.54
            },
            {
                "an": "2009",
                "nr_achizitii": 21,
                "valoare_totala": 215785.87
            }
        ],
        "tipuri_contract": [
            {
                "tip": "Furnizare",
                "nr_achizitii": 3641,
                "valoare_totala": 40918407.04
            },
            {
                "tip": "Servicii",
                "nr_achizitii": 3608,
                "valoare_totala": 151620205.05
            }
        ],
        "geografie_furnizori": {
            "top_judete": [
                {
                    "judet": "Cluj",
                    "nr_achizitii": 6206,
                    "valoare_totala": 195132814.65
                },
                {
                    "judet": "Bucuresti",
                    "nr_achizitii": 972,
                    "valoare_totala": 20479707.18
                }
            ],
            "nota": "Repartizarea achizițiilor pe județe (agregat din județul furnizorului)."
        },
        "statistici_valorice": {
            "valoare_minima_contract": 0,
            "valoare_maxima_contract": 50232000,
            "valoare_medie_contract": 29556.28,
            "valoare_mediana_contract": 3322.92,
            "contracte_peste_100k": 720,
            "contracte_peste_1M": 2
        },
        "finantare": {
            "fonduri_ue_valoare": 31896885.51,
            "fonduri_ue_contracte": 625,
            "fonduri_ue_procent": 11.63,
            "bugetar_valoare": 242326315.26,
            "bugetar_contracte": 8788,
            "bugetar_procent": 88.37
        }
    },
    "toate_achizitiile": {
        "total_disponibile": 1830,
        "vezi_toate": "https://www.firmeapi.ro/api/v1/sicap/autoritate/4321/achizitii",
        "cost_per_rezultat": 5
    }
}
```

| Câmp | Tip | Descriere |
|---|---|---|
| `success` | boolean | true la răspunsurile reușite. |
| `cui · entity_id` | string · integer | CUI-ul cerut și identificatorul autorității în SICAP. |
| `autoritate` | object | entity_id, denumire, cui, adresa, localitate, judet, este_utilitate, telefon, email, website. |
| `statistici_achizitii.total_achizitii · valoare_totala` | number | Numărul și valoarea totală a achizițiilor directe. |
| `statistici_achizitii.furnizori_distincti · categorii_cpv_distincte · achizitii_in_alte_categorii` | integer | Câți furnizori și câte categorii CPV distincte; câte achiziții nu intră în categoriile afișate. |
| `statistici_achizitii.categorii_cpv[]` | array | cod, nr_achizitii. |
| `statistici_achizitii.top_furnizori[]` | array | entity_id, cui, denumire, localitate, judet, nr_achizitii, valoare_totala. |
| `statistici_achizitii.evolutie_anuala[] · tipuri_contract[]` | array | Pe ani (an) și pe tipuri (tip): nr_achizitii, valoare_totala. |
| `statistici_achizitii.geografie_furnizori.top_judete[] · nota` | mixed | Repartizarea achizițiilor pe județul furnizorului. |
| `statistici_achizitii.statistici_valorice · finantare` | object | Aceeași structură ca la profilul firmei. |
| `toate_achizitiile` | object | total_disponibile, vezi_toate (adresa listei complete), cost_per_rezultat. |

### 2.3 Notificări de atribuire — `GET /sicap/atribuiri/lista`

Cost: **5 / rezultat** per cerere reușită (2xx). Erorile nu se taxează.

Toate contractele atribuite prin proceduri de achiziție, cu filtre.

| Parametru | Unde | Tip | Obligatoriu | Descriere |
|---|---|---|---|---|
| `cui_furnizor` | query | string | nu | CUI-ul furnizorului. |
| `cui_autoritate` | query | string | nu | CUI-ul autorității contractante. |
| `judet_furnizor` | query | string | nu | Județul furnizorului. |
| `cpv` | query | string | nu | Codul CPV al categoriei. Ex.: `45233142-6`. |
| `data_start · data_end` | query | dată | nu | Intervalul datei de publicare. Ex.: `2025-01-01`. |
| `valoare_min · valoare_max` | query | number | nu | Intervalul valorii, în lei. |
| `q` | query | string | nu | Text liber în obiectul contractului (minim 2 caractere). Ex.: `reparații drum`. |
| `pagina` | query | integer | nu | Pagina, de la 1. |
| `per_pagina` | query | integer | nu | Rezultate pe pagină, maxim 20. |

Exemplu: `GET https://www.firmeapi.ro/api/v1/sicap/atribuiri/lista?cpv=45233142-6&valoare_min=100000`

Răspuns 200 (date fictive, aceeași formă ca răspunsul real):

```json
{
    "success": true,
    "pagina": 1,
    "per_pagina": 20,
    "total": 247,
    "total_pagini": 13,
    "rezultate": [
        {
            "notice_id": 1234567,
            "numar_notificare": "DAN1234567",
            "data_publicare": "2026-07-28",
            "data_contract": "2026-07-20",
            "data_finalizare": "2026-10-26T00:00:00+02:00",
            "obiect_contract": "Reparații drum comunal",
            "valoare_atribuita": 125400,
            "valoare_atribuita_eur": 25200,
            "moneda": "RON",
            "cpv_cod": "45233142-6",
            "cpv_descriere": "Lucrări de reparare a drumurilor",
            "tip_contract": "Lucrari",
            "tip_achizitie": "Offline",
            "online": false,
            "stare": "Publicat",
            "furnizor_cui": "12345678",
            "furnizor_denumire": "EXEMPLU CONSTRUCT S.R.L.",
            "furnizor_adresa": "Strada: Tolstoi Alexei, nr. 8, Sector: -, Judet: Bacau, Localitate: Bacau, Cod postal: 600093",
            "furnizor_localitate": "Bacau",
            "furnizor_cod_postal": "600093",
            "furnizor_telefon": "0212345678",
            "furnizor_email": "office@exemplu.ro",
            "furnizor_website": null,
            "autoritate_id": 4321,
            "fonduri_ue": false,
            "fond_ue_denumire": null
        }
    ],
    "cost": {
        "credite_consumate": 100,
        "per_rezultat": 5,
        "tip": "general"
    }
}
```

| Câmp | Tip | Descriere |
|---|---|---|
| `success` | boolean | true la răspunsurile reușite. |
| `pagina · per_pagina · total · total_pagini` | integer | Paginarea. |
| `rezultate[]` | array | Notificări de atribuire sau achiziții directe, în formatul de mai sus. |
| `cost.credite_consumate · per_rezultat · tip` | mixed | Costul cererii: 5 credite generale per rezultat. |
| `rezultate[].notice_id · numar_notificare` | mixed | Identificatorul intern și numărul notificării. |
| `rezultate[].data_publicare · data_contract · data_finalizare` | string | Datele notificării și ale contractului. |
| `rezultate[].obiect_contract` | string | Ce s-a contractat. |
| `rezultate[].valoare_atribuita · valoare_atribuita_eur · moneda` | number | Valoarea în lei și în euro. |
| `rezultate[].cpv_cod · cpv_descriere` | string | Categoria CPV. |
| `rezultate[].tip_contract · tip_achizitie · online · stare` | mixed | Clasificarea și starea notificării. |
| `rezultate[].furnizor_cui · furnizor_denumire · furnizor_*` | string | Câștigătorul: CUI, denumire, adresă, localitate, cod poștal, contact. |
| `rezultate[].autoritate_id` | integer | entity_id-ul autorității contractante. |
| `rezultate[].fonduri_ue · fond_ue_denumire` | mixed | Finanțarea din fonduri europene și programul. |

Reguli:

- Costul este 5 credite per rezultat întors; o pagină fără rezultate nu costă nimic.

### 2.4 Achiziții directe — `GET /sicap/achizitii/lista`

Cost: **5 / rezultat** per cerere reușită (2xx). Erorile nu se taxează.

Achizițiile directe din catalogul SEAP, live și arhiva de dinainte de 2018.

| Parametru | Unde | Tip | Obligatoriu | Descriere |
|---|---|---|---|---|
| `cui_furnizor` | query | string | nu | CUI-ul furnizorului. |
| `cui_autoritate` | query | string | nu | CUI-ul autorității contractante. |
| `cpv` | query | string | nu | Codul CPV al categoriei. Ex.: `45233142-6`. |
| `data_start · data_end` | query | dată | nu | Intervalul datei de publicare. Ex.: `2025-01-01`. |
| `valoare_min · valoare_max` | query | number | nu | Intervalul valorii, în lei. |
| `q` | query | string | nu | Text liber în obiectul contractului (minim 2 caractere). Ex.: `reparații drum`. |
| `pagina` | query | integer | nu | Pagina, de la 1. |
| `per_pagina` | query | integer | nu | Rezultate pe pagină, maxim 20. |
| `include` | query | string | nu | produse = adaugă lista produselor fiecărei achiziții. Valori: `produse`. |

Exemplu: `GET https://www.firmeapi.ro/api/v1/sicap/achizitii/lista?cui_autoritate=4305857&data_start=2026-01-01`

Răspuns 200 (date fictive, aceeași formă ca răspunsul real):

```json
{
    "success": true,
    "pagina": 1,
    "per_pagina": 20,
    "total": 612,
    "total_pagini": 31,
    "rezultate": [
        {
            "acquisition_id": 98765432,
            "cod_unic": "DA12345678",
            "denumire": "Materiale de construcții",
            "descriere": "conform comenzii 826563",
            "valoare_estimata": 18000,
            "valoare_estimata_eur": 222.05,
            "valoare_inchidere": 17450,
            "valoare_inchidere_eur": 222.05,
            "economie": 550,
            "economie_eur": null,
            "economie_procent": 3.06,
            "depasire": null,
            "depasire_eur": null,
            "depasire_procent": null,
            "data_publicare": "2026-06-02",
            "data_decizie_furnizor": "2026-10-22T13:49:27+03:00",
            "data_decizie_autoritate": "2026-10-22T13:57:47+03:00",
            "data_finalizare": "2026-06-05",
            "deadline_decizie_furnizor": "2026-10-30T17:00:00+02:00",
            "deadline_decizie_autoritate": "2026-10-27T17:00:00+02:00",
            "cpv_cod": "44100000-1",
            "cpv_descriere": "Materiale de construcții și articole conexe",
            "tip_contract": "Furnizare",
            "stare": "Oferta acceptata",
            "conditii_livrare": "Livrarea se va face in 3-5 zile si este inclusa in pret.",
            "conditii_plata": "Plata se va face in termen de 30 de zile de la emiterea facturii.",
            "furnizor_id": 100210917,
            "autoritate_id": 4321,
            "fonduri_ue": false,
            "fond_ue_denumire": null,
            "nr_documente_atasate": 1,
            "nr_produse": 3
        }
    ],
    "cost": {
        "credite_consumate": 100,
        "per_rezultat": 5,
        "tip": "general"
    }
}
```

| Câmp | Tip | Descriere |
|---|---|---|
| `success` | boolean | true la răspunsurile reușite. |
| `pagina · per_pagina · total · total_pagini` | integer | Paginarea. |
| `rezultate[]` | array | Notificări de atribuire sau achiziții directe, în formatul de mai sus. |
| `cost.credite_consumate · per_rezultat · tip` | mixed | Costul cererii: 5 credite generale per rezultat. |
| `rezultate[].acquisition_id · cod_unic · denumire · descriere` | mixed | Identificarea achiziției. |
| `rezultate[].valoare_estimata · valoare_inchidere (+ _eur)` | number | Valoarea estimată și cea finală. |
| `rezultate[].economie · economie_procent · depasire · depasire_procent` | number | Diferența față de estimare. |
| `rezultate[].data_publicare · data_decizie_* · deadline_decizie_* · data_finalizare` | string | Calendarul achiziției. |
| `rezultate[].cpv_cod · cpv_descriere · tip_contract · stare` | string | Clasificarea și starea. |
| `rezultate[].conditii_livrare · conditii_plata` | string | Condițiile comerciale. |
| `rezultate[].furnizor_id · autoritate_id` | integer | Părțile, ca entity_id SICAP. |
| `rezultate[].nr_documente_atasate · nr_produse` | integer | Documente și produse. Cu ?include=produse primești și lista produse[]. |

Reguli:

- Costul este 5 credite per rezultat întors; o pagină fără rezultate nu costă nimic.

### 2.5 Atribuirile câștigate de un furnizor — `GET /sicap/furnizor/{id}/atribuiri`

Cost: **5 / rezultat** per cerere reușită (2xx). Erorile nu se taxează.

Lista completă a contractelor câștigate prin atribuire.

| Parametru | Unde | Tip | Obligatoriu | Descriere |
|---|---|---|---|---|
| `id` | cale | integer | da | CUI-ul sau entity_id-ul SICAP al furnizorului. Ex.: `100210917`. |
| `cpv` | query | string | nu | Codul CPV al categoriei. Ex.: `45233142-6`. |
| `data_start · data_end` | query | dată | nu | Intervalul datei de publicare. Ex.: `2025-01-01`. |
| `valoare_min · valoare_max` | query | number | nu | Intervalul valorii, în lei. |
| `q` | query | string | nu | Text liber în obiectul contractului (minim 2 caractere). Ex.: `reparații drum`. |
| `pagina` | query | integer | nu | Pagina, de la 1. |
| `per_pagina` | query | integer | nu | Rezultate pe pagină, maxim 20. |

Exemplu: `GET https://www.firmeapi.ro/api/v1/sicap/furnizor/100210917/atribuiri`

Răspuns 200 (date fictive, aceeași formă ca răspunsul real):

```json
{
    "success": true,
    "pagina": 1,
    "per_pagina": 20,
    "total": 247,
    "total_pagini": 13,
    "rezultate": [
        {
            "notice_id": 1234567,
            "numar_notificare": "DAN1234567",
            "data_publicare": "2026-07-28",
            "data_contract": "2026-07-20",
            "data_finalizare": "2026-10-26T00:00:00+02:00",
            "obiect_contract": "Reparații drum comunal",
            "valoare_atribuita": 125400,
            "valoare_atribuita_eur": 25200,
            "moneda": "RON",
            "cpv_cod": "45233142-6",
            "cpv_descriere": "Lucrări de reparare a drumurilor",
            "tip_contract": "Lucrari",
            "tip_achizitie": "Offline",
            "online": false,
            "stare": "Publicat",
            "furnizor_cui": "12345678",
            "furnizor_denumire": "EXEMPLU CONSTRUCT S.R.L.",
            "furnizor_adresa": "Strada: Tolstoi Alexei, nr. 8, Sector: -, Judet: Bacau, Localitate: Bacau, Cod postal: 600093",
            "furnizor_localitate": "Bacau",
            "furnizor_cod_postal": "600093",
            "furnizor_telefon": "0212345678",
            "furnizor_email": "office@exemplu.ro",
            "furnizor_website": null,
            "autoritate_id": 4321,
            "fonduri_ue": false,
            "fond_ue_denumire": null
        }
    ],
    "cost": {
        "credite_consumate": 100,
        "per_rezultat": 5,
        "tip": "general"
    }
}
```

| Câmp | Tip | Descriere |
|---|---|---|
| `success` | boolean | true la răspunsurile reușite. |
| `pagina · per_pagina · total · total_pagini` | integer | Paginarea. |
| `rezultate[]` | array | Notificări de atribuire sau achiziții directe, în formatul de mai sus. |
| `cost.credite_consumate · per_rezultat · tip` | mixed | Costul cererii: 5 credite generale per rezultat. |
| `rezultate[].notice_id · numar_notificare` | mixed | Identificatorul intern și numărul notificării. |
| `rezultate[].data_publicare · data_contract · data_finalizare` | string | Datele notificării și ale contractului. |
| `rezultate[].obiect_contract` | string | Ce s-a contractat. |
| `rezultate[].valoare_atribuita · valoare_atribuita_eur · moneda` | number | Valoarea în lei și în euro. |
| `rezultate[].cpv_cod · cpv_descriere` | string | Categoria CPV. |
| `rezultate[].tip_contract · tip_achizitie · online · stare` | mixed | Clasificarea și starea notificării. |
| `rezultate[].furnizor_cui · furnizor_denumire · furnizor_*` | string | Câștigătorul: CUI, denumire, adresă, localitate, cod poștal, contact. |
| `rezultate[].autoritate_id` | integer | entity_id-ul autorității contractante. |
| `rezultate[].fonduri_ue · fond_ue_denumire` | mixed | Finanțarea din fonduri europene și programul. |

Reguli:

- Costul este 5 credite per rezultat întors; o pagină fără rezultate nu costă nimic.

### 2.6 Achizițiile directe câștigate de un furnizor — `GET /sicap/furnizor/{id}/achizitii`

Cost: **5 / rezultat** per cerere reușită (2xx). Erorile nu se taxează.

Achizițiile directe (fără licitație) câștigate de firmă. Complementar cu atribuirile.

| Parametru | Unde | Tip | Obligatoriu | Descriere |
|---|---|---|---|---|
| `id` | cale | integer | da | CUI-ul sau entity_id-ul SICAP al furnizorului. Ex.: `100210917`. |
| `cpv` | query | string | nu | Codul CPV al categoriei. Ex.: `45233142-6`. |
| `data_start · data_end` | query | dată | nu | Intervalul datei de publicare. Ex.: `2025-01-01`. |
| `valoare_min · valoare_max` | query | number | nu | Intervalul valorii, în lei. |
| `q` | query | string | nu | Text liber în obiectul contractului (minim 2 caractere). Ex.: `reparații drum`. |
| `pagina` | query | integer | nu | Pagina, de la 1. |
| `per_pagina` | query | integer | nu | Rezultate pe pagină, maxim 20. |
| `include` | query | string | nu | produse = adaugă lista produselor fiecărei achiziții. Valori: `produse`. |

Exemplu: `GET https://www.firmeapi.ro/api/v1/sicap/furnizor/100210917/achizitii`

Răspuns 200 (date fictive, aceeași formă ca răspunsul real):

```json
{
    "success": true,
    "pagina": 1,
    "per_pagina": 20,
    "total": 612,
    "total_pagini": 31,
    "rezultate": [
        {
            "acquisition_id": 98765432,
            "cod_unic": "DA12345678",
            "denumire": "Materiale de construcții",
            "descriere": "10 5020060 PLACA RINOVA ANTIUME.H\n12,5X1200X2600 MM\nBUC 1,00 58,99 48,75 10,24\n20 4006653 SURUB AUTOP INECAT 4.2X25\n39601B4202500\nBUC\n200,00\n0,16 26,45 5,55\n30 5021612 PROFIL GYPSERRA CD60X4000X0,6\nMM\nBUC 2,00 40,91 67,6…",
            "valoare_estimata": 18000,
            "valoare_estimata_eur": 171.8,
            "valoare_inchidere": 17450,
            "valoare_inchidere_eur": 171.8,
            "economie": 550,
            "economie_eur": null,
            "economie_procent": 3.06,
            "depasire": null,
            "depasire_eur": null,
            "depasire_procent": null,
            "data_publicare": "2026-06-02",
            "data_decizie_furnizor": "2026-10-26T17:15:28+02:00",
            "data_decizie_autoritate": null,
            "data_finalizare": "2026-06-05",
            "deadline_decizie_furnizor": "2026-10-30T17:00:00+02:00",
            "deadline_decizie_autoritate": "2026-10-31T17:00:00+02:00",
            "cpv_cod": "44100000-1",
            "cpv_descriere": "Materiale de construcții și articole conexe",
            "tip_contract": "Furnizare",
            "stare": "Oferta acceptata",
            "conditii_livrare": "Livrare la sediul autorității",
            "conditii_plata": "Plata se va efectua cu ordin de plata în contul de Trezorerie al furnizorului în termen de 30 (treizeci) de zile de la transmiterea facturii în sistemul electronic RO e-Factura pentru prestarea serviciilor, terminarea lu…",
            "furnizor_id": 100210917,
            "autoritate_id": 4321,
            "fonduri_ue": false,
            "fond_ue_denumire": null,
            "nr_documente_atasate": 1,
            "nr_produse": 3
        }
    ],
    "cost": {
        "credite_consumate": 100,
        "per_rezultat": 5,
        "tip": "general"
    }
}
```

| Câmp | Tip | Descriere |
|---|---|---|
| `success` | boolean | true la răspunsurile reușite. |
| `pagina · per_pagina · total · total_pagini` | integer | Paginarea. |
| `rezultate[]` | array | Notificări de atribuire sau achiziții directe, în formatul de mai sus. |
| `cost.credite_consumate · per_rezultat · tip` | mixed | Costul cererii: 5 credite generale per rezultat. |
| `rezultate[].acquisition_id · cod_unic · denumire · descriere` | mixed | Identificarea achiziției. |
| `rezultate[].valoare_estimata · valoare_inchidere (+ _eur)` | number | Valoarea estimată și cea finală. |
| `rezultate[].economie · economie_procent · depasire · depasire_procent` | number | Diferența față de estimare. |
| `rezultate[].data_publicare · data_decizie_* · deadline_decizie_* · data_finalizare` | string | Calendarul achiziției. |
| `rezultate[].cpv_cod · cpv_descriere · tip_contract · stare` | string | Clasificarea și starea. |
| `rezultate[].conditii_livrare · conditii_plata` | string | Condițiile comerciale. |
| `rezultate[].furnizor_id · autoritate_id` | integer | Părțile, ca entity_id SICAP. |
| `rezultate[].nr_documente_atasate · nr_produse` | integer | Documente și produse. Cu ?include=produse primești și lista produse[]. |

Reguli:

- Costul este 5 credite per rezultat întors; o pagină fără rezultate nu costă nimic.

### 2.7 Achizițiile făcute de o autoritate — `GET /sicap/autoritate/{id}/achizitii`

Cost: **5 / rezultat** per cerere reușită (2xx). Erorile nu se taxează.

Toate achizițiile directe făcute de o instituție publică.

| Parametru | Unde | Tip | Obligatoriu | Descriere |
|---|---|---|---|---|
| `id` | cale | integer | da | CUI-ul sau entity_id-ul SICAP al autorității. Ex.: `100210917`. |
| `cpv` | query | string | nu | Codul CPV al categoriei. Ex.: `45233142-6`. |
| `data_start · data_end` | query | dată | nu | Intervalul datei de publicare. Ex.: `2025-01-01`. |
| `valoare_min · valoare_max` | query | number | nu | Intervalul valorii, în lei. |
| `q` | query | string | nu | Text liber în obiectul contractului (minim 2 caractere). Ex.: `reparații drum`. |
| `pagina` | query | integer | nu | Pagina, de la 1. |
| `per_pagina` | query | integer | nu | Rezultate pe pagină, maxim 20. |
| `include` | query | string | nu | produse = adaugă lista produselor fiecărei achiziții. Valori: `produse`. |

Exemplu: `GET https://www.firmeapi.ro/api/v1/sicap/autoritate/4321/achizitii?data_start=2026-01-01`

Răspuns 200 (date fictive, aceeași formă ca răspunsul real):

```json
{
    "success": true,
    "pagina": 1,
    "per_pagina": 20,
    "total": 612,
    "total_pagini": 31,
    "rezultate": [
        {
            "acquisition_id": 98765432,
            "cod_unic": "DA12345678",
            "denumire": "Materiale de construcții",
            "descriere": "conform comenzii 826563",
            "valoare_estimata": 18000,
            "valoare_estimata_eur": 222.05,
            "valoare_inchidere": 17450,
            "valoare_inchidere_eur": 222.05,
            "economie": 550,
            "economie_eur": null,
            "economie_procent": 3.06,
            "depasire": null,
            "depasire_eur": null,
            "depasire_procent": null,
            "data_publicare": "2026-06-02",
            "data_decizie_furnizor": "2026-10-22T13:49:27+03:00",
            "data_decizie_autoritate": "2026-10-22T13:57:47+03:00",
            "data_finalizare": "2026-06-05",
            "deadline_decizie_furnizor": "2026-10-30T17:00:00+02:00",
            "deadline_decizie_autoritate": "2026-10-27T17:00:00+02:00",
            "cpv_cod": "44100000-1",
            "cpv_descriere": "Materiale de construcții și articole conexe",
            "tip_contract": "Furnizare",
            "stare": "Oferta acceptata",
            "conditii_livrare": "Livrarea se va face in 3-5 zile si este inclusa in pret.",
            "conditii_plata": "Plata se va face in termen de 30 de zile de la emiterea facturii.",
            "furnizor_id": 100210917,
            "autoritate_id": 4321,
            "fonduri_ue": false,
            "fond_ue_denumire": null,
            "nr_documente_atasate": 1,
            "nr_produse": 3
        }
    ],
    "cost": {
        "credite_consumate": 100,
        "per_rezultat": 5,
        "tip": "general"
    }
}
```

| Câmp | Tip | Descriere |
|---|---|---|
| `success` | boolean | true la răspunsurile reușite. |
| `pagina · per_pagina · total · total_pagini` | integer | Paginarea. |
| `rezultate[]` | array | Notificări de atribuire sau achiziții directe, în formatul de mai sus. |
| `cost.credite_consumate · per_rezultat · tip` | mixed | Costul cererii: 5 credite generale per rezultat. |
| `rezultate[].acquisition_id · cod_unic · denumire · descriere` | mixed | Identificarea achiziției. |
| `rezultate[].valoare_estimata · valoare_inchidere (+ _eur)` | number | Valoarea estimată și cea finală. |
| `rezultate[].economie · economie_procent · depasire · depasire_procent` | number | Diferența față de estimare. |
| `rezultate[].data_publicare · data_decizie_* · deadline_decizie_* · data_finalizare` | string | Calendarul achiziției. |
| `rezultate[].cpv_cod · cpv_descriere · tip_contract · stare` | string | Clasificarea și starea. |
| `rezultate[].conditii_livrare · conditii_plata` | string | Condițiile comerciale. |
| `rezultate[].furnizor_id · autoritate_id` | integer | Părțile, ca entity_id SICAP. |
| `rezultate[].nr_documente_atasate · nr_produse` | integer | Documente și produse. Cu ?include=produse primești și lista produse[]. |

Reguli:

- Costul este 5 credite per rezultat întors; o pagină fără rezultate nu costă nimic.

## 3. Testare

Endpoint-urile acestui API nu au sandbox. Pentru testele automate, folosește răspunsurile din secțiunea 2 ca fixture (mock HTTP pe clientul tău). Pentru o verificare reală, fă o singură cerere cu cheia utilizatorului: erorile și răspunsurile 404 nu consumă credite.

## 4. Erori

Corpul unei erori: `{ "success": false, "error": "...", "code": "...", "message": "..." }` (câmpul `message` poate lipsi). Decide după statusul HTTP și `code`, nu după text. Nicio eroare nu consumă credite.

| HTTP | code | Când apare | Ce face integrarea | Reîncearcă |
|---|---|---|---|---|
| 401 | AUTH_MISSING_KEY, AUTH_INVALID_KEY, AUTH_KEY_EXPIRED | Cheia lipsește, e greșită sau a expirat. | Eroare de configurare: loghează și verifică FIRMEAPI_KEY. | nu |
| 403 | CREDITS_EXHAUSTED | Creditele nu acoperă cererea. | Mesaj către utilizator cu required_credits și linkul din buy_credits_url. | nu |
| 403 | ACCESS_DENIED_IP, ACCESS_DENIED_SCOPE | Cheia e limitată la alte IP-uri sau endpoint-uri. | Eroare de configurare a cheii, din contul FirmeAPI. | nu |
| 403 | MONTHLY_LIMIT_REACHED | Planul gratuit și-a atins limita lunară de cereri. | Mesaj către utilizator cu linkul din upgrade_url. | nu |
| 404 | — | Firma sau autoritatea nu apare în SICAP. Nu se consumă credite. | Afișează „fără date”. Păstrează în cache scurt (de exemplu o oră). | nu |
| 422 | VALIDATION_FAILED | Un parametru e invalid sau lipsește unul obligatoriu. | Arată eroarea din errors, pe câmp. Validează înainte de cerere. | nu |
| 429 | LIMIT_EXCEEDED_SECOND | Prea multe cereri într-o secundă. | Așteaptă retry_after secunde și reia cererea. | da |
| 429 | LIMIT_EXCEEDED_DAILY, LIMIT_EXCEEDED_MONTHLY | Limita zilnică sau lunară a planului. | Oprește cererile până la retry_after și anunță utilizatorul. | nu |
| 500 | — | Eroare neașteptată pe server. | Reîncearcă de cel mult 3 ori, la 1, 2 și 4 secunde. | da |
| 503 | SICAP_UNAVAILABLE | Serviciul e temporar indisponibil. | Reîncearcă de cel mult 3 ori, la 1, 2 și 4 secunde. | da |

## 5. Reguli de domeniu și de integrare

1. Atribuiri față de achiziții directe: Atribuirile sunt contracte câștigate prin proceduri competitive, de regulă cu valori mari. Achizițiile directe sunt cumpărături sub pragurile legale, făcute din catalogul SEAP. API-ul le ține separat.
2. Normalizează CUI-ul înainte de cerere: elimină prefixul RO, spațiile și orice caracter care nu e cifră.
3. Un câmp `null` înseamnă că sursa nu are informația: nu îl transforma în 0 sau în șir gol.
4. Apelurile se fac din backend; cheia API nu ajunge niciodată în browser sau în aplicația mobilă.
5. Păstrează rezultatele în cache pe cheia cererii; nu repeta aceeași cerere la fiecare afișare.

## 6. Header-e de răspuns utile

| Header | Conținut |
|---|---|
| `X-Credit-Cost` | Creditele consumate de cerere. |
| `X-Credit-Type` | Tipul creditelor folosite de endpoint. |
| `X-Credit-Balance-General` | Soldul de credite generale. |
| `X-Credit-Balance-{TIP}` | Soldul pentru tipul cererii, când nu e general (de exemplu X-Credit-Balance-ACTIONARI). |
| `X-RateLimit-Limit-Second · -Day · -Month` | Limitele planului. |
| `X-RateLimit-Remaining-Second · -Day · -Month` | Cât a mai rămas din fiecare limită. |

## 7. Implementare de referință

TypeScript / Node 18+ (tradu în limbajul proiectului dacă e altul):

```ts
const BASE = "https://www.firmeapi.ro/api/v1";

export class FirmeApiError extends Error {
  constructor(public status: number, public code: string | null, message: string, public body: unknown) {
    super(message);
  }
}

type Query = Record<string, string | number | boolean | undefined>;

async function call<T>(path: string, query?: Query): Promise<T> {
  const url = new URL(BASE + path);
  for (const [k, v] of Object.entries(query ?? {})) if (v !== undefined) url.searchParams.set(k, String(v));

  for (let attempt = 0; ; attempt++) {
    const res = await fetch(url, { headers: { "X-API-KEY": process.env.FIRMEAPI_KEY ?? "", Accept: "application/json" }, signal: AbortSignal.timeout(30_000) });
    const body: any = await res.json().catch(() => null);
    if (res.ok) return body as T;

    const code = body?.code ?? null;
    const retriable = res.status >= 500 || code === "LIMIT_EXCEEDED_SECOND";
    if (retriable && attempt < 3) {
      const wait = code === "LIMIT_EXCEEDED_SECOND" ? (body?.retry_after ?? 1) * 1000 : 1000 * 2 ** attempt;
      await new Promise((r) => setTimeout(r, wait));
      continue;
    }
    throw new FirmeApiError(res.status, code, body?.message ?? body?.error ?? res.statusText, body);
  }
}

/** 404 = fără date (netaxat): întoarce null în loc de excepție. */
async function orNull<T>(p: Promise<T>): Promise<T | null> {
  try {
    return await p;
  } catch (e) {
    if (e instanceof FirmeApiError && e.status === 404) return null;
    throw e;
  }
}

export const normalizeCui = (input: string) => input.replace(/^\s*RO/i, "").replace(/\D/g, "");

// Câte o funcție pentru fiecare endpoint (tipează răspunsurile după câmpurile din secțiunea 2).
export const sicapFirma = (cui: string) => orNull(call<any>(`/sicap/${normalizeCui(cui)}`));
export const sicapAutoritate = (cui: string) => orNull(call<any>(`/sicap/autoritate/${normalizeCui(cui)}`));
export const sicapAtribuiri = (query: Query = {}) => call<any>(`/sicap/atribuiri/lista`, query);
export const sicapAchizitii = (query: Query = {}) => call<any>(`/sicap/achizitii/lista`, query);
export const sicapFurnizorAtribuiri = (id: string, query: Query = {}) => orNull(call<any>(`/sicap/furnizor/${encodeURIComponent(id)}/atribuiri`, query));
export const sicapFurnizorAchizitii = (id: string, query: Query = {}) => orNull(call<any>(`/sicap/furnizor/${encodeURIComponent(id)}/achizitii`, query));
export const sicapAutoritateAchizitii = (id: string, query: Query = {}) => orNull(call<any>(`/sicap/autoritate/${encodeURIComponent(id)}/achizitii`, query));
```

Echivalent PHP (Laravel):

```php
use Illuminate\Http\Client\RequestException;
use Illuminate\Support\Facades\Http;

// config/services.php: 'firmeapi' => ['key' => env('FIRMEAPI_KEY')]
$res = Http::withHeaders(['X-API-KEY' => config('services.firmeapi.key')])->acceptJson()
    ->timeout(30)
    ->retry(3, fn (int $attempt) => 1000 * 2 ** ($attempt - 1),
        fn ($e) => $e instanceof RequestException && $e->response->serverError(), throw: false)
    ->get('https://www.firmeapi.ro/api/v1/sicap/12345678');

if ($res->status() === 404) return null;   // fără date, netaxat
$res->throw();                              // restul erorilor: vezi secțiunea 4
$data = $res->json();
```

Echivalent Python:

```python
import os, time, requests

BASE = "https://www.firmeapi.ro/api/v1"

def call(path: str, params: dict | None = None):
    for attempt in range(4):
        r = requests.get(BASE + path, params=params, timeout=30,
                         headers={"X-API-KEY": os.environ["FIRMEAPI_KEY"], "Accept": "application/json"})
        if r.status_code == 404:
            return None                      # fără date, netaxat
        retriable = r.status_code >= 500 or (r.status_code == 429 and r.json().get("code") == "LIMIT_EXCEEDED_SECOND")
        if retriable and attempt < 3:
            time.sleep(r.json().get("retry_after", 1) if r.status_code == 429 else 2 ** attempt)
            continue
        r.raise_for_status()
        return r.json()
```

## 8. Teste de acceptanță

1. `sicapFirma` cu cererea `/sicap/12345678` întoarce 200 și se parsează în câmpurile din secțiunea 2 (fixture).
2. `sicapAutoritate` cu cererea `/sicap/autoritate/4305857` întoarce 200 și se parsează în câmpurile din secțiunea 2 (fixture).
3. `sicapAtribuiri` cu cererea `/sicap/atribuiri/lista?cpv=45233142-6&valoare_min=100000` întoarce 200 și se parsează în câmpurile din secțiunea 2 (fixture).
4. `sicapAchizitii` cu cererea `/sicap/achizitii/lista?cui_autoritate=4305857&data_start=2026-01-01` întoarce 200 și se parsează în câmpurile din secțiunea 2 (fixture).
5. `sicapFurnizorAtribuiri` cu cererea `/sicap/furnizor/100210917/atribuiri` întoarce 200 și se parsează în câmpurile din secțiunea 2 (fixture).
6. `sicapFurnizorAchizitii` cu cererea `/sicap/furnizor/100210917/achizitii` întoarce 200 și se parsează în câmpurile din secțiunea 2 (fixture).
7. `sicapAutoritateAchizitii` cu cererea `/sicap/autoritate/4321/achizitii?data_start=2026-01-01` întoarce 200 și se parsează în câmpurile din secțiunea 2 (fixture).
8. Un CUI scris `RO 12345678` e normalizat la `12345678` înainte de cerere.
9. Un răspuns 404 devine „fără date” (null sau listă goală), fără excepție.
10. Un 503 sau 500 e reîncercat de cel mult 3 ori; un 401 sau 403 nu e reîncercat.
11. Un 429 `LIMIT_EXCEEDED_SECOND` așteaptă `retry_after` secunde și reia cererea.
12. A doua cerere identică vine din cache, fără cerere HTTP.

## 9. Alternativa fără cod: MCP

Dacă utilizatorul vrea ca un asistent AI să interogheze datele direct (nu o integrare în aplicație), folosește serverul MCP: `https://www.firmeapi.ro/api/mcp` cu header-ul `Authorization: Bearer <cheie>`. Tool-uri: `sicap`, `sicap_autoritate`, `sicap_atribuiri`, `sicap_achizitii`, `sicap_furnizor_atribuiri`, `sicap_furnizor_achizitii`, `sicap_autoritate_achizitii`, cu aceleași costuri. Ghid pe fiecare client: https://www.firmeapi.ro/mcp

## Legături

- Pagina API-ului: https://www.firmeapi.ro/info-api/achizitii-publice-sicap
- Acest ghid (Markdown): https://www.firmeapi.ro/info-api/achizitii-publice-sicap.md
- Specificația OpenAPI: https://www.firmeapi.ro/api/mcp/openapi.json
- Documentația generală: https://www.firmeapi.ro/docs
- Rezumat pentru LLM-uri: https://www.firmeapi.ro/llms.txt
