Cuprins
Deschide tabela de clienți a oricărei aplicații care lucrează de câțiva ani cu firme românești și vei găsi aceleași lucruri. CUI-uri cu „RO” în față și fără, cu spații, cu puncte. Aceeași firmă de trei ori, sub trei forme ale aceluiași cod. Numere de registru scrise în trei feluri. Nu e vina nimănui anume, e ce se întâmplă când un câmp liber stă ani la rând la dispoziția utilizatorilor. Se poate repara, și mai ales se poate preveni, dacă știi exact ce stochezi.

CUI, CIF și codul de TVA
CUI, codul unic de înregistrare, e numărul primit de firmă la înmatriculare. Rămâne același toată viața firmei și e cheia după care o găsești în toate registrele publice.
CIF, codul de identificare fiscală, e identificatorul folosit de administrația fiscală. Pentru firmele înregistrate la registrul comerțului, CIF-ul e chiar CUI-ul. De asta cei doi termeni se folosesc unul în locul celuilalt și nimeni nu greșește.
Codul de TVA e CUI-ul cu prefixul „RO” în față și arată că firma e înregistrată în scopuri de TVA. Nu e alt număr. E același CUI, cu un prefix care are sens fiscal. O firmă care iese din evidența TVA își păstrează CUI-ul, dar prefixul nu mai are temei.
Pentru aplicația ta asta înseamnă un singur lucru: stochezi CUI-ul doar din cifre, fără prefix, și ții separat informația despre TVA. Prefixul „RO” îl pui la afișare, pe factură, doar când firma e plătitoare de TVA. Am văzut baze de date unde prefixul era salvat odată cu codul, iar după ce firma ieșea din evidența TVA, facturile continuau să apară cu „RO” luni la rând.
Numărul de la registrul comerțului
Numărul de ordine din registrul comerțului identifică înmatricularea firmei la ONRC. Formatul clasic, cel din majoritatea bazelor de date existente, începe cu o literă care arată tipul entității, urmată de codul județului, numărul de ordine și anul, de exemplu J40/1234/2015. În ultimii ani formatul s-a schimbat pentru înregistrările noi, iar firmele vechi pot apărea în ambele forme, în surse diferite.
De aici sfatul meu: nu valida numărul de registru cu o expresie regulată rigidă. Tratează-l ca text, păstrează-l exact cum vine din sursa oficială și folosește CUI-ul drept cheie. O regulă prea strictă îți va respinge fix firmele înregistrate recent.
În API-ul Informații firmă, numărul vine în câmpul numar_registru. La căutarea de firme, lista are doar firmele înmatriculate la registrul comerțului, deci numar_registru e mereu completat. Punctele de lucru nu au număr propriu.
Întâi, curăță intrarea
Utilizatorii vor scrie CUI-ul în orice formă: „RO 12345678”, „ro12345678”, „12.345.678”, „ 12345678 ”. Înainte de orice altceva, reduci intrarea la cifre:
import re
def normalizeaza_cui(text):
t = text.strip().upper()
if t.startswith("RO"):
t = t[2:]
return re.sub(r"\D", "", t)
Poți păstra intrarea originală, dacă vrei să știi ce a scris omul, dar lucrezi doar cu forma curățată.
Apoi, cifra de control
CUI-ul are între 2 și 10 cifre, iar ultima e o cifră de control, calculată din celelalte. Algoritmul folosește cheia 753217532. Cifrele fără ultima se aliniază la dreapta cu cheia, se înmulțesc cifră cu cifră și se adună produsele. Suma se înmulțește cu 10 și se împarte la 11. Restul e cifra de control, iar dacă restul e 10, cifra de control e 0.
def cui_valid(cui):
if not cui.isdigit() or not 2 <= len(cui) <= 10:
return False
corp, control = cui[:-1].zfill(9), int(cui[-1])
suma = sum(int(c) * int(k) for c, k in zip(corp, "753217532"))
rest = suma * 10 % 11
return (0 if rest == 10 else rest) == control
Cifra de control prinde majoritatea greșelilor de tastare: o cifră schimbată sau, de cele mai multe ori, două cifre inversate. Nu-ți spune însă dacă firma există. Un CUI valid matematic poate să nu fi fost atribuit niciodată.
O capcană la teste: CUI-urile fictive din sandbox-ul BilantAPI nu sunt construite să treacă de cifra de control. 90000010, de exemplu, pică: suma ponderată e 29, restul împărțirii lui 290 la 11 e 4, iar ultima cifră e 0. Dacă aplici validarea și în mediul de test, lasă o excepție pentru ele. Nici API-ul nu verifică cifra de control. Cere doar un CUI de 2–10 cifre, altfel răspunde cu eroarea 400 INVALID_CUI_FORMAT, care nu se taxează.

