api-cui.ro
Documentație

Tot API-ul, pe o singură pagină.

Un endpoint pentru fișa firmei, unul pentru căutare, câteva validări și cursul BNR. Cheia în antet, JSON înapoi. Dacă știi curl, știi deja tot.

Primii pași

Bază: https://api-cui.ro/v1. Toate răspunsurile sunt JSON, UTF-8, cu diacritice reale (nu ș). Datele sunt ISO 8601 (2026-09-21).

curl https://api-cui.ro/v1/firma/14399840 -H "X-Api-Key: ck_..."

Cheia o iei din cont, în 30 de secunde. Contul gratuit e o probă de 30 de zile cu 50 de cereri.

Autentificare

Cheia se trimite în antetul X-Api-Key (sau Authorization: Bearer <cheie>). Sunt două feluri de chei:

tipprefixundeprotecție
secretăck_pe server (ERP, facturare, importuri)nu o trimite niciodată în URL sau în browser
publicăpk_în browser (checkout, formulare)merge doar de pe domeniile aprobate în panou (verificăm Origin); poate fi trimisă și ca ?cheie=pk_...
de testtk_dezvoltare, teste automatenu consumă cotă; date reale pentru CUI 14399840, 13548146, 6859662, 18547290, 47310601 și fictive (deterministe, FIRMA TEST … S.R.L., meta.test: true) pentru orice alt CUI valid

Răspunsurile pentru cheile publice includ antetele CORS pentru domeniul de origine. Cheile se pot roti din cont: cea nouă apare imediat, cea veche mai merge 24 de ore.

GET/v1/firma/{cui}

Fișa firmei. {cui} acceptă și forma RO14399840 sau cu spații. Se validează cifra de control înainte de orice.

câmpce e
cui, cui_ronumărul; cui_ro are prefixul RO când firma e plătitoare de TVA
denumire, nr_reg_com, cod_caen, forma_juridica, forma_organizare, forma_proprietate, organ_fiscal, telefon, faxidentificare, așa cum le are ANAF
stare.activatrue dacă nu e radiată și nu e inactivă fiscal
stare.text, stare.data_inregistrare, stare.radiata, stare.data_radiere, stare.inactiv_fiscal, stare.data_inactivare, stare.data_reactivaredetaliile stării
tva.platitor, tva.de_la, tva.pana_la, tva.perioade[]înregistrarea în scopuri de TVA
tva.la_incasare (+ _de_la, _pana_la), tva.splitTVA la încasare, split TVA
efactura, efactura_de_laînregistrarea în Registrul RO e-Factura
adresa_sediu, adresa_fiscalaobiecte cu judet, judet_auto, localitate, strada, numar, detalii, cod_postal, cod_judet, cod_localitate, tara și text (pe o linie)
adresa_anaftextul brut al ANAF, pentru comparație
verificat_lacând am citit ultima oară fișa de la ANAF
meta.mscât a durat pe server

?extins=1

Adaugă, în același răspuns: bilanturi[] (ultimii 3 ani: an, caen, cifra_afaceri, profit_net, venituri, cheltuieli, angajati, datorii, capitaluri, active), registru (cod_j, stare ONRC, data_inmatriculare, euid, web), persoane[] (nume, calitate — administratori, asociați), contacte[] (fel: email / telefon / site, valoare) și bani_publici (achiziții directe și contracte din SEAP, în lei).

curl "https://api-cui.ro/v1/firma/14399840?extins=1" -H "X-Api-Key: ck_..."

POST/v1/firme

Până la 100 de CUI-uri într-o singură cerere — pentru importuri, ERP, verificări periodice. Corp JSON: {"cui": ["14399840", "RO13548146", …], "extins": false}. Răspuns: {"firme": {"14399840": {…}, …}, "lipsa": ["…"], "invalide": ["…"]}. Fiecare CUI găsit consumă o cerere din cotă (cele invalide/lipsă nu); dacă lotul depășește cota rămasă primești 429 cota_insuficienta înainte de a consuma ceva. Disponibil pe planurile plătite.

curl -X POST https://api-cui.ro/v1/firme -H "X-Api-Key: ck_..." -H "Content-Type: application/json" \
  -d '{"cui": ["14399840", "13548146", "6859662"]}'

Snippet pentru orice formular

Fără cod: incluzi scriptul cu o cheie publică și marchezi câmpurile cu data-api-cui. Când clientul scrie un CUI valid în câmpul cui, restul se completează.

<script src="https://api-cui.ro/static/precompletare.js" data-cheie="pk_..."></script>

<input data-api-cui="cui" placeholder="CUI">            <span data-api-cui-stare></span>
<input data-api-cui="denumire">                          <input data-api-cui="nr_reg_com">
<input data-api-cui="adresa_sediu.strada_nr">            <input data-api-cui="adresa_sediu.oras">
<input data-api-cui="adresa_sediu.judet">                <input data-api-cui="adresa_sediu.cod_postal">
<input type="checkbox" data-api-cui="tva.platitor"> plătitor de TVA

