# ASF — Autoritatea de Supraveghere Financiară Public registries of authorized financial entities — insurers, brokers, pension funds, asset managers, intermediaries. ## Status (2026-05-10) **MVP ingest complete: 849 entities, 100% CUI coverage.** Captures `data.asfromania.ro/scr/ra` via free-text term enumeration. | Register type | Active | Radiated | |---|---|---| | Asigurători (RA-NNN) | 24 | 37 | | Brokeri (RBK-NNN) | 245 | 543 | **Cross-source signal (validated):** 69 ASF-licensed firms hold 3,530 SEAP contracts totaling **€614 mln**. Top: ASIROM (RA-023) — 523 contracts, €283 mln; ALLIANZ-ȚIRIAC (RA-017) — 467 contracts, €50 mln; GROUPAMA (RA-009) — 315 contracts, €41 mln. Zero contracts won post-radiere (positive integrity signal). Files: - SQL: `services/seap-scraper/sql/034_asf.sql` — schema `asf` (entitati, scrape_log, mv_entitati_per_cui). - Scraper: `services/seap-scraper/src/scrape-asf.ts` - Wrapper: `services/seap-scraper/cron/scrape-asf.sh` ## Source map (ASF registers ecosystem) | Sub-register | Volume | URL | Status | |---|---|---|---| | Asigurători (RA-NNN) + Intermediari principali (RBK-NNN) — active + radiate | ~860 | `data.asfromania.ro/scr/ra` | **Done — this scraper** | | Intermediari secundari (RIS) | ~variable | `asfromania.ro/ro/a/1704` | TODO | | Specialiști constatare daune | ~variable | `asfromania.ro/ro/a/1999` | TODO | | Furnizori programe formare | ~variable | `asfromania.ro/ro/a/2068` | TODO | | Lectori | ~variable | `asfromania.ro/ro/a/2067` | TODO | | Piață de capital (SSIF/AOPC/SAI/depozitari) | ~30-50 | `asfromania.ro/ro/a/1705` | TODO | | Pensii private (Pillar 2 + 3 + administratori) | ~20 | `asfromania.ro/ro/a/2365` + `data.asfromania.ro/scr/adeziuniFP` | TODO | | Asigurători din SEE (passporting) | ~~hundreds | `asfromania.ro/ro/a/2082` | TODO | ## Critical scraping insight (the trick) `data.asfromania.ro/scr/ra/cautare` POST endpoint is fronted by Google reCAPTCHA Enterprise but **the server only validates the captcha if the form field `g-recaptcha-response` is present in the body**. When that field is OMITTED entirely, the captcha check is skipped and the server returns full results. (When sent with any value, even empty, server tries to verify and rejects with "Verificare captcha eșuată".) Fields per response (HTML inside `raspuns`): - Number registration (RA-XXX / RBK-XXX) — globally unique per type - LEI 20-char, CUI, RC code (J40/2226/2006) - Authorization number + date, registration date, radiation date (active=NULL) - Type (Societate de asigurare / Intermediar principal) - Legal form, address, phone, fax - Authorized classes (general + life — array) - Executives (Conducere executivă) ## Constraints - Server-side validation: `termen` must be ≥4 characters. - Free-text search hits multiple fields (denumire, CUI, adresă, județ, classes). - `sectiune` (1=active / 2=radiate) and `tipCompanie` (0=insurer / 1=broker) appear to be IGNORED by the search endpoint when `termen` is given — results span all sections regardless. ## Strategy used 1. **Seed phase** — 11 broad terms (ASIGURA, BROKER, BUCU, CLUJ, TIMI, BRAS, RETRA, RADI, FUZIO, ...) covering active + radiated. Yields ~840 entities. 2. **Gap-fill phase** — for each prefix (RA-, RBK-) compute observed sequence, probe gaps + 5 entries past the max via direct register-no lookup. Yields the final ~20 missing. ## Next steps (TODO for follow-up agents) ### Quick wins (1-2h each) 1. **Pensii private** — `data.asfromania.ro/scr/adeziuniFP` likely has same captcha-bypass trick. ~7-15 fund administrators is small but high-value (NN, BCR Pensii, Allianz-Țiriac Pensii, etc.). 2. **SEE passporting list** — `asfromania.ro/ro/a/2082`. EU-wide insurers selling RCA in Romania. Probably HTML table on the page itself. ### Medium (3-5h) 3. **Piață de capital register** (`SSIF`, `SAI`, `AOPC`, depozitari) — typically PDF/Excel attachments at `asfromania.ro/uploads/articole/`. ~50 entities total. Replicates the `fonduri.beneficiar_anunt` Excel-parser pattern. 4. **Intermediari secundari (RIS)** — large (~thousands) but mostly individuals (no CUI). May not be worth the effort vs. corporate registers. ## Cross-source recipe **"Asigurători + brokeri ASF cu contracte SEAP"** — financial firms licensed by ASF that have won state insurance/financial-services contracts. ```sql -- Recipe: ASF-licensed firms × SEAP wins SELECT a.register_no, a.register_type, a.section_status, a.name AS asf_name, a.cui, a.data_autorizare, a.data_radiere, COUNT(DISTINCT n.id) AS seap_contracts, SUM(COALESCE(n.awarded_value, n.estimated_value)) AS total_seap_value, COUNT(DISTINCT n.authority_cui) AS distinct_authorities, MIN(n.publication_date) AS first_seap_win, MAX(n.publication_date) AS last_seap_win, -- Red-flag: still winning contracts after radiere COUNT(*) FILTER (WHERE a.data_radiere IS NOT NULL AND n.publication_date::date > a.data_radiere) AS contracts_post_radiere FROM asf.entitati a JOIN seap.announcements n ON n.supplier_cui = a.cui WHERE a.cui IS NOT NULL GROUP BY a.id, a.register_no, a.register_type, a.section_status, a.name, a.cui, a.data_autorizare, a.data_radiere ORDER BY total_seap_value DESC NULLS LAST LIMIT 100; ``` **Companion recipe:** "Brokeri ASF cu datorii ANAF" — brokers in ANAF datornici list still active in ASF register. Combines `asf.mv_entitati_per_cui` with `anaf.datornici_curent`. ```sql SELECT a.register_no, a.name, a.cui, d.suma_totala_datorii, d.luna_raportare FROM asf.mv_entitati_per_cui m JOIN asf.entitati a ON a.cui = m.cui JOIN anaf.datornici_curent d ON d.cui = m.cui WHERE m.nr_active > 0 ORDER BY d.suma_totala_datorii DESC LIMIT 50; ``` ## Schema reference ``` asf.entitati ( id, register_type, section_status, register_no, name, name_normalized, cui, cod_rc, cod_lei, nr_autorizatie, data_autorizare, data_inmatriculare, data_radiere, tip_companie, forma_juridica, adresa, telefon, fax, email, web, observatii, clase_autorizate jsonb, conducere jsonb, raw_html, fetched_at ) UNIQUE (register_type, register_no) asf.mv_entitati_per_cui (cui, nr_total, nr_asigurator, nr_broker, ...) ``` ## Refresh policy Recommended: weekly cron (registry changes are slow — new authorizations ~weekly, radiation events monthly). Estimated full scrape: ~10 min wall. ```cron # Sunday 3:30 AM 30 3 * * 0 root /opt/vreaudigital/services/seap-scraper/cron/scrape-asf.sh ```