La final, registrul
Singurul mod în care afli sigur că un CUI aparține unei firme reale e să-l cauți în registru. GET /api/v1/registru/firme/{cui} întoarce profilul fiscal: CUI-ul în cui, ca număr, denumirea, numărul de registru în numar_registru, forma juridică și starea. În cale trimiți doar cifrele, fără „RO”. Costă un credit. Dacă firma nu există, nu primești profil, ci un 404 cu codul COMPANY_NOT_FOUND, și nu plătești nimic, pentru că cererile fără rezultat nu consumă credite.
curl -H "X-API-KEY: cheia-ta" \
https://www.bilantapi.ro/api/sandbox/v1/registru/firme/90000010
Exemplul folosește sandbox-ul, care cere o cheie API, deci un cont gratuit, fără card. Cererile de acolo nu consumă credite și primesc date fictive. Ordinea pe care o recomand e normalizare, cifră de control și abia apoi cererea în registru. Greșelile evidente le oprești local și nu trimiți cereri degeaba.
Cum arată tabela
CUI-ul e cheia unică, stocat ca text de cifre, fără prefix. API-ul îl întoarce în cui ca număr, așa că îl transformi în text la import. Text și nu număr, ca să nu depinzi de limitele tipurilor numerice și să poți compara exact. Pui un index unic pe el, ca aceeași firmă să nu mai apară de două ori sub forme diferite.
Numărul de registru rămâne text liber, cum vine din sursa oficială. Informația despre TVA stă separat, cu data ultimei verificări.
Dacă ai deja o bază cu dubluri, începe cu normalizarea tuturor CUI-urilor și grupează după forma curățată. Îți iese imediat lista de fișe care trebuie unite. Partea grea e să decizi care fișă rămâne, nu să le găsești.
Când omul știe doar numele
Uneori utilizatorul nu are CUI-ul, doar numele firmei. Căutarea de firme, GET /api/v1/registru/firme, acceptă în parametrul q fie denumirea, fie CUI-ul, cu prefixul RO sau fără. Fiecare rezultat costă un credit și vine cu profilul complet, deci poți afișa o listă scurtă din care omul își alege firma, în loc să-l lași să scrie orice.
Profilul complet e descris pe pagina API Informații firmă, iar căutarea după denumire pe pagina API Căutare firme. Cele 250 de credite gratuite pe care le primești la înregistrare, fără card, îți ajung să cureți și să verifici CUI-urile dintr-o bază de date mică.
Întrebări frecvente
CUI și CIF sunt același lucru?
Pentru firmele înregistrate la registrul comerțului, da: CIF-ul e chiar CUI-ul. De asta termenii se folosesc unul în locul celuilalt.
Ce înseamnă „RO” din fața CUI-ului?
Că firma e înregistrată în scopuri de TVA. Numărul rămâne același, prefixul are doar sens fiscal.
CUI-ul trece de cifra de control. Înseamnă că firma există?
Nu. Cifra de control prinde greșelile de tastare. Că firma există afli doar căutând-o în registru.
Plătesc dacă verific un CUI care nu există?
Nu. Cererile fără rezultat și erorile 400 nu consumă credite.