Valoarea din data-api-cui e calea din răspunsul JSON (adresa_sediu.strada, tva.platitor, cod_caen…) plus trei scurtături: adresa_sediu.strada_nr (stradă + număr), adresa_sediu.oras (localitatea curățată de „Mun.”, „Orș.”) și tva.platitor_text („da”/„nu”). Merge cu <select> (potrivește după valoare sau text) și cu checkbox. Evenimentul api-cui:firma pe document primește tot răspunsul, dacă vrei logică proprie. Cheia publică trebuie să aibă domeniul site-ului în panou.

Exemple de cod

Gata de copiat. Cheia secretă (ck_) stă pe server, citită din configurare, nu scrisă în cod. Specificația completă e în /openapi.json (OpenAPI 3): o poți importa în Postman, Insomnia sau într-un generator de client.

PHP

$ch = curl_init('https://api-cui.ro/v1/firma/' . rawurlencode($cui));
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT        => 5,
    CURLOPT_HTTPHEADER     => ['X-Api-Key: ' . getenv('APICUI_KEY')],
]);
$firma = json_decode(curl_exec($ch), true);
if (curl_getinfo($ch, CURLINFO_HTTP_CODE) === 200) {
    echo $firma['denumire'], ' · ', $firma['adresa_sediu']['text'];
}

JavaScript (Node.js 18+)

const r = await fetch(`https://api-cui.ro/v1/firma/${encodeURIComponent(cui)}`, {
  headers: { 'X-Api-Key': process.env.APICUI_KEY },
});
if (r.ok) {
  const firma = await r.json();
  console.log(firma.denumire, firma.tva.platitor);
}

Python

import os, requests

r = requests.get(f"https://api-cui.ro/v1/firma/{cui}",
                 headers={"X-Api-Key": os.environ["APICUI_KEY"]}, timeout=5)
if r.ok:
    firma = r.json()
    print(firma["denumire"], firma["stare"]["activa"])

C# (.NET 6+)

using var http = new HttpClient();
http.DefaultRequestHeaders.Add("X-Api-Key", Environment.GetEnvironmentVariable("APICUI_KEY"));
var r = await http.GetAsync($"https://api-cui.ro/v1/firma/{Uri.EscapeDataString(cui)}");
if (r.IsSuccessStatusCode)
{
    using var doc = System.Text.Json.JsonDocument.Parse(await r.Content.ReadAsStringAsync());
    Console.WriteLine(doc.RootElement.GetProperty("denumire").GetString());
}

Toate exemplele merg la fel cu cheia de test tk_, care nu consumă din cotă.

Google Sheets: funcția =CUI()

Pui CUI-urile într-o coloană și primești denumirea, adresa, TVA-ul sau orice alt câmp, direct în foaie. Fără supliment de instalat: un script de 20 de rânduri.

1. În foaie: Extensii → Apps Script. 2. Ștergi ce e acolo, lipești codul de mai jos și pui cheia ta. 3. Salvezi și te întorci în foaie.

const CHEIE = 'ck_...';   // cheia ta secretă

/**
 * Date despre firmă din CUI, de la api-cui.ro.
 * @param {string} cui CUI-ul, cu sau fără RO
 * @param {string} camp câmpul din răspuns: denumire (implicit), nr_reg_com,
 *   adresa_sediu.text, adresa_sediu.judet, tva.platitor, stare.activa, cod_caen...
 * @customfunction
 */
function CUI(cui, camp) {
  if (!cui) return '';
  const cheieCache = 'cui_' + String(cui).replace(/\D/g, '');
  const cache = CacheService.getScriptCache();
  let text = cache.get(cheieCache);
  if (!text) {
    const r = UrlFetchApp.fetch('https://api-cui.ro/v1/firma/' + encodeURIComponent(String(cui)),
      { headers: { 'X-Api-Key': CHEIE }, muteHttpExceptions: true });
    if (r.getResponseCode() !== 200) return 'eroare ' + r.getResponseCode();
    text = r.getContentText();
    cache.put(cheieCache, text, 21600);   // 6 ore: recalcularea foii nu consumă din cotă
  }
  const v = (camp || 'denumire').split('.').reduce((o, p) => (o == null ? o : o[p]), JSON.parse(text));
  return v !== null && typeof v === 'object' ? JSON.stringify(v) : v;
}

În celule: =CUI(A2) pentru denumire, =CUI(A2; "adresa_sediu.text"), =CUI(A2; "tva.platitor"). Foile în limba română folosesc ; între argumente, cele în engleză ,. Fiecare CUI consumă o cerere o singură dată la 6 ore, oricât ar recalcula foaia.

Atenție: oricine are drept de editare pe foaie poate vedea scriptul, deci și cheia. Pentru foi partajate, fă-ți o cheie separată din cont, ca s-o poți revoca fără să le afectezi pe celelalte.

GET/v1/firma/{cui}/bilanturi

Toți anii disponibili (din 2011), cu aceleași câmpuri ca la extins. Sursa: Ministerul Finanțelor, date deschise.

