Case study · Tools / Open source

GetCIF

Public data.Developer ready.

A free, documented API that makes Romanian public company data easier to query, reason about and depend on.

Access
Free, documented API
Model
Cache / snapshot / live source
Status
Live
GetCIF documentation introduction with an example request and JSON response
GetCIF API reference: the CIF lookup endpoint table and a curl example
Response semanticsKnow where the data came from.meta.data_origin → CACHE / SNAPSHOT / ANAF

01 / Overview

Not another thin proxy.

GetCIF gives developers a clean way to look up Romanian companies by CIF. Behind one small, consistent API it handles validation, caching, snapshots and the public ANAF services, so an integration gets a predictable answer instead of the upstream's quirks.

It is free to use, documented in English and Romanian, and has SDKs for Node.js and PHP.

02 / The problem

The data is public. Depending on it is harder.

Company and VAT data from ANAF is freely available, but building directly on top of it means taking on every rough edge of the source.

  1. An unpredictable upstream

    The public services can be slow, rate-limited or briefly unavailable. Call them directly and each of those moments becomes your application's problem.

  2. Input with its own rules

    CIFs need normalising, personal CNP values have to be kept out, and date-based lookups need a sensible default. Every integration ends up relearning the same rules.

  3. Payloads shaped for the source

    Raw responses mirror how the upstream stores data, not how an application wants to use it, and they don't say whether the data came from a live lookup.

03 / What it does

Small surface. Clear contract.

A handful of obvious endpoints, one response envelope, and the source of every answer included in the response.

  • Company lookup

    Look up one company by CIF, or many at once. Bulk requests keep the order you asked in, duplicates included.

  • Raw payloads when you need them

    Each structured endpoint has a raw twin that keeps the same envelope and places the original ANAF payload in data.raw.

  • More than company records

    Financial statements, the agriculture and cult registries and the RO e-Factura registry follow the same conventions.

  • SDKs and an OpenAPI contract

    Typed SDKs for Node.js / TypeScript and PHP, and an OpenAPI spec for everything else.

CIF lookup endpoints
MethodPathDescription
GET/v1/cifs/{cif}Structured company lookup
GET/v1/cifs/{cif}/rawRaw ANAF payload
POST/v1/cifs/bulkStructured bulk lookup
POST/v1/cifs/bulk/rawRaw bulk lookup
Single lookup
GET /v1/cifs/1590082

{
  "data": {
    "cif": "1590082",
    "name": "ACME SRL",
    ...
  },
  "meta": {
    "data_origin": "CACHE"
  }
}

04 / Under the hood

Do the cheap work first.

Every lookup follows the same deliberate sequence. A live ANAF call is the last resort, not the default.

  1. 01

    Validate

    Normalise identifiers, reject CNPs and parse dates before anything touches an upstream service.

  2. 02

    Resolve

    Derive the lookup key. Date-based endpoints default to today in Europe/Bucharest.

  3. 03

    Check local

    Use the current cache and saved snapshots before considering a live request.

  4. 04

    Gate

    Apply rate limits and safe fallback rules before reaching the origin.

  5. 05

    Fetch

    Call ANAF only when the record is not already available locally.

  6. 06

    Shape

    Return a stable envelope: data plus meta, with per-CIF items for bulk lookups.

Fresh when possible. Useful when not.

Every successful response says where it came from, so an integration can tell a fast cached answer from a saved snapshot or a live fetch.

  1. 01 / First choiceCACHE

    A record already inside the current cache window.

    miss
  2. 02 / FallbackSNAPSHOT

    A persisted record saved from an earlier lookup.

    not saved
  3. 03 / Live sourceANAF

    The upstream service, reached only when the record has to be fetched live.

meta.data_originX-Data-OriginCACHESNAPSHOTANAF

GetCIF documentation page describing the six-step request lifecycle
  • Live lookups pay forward

    Once a record has been fetched and saved, later requests can usually skip the same upstream work.

  • Failure is designed, not leaked

    When ANAF is struggling, the API can return a locally available record instead of passing the outage on to the caller.

05 / Tech stack

Plain, dependable parts.

Nothing exotic. Each piece has one job in the lookup path.

API
Go · chi
Cache + rate limits
Redis
Snapshots
PostgreSQL · sqlc · pgx · golang-migrate
Contract
OpenAPI
Observability
OpenTelemetry
SDKs
TypeScript (@getcif/sdk) · PHP (getcif/sdk)
Documentation site
React · Vite · Tailwind CSS
Deployment
Docker · Traefik · Dokploy

06 / Current status

Live, documented, deliberately small.

The scope is intentionally narrow: reliable access to useful Romanian company data, with enough caching, provenance and fallback logic to make integrations less fragile.

API
Live at api.getcif.dev
Documentation
English and Romanian
SDKs
Node.js and PHP · 0.1.0

Next project · 02

Agrafa

Know the state.Catch the change.

A Go-based monitoring system that collects node and service health, evaluates state, applies alert rules and exposes a useful read model for dashboards.

Agent
Go / gopsutil
Backend
Go / PostgreSQL / REST
Focus
Nodes / services / alerts
View case study