GET/v1/firme/cauta?q=&judet=&limita=&doar_active=

Autocomplete după denumire. Minimum 3 litere; ignoră diacriticele, punctuația și cuvintele „SC”, „SRL”, „SA”, „PFA”. Întâi potrivire de prefix (sub 2 ms); dacă nu găsește nimic, caută și în interiorul numelui. limita ≤ 25, implicit 10. doar_active=0 include firmele radiate.

curl "https://api-cui.ro/v1/firme/cauta?q=dante+intern&judet=bucuresti" -H "X-Api-Key: ck_..."
{"rezultate":[{"cui":14399840,"denumire":"DANTE INTERNATIONAL SA","judet":"MUNICIPIUL BUCUREȘTI","localitate":"Sector 6 Mun. București","activa":true,"tva":true}],"meta":{"ms":1.1}}

Câmpuri: cui, denumire, judet, localitate, activa (nu e radiată/inactivă), tva (plătitor). Pentru restul fișei ceri apoi /v1/firma/{cui}. Tabela de căutare se reconstruiește săptămânal.

GET/v1/valideaza/cui/{cui} · /cnp/{cnp} · /iban/{iban}

Validări de format, fără să atingă baza. Nu stocăm nimic din ce ne trimiți aici.

endpointrăspuns
/valideaza/cui/RO14399840{"cui":"RO14399840","valid":true,"cui_numeric":14399840}
/valideaza/cnp/1960101123456{"cnp":"…","valid":true,"sex":"M","data_nasterii":"1996-01-01","rezident_strain":false,"cod_judet":"12","judet":"Cluj"}
/valideaza/iban/RO49AAAA1B31007593840000{"iban":"…","valid":true,"banca_cod":"AAAA","tara":"RO"}

GET/v1/curs?data=&moneda=

Cursul BNR, cu istoric zilnic din ianuarie 2015; ziua curentă apare după publicarea BNR de la 13:00. Fără parametri: ultima zi publicată, toate monedele. data=2026-09-15 întoarce cursul valabil în acea zi (ultima publicare de dinainte, dacă e weekend). moneda=EUR întoarce doar una. multiplu e 100 pentru HUF, JPY, KRW.

Erori și cote

Erorile vin ca {"eroare": {"tip": "...", "mesaj": "...", "status": 4xx}}. Tipurile:

statustipce înseamnă
400cui_invalidnu trece de cifra de control
401cheie_lipsalipsește antetul
403cheie_necunoscuta, origine_nepermisa, cheie_secreta_in_url, cont_inactivcheia nu e bună sau nu e folosită unde trebuie
403proba_expiratacele 30 de zile de probă au trecut; alege un plan din cont și cheile pornesc pe loc
403domeniu_ocupatdomeniul e legat de alt cont; pe un cont gratuit nu se poate refolosi
404in_cursCUI valid pe care nu-l avem încă; l-am cerut de la ANAF — reîncearcă după reincearca_in_secunde
404necunoscut_anafANAF nu are acest CUI (firmă străină, număr greșit)
429ritm_depasit, cota_lunara_depasitaprea repede, sau cota lunii e consumată
400json_invalid, lista_lipsa, lista_prea_marela POST /v1/firme: corp JSON greșit, listă goală sau peste 100 400interogare_scurta, data_invalidacăutare sub 3 litere; dată care nu e YYYY-MM-DD 403doar_plan_platitfuncție disponibilă doar pe planurile plătite (lotul) 404fara_curs, moneda_necunoscutala curs 429cota_insuficientalotul cere mai multe CUI-uri decât cota rămasă

Fiecare răspuns autentificat are antetele X-Cota-Luna (cota planului), X-Cota-Ramasa (cereri rămase, inclusiv creditele), X-Credite (creditele din rezervă), X-Plan și X-Timp-Ms; cheile de test au X-Mod: test. Răspunsurile 429 și 503 (ocupat, rar și de scurtă durată) au Retry-After (secunde). Cererile refuzate (401/403/429) nu consumă cotă. Cota se resetează la 1 ale lunii.

Cotă, credite, probă

Fiecare răspuns 200 sau 404 consumă o cerere din cota lunară a planului. Când cota s-a terminat, cererile se iau din credite (pachete cumpărate o dată din cont, valabile 12 luni) — dacă ai; altfel primești 429 până la 1 ale lunii sau până treci la un plan mai mare (se aplică pe loc). Contul gratuit e o probă de 30 de zile: după expirare cheile răspund 403 proba_expirata până alegi un plan sau cumperi credite. Un domeniu folosit pe un cont de probă rămâne legat de acel cont (403 domeniu_ocupat de pe alt cont gratuit).

Prospețimea datelor

Toate firmele sunt reverificate la ANAF cel puțin săptămânal; fișele servite cu date mai vechi de 7 zile primesc reverificare_ceruta: true și intră la coadă imediat. Firmele noi se descoperă zilnic. Dacă vrei să știi cât de proaspătă e o fișă, uită-te la verificat_la. /v1/stare arată, fără cheie, câte firme avem și ultima verificare.