Atti Service API
API REST per richiedere, monitorare e scaricare documenti camerali italiani: visure ordinarie e storiche, atti ottici repertoriati, statuti societari.
Come funziona
Il flusso è asincrono: la richiesta viene accettata immediatamente, il documento è pronto dopo alcuni secondi/minuti. L'applicazione fa polling su ?action=stato finché completed: true.
Autenticati
Usa il tuo Personal API Token (cs_pat_...) oppure ottieni un JWT con il flusso Client Credentials. Ogni metodo è descritto nella sezione Autenticazione.
Richiedi il documento
POST ?action=richiesta con P.IVA e tipo documento. Ricevi subito l'id della richiesta e il costo addebitato. Consulta prima ?action=prezzi per il catalogo prezzi (no auth).
Fai polling sullo stato
GET ?action=stato&id=N ogni 15 secondi finché "completed": true.
Scarica il PDF
Usa il download_url restituito da stato, oppure chiama direttamente GET ?action=scarica&id=N.
Autenticazione
Tre metodi disponibili. Se hai un account CertiSource con credito, usa il Personal API Token: è il più semplice e i documenti vengono addebitati direttamente sul tuo saldo.
Personal API Token (PAT)
Authorization: Bearer cs_pat_••••••
Genera il token dal tuo profilo CertiSource. I costi scalano dal tuo credito account (voucher-first). Nessun JWT da rinnovare. La scadenza è opzionale (nessuna, 30gg, 90gg, 1 anno) — impostata al momento della creazione.
B2B Client Credentials
Authorization: Bearer <JWT>
Per app senza un utente CertiSource. Ottieni client_id + client_secret, chiama POST ?action=token, ricevi un JWT valido 24h.
expires_at. Il JWT B2B scade dopo token_ttl_hours ore (default 24h) e va rinnovato automaticamente.
Costi & Addebiti
Ogni richiesta andata a buon fine genera un addebito immediato sul credito dell'account. Il credito promozionale (voucher) viene consumato prima di quello reale.
| Documento | Provider | Costo | Tempo medio |
|---|---|---|---|
| Visura Camerale Ordinaria Sede legale + unità locali, REA, cariche, soci/quote, ATECO, PEC, oggetto sociale, capitale sociale |
visurecamerali.openapi.it | € 4,95 | 30–120 s |
| Visura Storica Tutta la storia societaria dalla fondazione |
visurecamerali.openapi.it | € 5,90 | 60–180 s |
| Atto Ottico CCIAA Documento repertoriato depositato al RI (richiede numero protocollo) |
docuengine.openapi.com | € 5,50 | 10–60 s |
| Statuto Societario Statuto aggiornato depositato al Registro Imprese |
docuengine.openapi.com | € 5,50 | 10–60 s |
"force": true al body per bypassare la cache.
In caso di credito insufficiente l'API risponde con HTTP 402 e non effettua alcun addebito né richiesta al provider.
GET ?action=prezzi (no auth, JSON strutturato con breakdown costi, durate cache, campi obbligatori e features per tipo documento).
Caching automatico
CertiSource memorizza ogni documento acquisito e lo riusa automaticamente nelle richieste successive per la stessa P.IVA. Il documento viene consegnato immediatamente al prezzo pieno: il client paga sempre, CertiSource non sostiene il costo del provider.
| Tipo documento | Durata cache | Cross-type | Prezzo per il client |
|---|---|---|---|
| Visura Camerale Ordinaria | 240 ore (10 giorni) | ✅ Accetta anche Visura Storica in cache | Prezzo pieno (€ 4,95) |
| Visura Storica | 240 ore (10 giorni) | — solo tipo esatto | Prezzo pieno (€ 5,90) |
| Atto Ottico / Statuto | 24 ore (stesso protocollo) | — | Prezzo pieno |
visura_storica per una P.IVA, una successiva richiesta di visura_camerale per la stessa P.IVA (entro 10 giorni) viene servita dalla cache. La risposta include il campo cached_source_type per indicare il tipo del documento servito.
{
"success": true,
"id": 43,
"cached": true,
"cached_from": 38, // id richiesta originale
"cached_source_type": "visura_storica", // tipo del doc servito (può differire dal richiesto)
"status": "completed",
"cost": 4.95, // prezzo pieno del tipo richiesto
"download_url": "?action=scarica&id=43",
"data_url": "?action=dati&id=43",
"message": "Documento disponibile (originale del 2026-03-01 10:22:00) — servita visura_storica in cache."
}
Per forzare un nuovo acquisto (es. dopo una modifica societaria urgente) aggiungi "force": true nel body della richiesta.
GET ?action=prezzi
Catalogo prezzi machine-readable con breakdown dettagliato per ogni tipo di documento: costo totale, voci di costo, durata cache, tempi di consegna, campi obbligatori e features disponibili. Non richiede autenticazione.
curl "https://certisource.it/atti-service.php?action=prezzi"
{
"success": true,
"currency": "EUR",
"computed_at": "2026-02-27T14:00:00+01:00",
"billing": {
"model": "prepaid_credit",
"voucher_first": true,
"insufficient_credit_http": 402,
"note": "Il credito voucher viene consumato prima del credito reale. HTTP 402 se credito insufficiente."
},
"catalog": [
{
"type": "visura_camerale",
"name": "Visura Camerale Ordinaria",
"description": "Dati attuali: ragione sociale, sede legale, unità locali, REA, cariche con anagrafica completa, soci/quote, ATECO, PEC, oggetto sociale, capitale sociale, poteri di rappresentanza. Include JSON strutturato via ?action=dati.",
"provider": "visurecamerali.openapi.it",
"cost": {
"total": 4.95,
"breakdown": [
{ "item": "documento CCIAA", "amount": 4.95 }
]
},
"cache_hours": 240,
"cache_note": "Documento riusato da cache (10 giorni) — costo pieno addebitato al cliente",
"async": true,
"avg_delivery_seconds": { "min": 30, "max": 120 },
"required_fields": ["vat"],
"optional_fields": ["webhook_url", "webhook_secret", "force"],
"features": {
"structured_data": true, // JSON via ?action=dati
"webhook": true, // notifica push al completamento
"caching": true // riuso automatico
}
},
{
"type": "visura_storica",
"description": "Tutti i dati della visura camerale + storia completa degli eventi societari dalla fondazione: nomine, cessioni quote, variazioni capitale, depositi bilancio, procedure concorsuali, fusioni. Include JSON strutturato con campo eventi[] via ?action=dati.",
"cost": { "total": 5.90, "breakdown": [{ "item": "documento CCIAA storico", "amount": 5.90 }] },
"cache_hours": 240, "required_fields": ["vat"], "features": { "structured_data": true, "eventi": true, "webhook": true, "caching": true }
},
{
"type": "atto_ottico",
"cost": {
"total": 5.50,
"breakdown": [
{ "item": "ricerca protocollo", "amount": 0.60 },
{ "item": "documento ottico", "amount": 4.90 }
]
},
"cache_hours": 24, "required_fields": ["vat", "protocol"], "features": { "structured_data": false, "webhook": true, "caching": true }
},
{
"type": "statuto",
"cost": { "total": 5.50, "breakdown": [{ "item": "ricerca protocollo", "amount": 0.60 }, { "item": "documento statuto", "amount": 4.90 }] },
"cache_hours": 24, "required_fields": ["vat", "protocol"], "features": { "structured_data": false, "webhook": true, "caching": true }
}
]
}
Schema risposta — campo catalog[n]
| Campo | Tipo | Descrizione |
|---|---|---|
| type | string | Identificatore da usare nel campo type di action=richiesta |
| cost.total | float | Costo totale in EUR addebitato al completamento |
| cost.breakdown | array | Voci di costo singole (utile per atto_ottico: ricerca + documento) |
| cache_hours | int | Finestra di cache in ore (visure: 240h = 10 giorni). Il documento viene riutilizzato automaticamente; il prezzo è comunque addebitato al cliente. |
| avg_delivery_seconds | object | min e max in secondi per il completamento |
| required_fields | string[] | Campi obbligatori nel body di action=richiesta |
| optional_fields | string[] | Campi opzionali accettati |
| features.structured_data | bool | Se true: JSON strutturato disponibile via ?action=dati |
| features.webhook | bool | Se true: supporta notifica push webhook al completamento |
| features.caching | bool | Se true: riuso automatico del documento entro la finestra cache |
catalog[n].cache_hours > 0, la seconda richiesta per la stessa vat + type entro quella finestra restituisce il documento già acquisito ("cached": true). Il prezzo è comunque addebitato per intero — CertiSource sostiene costo zero sull'OpenAPI, il cliente paga il prezzo standard. Usa "force": true nel body per forzare un nuovo acquisto dal registro CCIAA.
GET ?action=info
Catalogo pubblico del servizio con tipi di documento, costi e metodi di autenticazione. Non richiede autenticazione.
curl "https://certisource.it/atti-service.php?action=info"
{
"success": true,
"service": "CertiSource Atti Service",
"version": "1.2",
"documents": [
{ "type": "visura_camerale", "cost_total": 4.95 },
{ "type": "visura_storica", "cost_total": 5.90 },
{ "type": "atto_ottico", "cost_total": 5.50 },
{ "type": "statuto", "cost_total": 5.50 }
],
"price_catalog": "https://certisource.it/atti-service.php?action=prezzi"
}
Per un catalogo prezzi strutturato e machine-readable usa ?action=prezzi.
POST ?action=token
Endpoint OAuth2 Client Credentials. Emette un JWT Bearer valido per la durata configurata. Solo per integrazione B2B senza utente CertiSource.
Parametri body (JSON)
| Campo | Tipo | Note |
|---|---|---|
| client_id | string | obbligatorio UUID assegnato da CertiSource |
| client_secret | string | obbligatorio Segreto (64 hex) — non recuperabile |
curl -X POST "https://certisource.it/atti-service.php?action=token" \ -H "Content-Type: application/json" \ -d '{"client_id":"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", "client_secret":"aabbcc..."}'
{
"success": true,
"access_token": "eyJhbGciOiJIUzI1NiJ9...",
"token_type": "Bearer",
"expires_in": 86400,
"expires_at": "2026-02-27T14:30:00+01:00",
"client_name": "AgileApp"
}
POST ?action=richiesta
Avvia la richiesta di un documento. Il costo viene addebitato immediatamente. La risposta contiene l'id da usare per il polling.
Parametri body (JSON)
| Campo | Tipo | Note |
|---|---|---|
| vat | string | obbligatorio P.IVA italiana (11 cifre) |
| type | string | obbligatorio visura_camerale · visura_storica · atto_ottico · statuto |
| protocol | string | obbligatorio per atti Es. MO-2025-5323 |
| investigation_id | int | opzionale ID informativa CertiSource |
| dossier_id | int | opzionale ID dossier CertiSource |
| webhook_url | string | opzionale URL HTTPS a cui CertiSource invierà un POST al completamento (niente polling) |
| webhook_secret | string | opzionale Segreto HMAC-SHA256 per verificare la firma X-CertiSource-Signature |
| force | bool | opzionale true = bypassa la cache e acquista sempre un nuovo documento (costo pieno) |
curl -X POST "https://certisource.it/atti-service.php?action=richiesta" \ -H "Authorization: Bearer cs_pat_IL_TUO_TOKEN" \ -H "Content-Type: application/json" \ -d '{"vat":"04058890361","type":"visura_camerale"}'
const res = await fetch("https://certisource.it/atti-service.php?action=richiesta", { method: "POST", headers: { "Authorization": "Bearer cs_pat_IL_TUO_TOKEN", "Content-Type": "application/json" }, body: JSON.stringify({ vat: "04058890361", type: "visura_camerale" }) }); const data = await res.json(); console.log(data.id, data.cost); // id da usare per polling, costo addebitato
$ch = curl_init("https://certisource.it/atti-service.php?action=richiesta"); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ "Authorization: Bearer cs_pat_IL_TUO_TOKEN", "Content-Type: application/json" ], CURLOPT_POSTFIELDS => json_encode([ "vat" => "04058890361", "type" => "visura_camerale" ]) ]); $data = json_decode(curl_exec($ch), true);
{
"success": true,
"id": 42, // usa per stato, scarica, dati
"provider_id": "uuid-del-provider",
"status": "processing",
"cached": false,
"cost": 4.95,
"currency": "EUR",
"data_url": "?action=dati&id=42",
"message": "Chiama ?action=stato&id=42 ogni 15s"
}
{
"success": true,
"id": 43,
"cached": true,
"cached_from": 38, // id della richiesta originale
"status": "completed",
"cost": 0.00, // nessun addebito
"currency": "EUR",
"download_url": "?action=scarica&id=43",
"data_url": "?action=dati&id=43"
}
"code": "INSUFFICIENT_CREDIT". Nessun addebito viene effettuato.
GET ?action=stato&id={id}
Controlla lo stato di una richiesta. Da chiamare ogni 15 secondi fino a "completed": true.
curl -H "Authorization: Bearer cs_pat_IL_TUO_TOKEN" \ "https://certisource.it/atti-service.php?action=stato&id=42"
Risposta — In elaborazione
{
"success": true,
"id": 42,
"status": "In erogazione",
"completed": false,
"message": "Documento in elaborazione..."
}
Risposta — Completata
{
"success": true,
"id": 42,
"status": "completed",
"completed": true,
"file_name": "visura_camerale_04058890361_20260226.pdf",
"download_url": "?action=scarica&id=42&token=..."
}
async function pollUntilReady(id, token, intervalMs = 15000, maxAttempts = 40) { for (let i = 0; i < maxAttempts; i++) { const res = await fetch(`?action=stato&id=${id}`, { headers: { "Authorization": `Bearer ${token}` } }); const data = await res.json(); if (data.completed) return data; // ✓ pronto if (data.status === "failed") throw new Error(data.error); // ✗ errore await new Promise(r => setTimeout(r, intervalMs)); } throw new Error("Timeout: documento non pronto dopo 10 minuti"); }
GET ?action=scarica&id={id}
Scarica il PDF di una richiesta completata. Risponde con Content-Type: application/pdf.
curl -H "Authorization: Bearer cs_pat_IL_TUO_TOKEN" \ "https://certisource.it/atti-service.php?action=scarica&id=42" \ -o visura.pdf
&token=... nel download_url restituito da stato permette di aprire il PDF direttamente in una nuova scheda del browser senza header aggiuntivi.
GET ?action=lista
Elenco delle richieste dell'account autenticato (o filtrate per informativa).
Query string opzionale
| Param | Default | Note |
|---|---|---|
| investigation_id | — | Filtra per ID informativa |
| limit | 50 | Max 200 |
| offset | 0 | Per paginazione |
{
"success": true,
"total": 3,
"items": [
{
"id": 42,
"document_type": "visura_camerale",
"vat_number": "04058890361",
"status": "completed",
"cost_eur": 4.95,
"created_at": "2026-02-26 14:00:00"
}
]
}
GET ?action=dati&id={id}
Restituisce i dati strutturati estratti dalla visura: ragione sociale, codice fiscale, P.IVA, forma giuridica, sedi (array), PEC, oggetto sociale, codici ATECO multipli, cariche con dati anagrafici completi. Disponibile per visura_camerale e visura_storica. Se i dati non sono ancora stati parsati ma il PDF esiste, il parsing viene eseguito on-demand.
| Tipo documento | Dati strutturati | Costo | Quando usarla |
|---|---|---|---|
visura_camerale ✓ Consigliata |
Dati correnti: ragione sociale, sede legale + unità locali, REA, cariche con anagrafica completa, soci/quote, ATECO primari+secondari, PEC, oggetto sociale, capitale sociale, numero addetti, poteri di rappresentanza | € 4,95 | Onboarding clienti, KYC, arricchimento CRM — uso tipico |
visura_storica |
Tutti i dati della camerale + storia completa degli eventi societari dalla fondazione (nomine, cessioni, variazioni capitale, procedure concorsuali, ecc.) | € 5,90 | Due diligence, analisi governance storica, monitoraggio procedure concorsuali |
curl -H "Authorization: Bearer cs_pat_IL_TUO_TOKEN" \ "https://certisource.it/atti-service.php?action=dati&id=42"
const res = await fetch(`https://certisource.it/atti-service.php?action=dati&id=${id}`, { headers: { "Authorization": "Bearer cs_pat_IL_TUO_TOKEN" } }); const data = await res.json(); const sd = data.structured_data; // Pre-compila il form di onboarding document.getElementById("ragione_sociale").value = sd.ragione_sociale; document.getElementById("codice_fiscale").value = sd.codice_fiscale; document.getElementById("pec").value = sd.pec; const sedeLegale = sd.sedi?.find(s => s.tipo === 'sede_legale'); document.getElementById("comune").value = sedeLegale?.comune; document.getElementById("ateco_primario").value = sd.ateco_codes[0]?.code;
{
"success": true,
"id": 42,
"document_type": "visura_camerale",
"vat_number": "04058890361",
"structured_data": {
"ragione_sociale": "ACME SOCIETA' COOPERATIVA S.R.L.",
"forma_giuridica": "srl",
"codice_fiscale": "04058890361", // estratto dalla sez.1 del PDF
"partita_iva": "04058890361",
"pec": "acme@pec.it",
"rea": "MO - 381232",
"sedi": [ // array: sede_legale sempre prima, poi unità locali
{
"tipo": "sede_legale",
"via": "Via Roma 1",
"cap": "41100",
"comune": "Modena",
"provincia": "MO",
"pec": "acme@pec.it"
},
{
"tipo": "unita_locale",
"via": "Via Verdi 5",
"cap": "40100",
"comune": "Bologna",
"provincia": "BO",
"attivita": "Magazzino e logistica",
"ateco_codes": [ // codici ATECO specifici di questa unità locale (se presenti nella visura)
{ "code": "41.20.00", "description": "Costruzione di edifici residenziali", "type": "primary" }
]
}
],
"oggetto_sociale": "Costruzione, ristrutturazione e vendita di edifici civili e industriali. La società potrà compiere tutte le operazioni commerciali, industriali, finanziarie, mobiliari e immobiliari necessarie o utili per il raggiungimento dell'oggetto sociale...",
"ateco_codes": [
{ "code": "41.20.00", "description": "Costruzione di edifici residenziali", "type": "primary" },
{ "code": "43.31.00", "description": "Intonacatura e stuccatura", "type": "secondary" }
],
"capitale_sociale": 50000,
"numero_addetti": 127, // media annua addetti (da fonte INPS, se disponibile)
"addetti": { // dettaglio dipendenti/indipendenti da fonte INPS — null se non presente
"fonte": "INPS",
"anno": 2024,
"data_rilievo": "2024-09-30",
"trimestri": {
"dipendenti": { "q1": 120, "q2": 125, "q3": 130, "media": 125 },
"indipendenti": { "q1": 2, "q2": 2, "q3": 2, "media": 2 },
"totale": { "q1": 122, "q2": 127, "q3": 132, "media": 127 }
},
"totale_medio": 127, // coincide con numero_addetti
"addetti_per_comune": [ // distribuzione per sede
{ "comune": "MODENA", "provincia": "MO", "tipo": "sede_legale" },
{ "comune": "ROMA", "provincia": "RM", "tipo": "unita_locale" }
],
"distribuzione_contratto": [ // % per tipo contratto (Q1,Q2,Q3) — null se dati non presenti (es. azienda con un solo tipo contratto)
{ "tipo": "Tempo Indeterminato", "q1": 85.3, "q2": 88.0, "q3": 87.5 },
{ "tipo": "Tempo Determinato", "q1": 14.7, "q2": 12.0, "q3": 12.5 }
],
"distribuzione_orario": [ // % per orario di lavoro — null se non presente
{ "tipo": "Tempo Pieno", "q1": 92.0, "q2": 91.0, "q3": 93.0 },
{ "tipo": "Tempo Parziale", "q1": 8.0, "q2": 9.0, "q3": 7.0 }
],
"distribuzione_qualifica": [ // % per qualifica — null se non presente
{ "tipo": "Impiegato", "q1": 68.0, "q2": 70.0, "q3": 69.0 },
{ "tipo": "Quadro", "q1": 20.0, "q2": 18.0, "q3": 19.0 },
{ "tipo": "Apprendista", "q1": 12.0, "q2": 12.0, "q3": 12.0 }
]
},
"data_costituzione": "1998-03-15",
"data_scadenza": null, // data termine societaria, se presente (es. spa a tempo determinato)
"data_rilascio": "2026-02-27", // data ufficiale di emissione del documento CCIAA
"soci": [ // sez. 7 — presenti solo se indicati nella visura (es. SRL, SPA)
{
"tipo": "persona_fisica", // "persona_fisica" | "persona_giuridica"
"nome_completo": "BIANCHI LUCIA",
"codice_fiscale": "BNCLCU75B48F205Z",
"nato_a": "Milano",
"provincia_nascita":"MI",
"data_nascita": "1975-02-08",
"tipo_rapporto": "Socio",
"quota_eur": 5000, // quota in EUR (SRL/cooperative)
"percentuale": 10.00, // % capitale sociale
"data_iscrizione": "2010-06-01"
},
{
"tipo": "persona_giuridica",
"ragione_sociale": "HOLDING NORD S.R.L.",
"codice_fiscale": "12345678901",
"tipo_rapporto": "Socio",
"quota_eur": 45000,
"percentuale": 90.00,
"num_azioni": 9000, // presente solo per SPA (numero azioni)
"data_iscrizione": "2010-06-01"
}
],
"poteri_rappresentanza": "Il Presidente del Consiglio di Amministrazione ha la rappresentanza legale della società di fronte a terzi e in giudizio, con firma singola per operazioni fino a Euro 50.000; oltre tale importo è richiesta la firma congiunta di un secondo amministratore delegato.",
// null se non estratto dalla visura
"cariche": [
{
"nome_completo": "ROSSI MARIO",
"cognome": "ROSSI",
"nome": "MARIO",
"codice_fiscale": "RSSMRA70A01F205X",
"genere": "M",
"data_nascita": "1970-01-01",
"luogo_nascita": "Milano (MI)",
"domicilio": "Via Verdi 3 CAP 41100",
"ruolo": "Amministratore Unico",
"tutti_i_ruoli": ["Amministratore Unico"],
"data_nomina": "2020-01-15",
"data_cessazione": null, // data fine carica (presente nella visura storica)
"pec": "rossi@pec.it", // PEC personale dell'amministratore, se presente
"rappresentante_legale": true,
"contesto": "administrator"
},
{
"nome_completo": "TESTI GIULIO",
"codice_fiscale": "TSTGLL68T12F257H",
"ruolo": "curatore",
"data_nomina": "2025-01-15",
"contesto": "procedure" // "procedure" = soggetto in procedura concorsuale
}
],
"eventi": [ // presente solo per visura_storica — storia completa dalla fondazione
{
"data": "1998-03-15",
"tipo": "costituzione",
"categoria": "structural",
"descrizione": "Atto costitutivo - Notaio MARIO BIANCHI",
"dettagli": { "notaio": "MARIO BIANCHI" }
},
{
"data": "2020-01-15",
"tipo": "nomina",
"categoria": "governance",
"soggetto": "ROSSI MARIO",
"descrizione": "Nomina Amministratore Unico: ROSSI MARIO"
},
{
"data": "2022-06-30",
"tipo": "deposito_bilancio",
"categoria": "financial",
"descrizione": "Deposito bilancio esercizio 2021"
}
], // null per visura_camerale
"source": "parsed_from_pdf",
"parsed_at": "2026-02-27T10:00:00+01:00"
}
}
YYYY-MM-DD), estratta dall'intestazione del PDF o, come fallback, dalla data di acquisizione. Usare questo campo per valutare la "freschezza" del documento nei propri processi di compliance.Validità per contesto d'uso — non esiste una legge che stabilisce una validità universale: la CCIAA emette il documento "alla data odierna" senza scadenza. In pratica: uso KYC/CRM → 6 mesi comunemente accettati; gare d'appalto pubbliche (D.Lgs. 36/2023) → tipicamente 3-6 mesi; pratiche bancarie → 3 mesi; atti notarili/giudiziari → richiedere con
"force":true per documento fresco.rea: numero REA nel formato
"XX - 123456" dove XX è la sigla della Camera di Commercio (es. "RM - 381232"). Estratto dalla sezione 1 del PDF.sedi[] è un array: il primo elemento è sempre la sede legale (
"tipo": "sede_legale"), i successivi sono le unità locali ("tipo": "unita_locale"). Ogni sede ha: via, cap, comune, provincia. Le unità locali hanno il campo aggiuntivo attivita (tipo attività svolta) e ateco_codes[] con i codici ATECO specifici di quella sede (quando registrati al CCIAA — stessa struttura di ateco_codes aziendale). Tutte le unità locali registrate alla CCIAA sono incluse.soci[] rispecchia la sezione "Soci e titolari" della visura: presente per SRL e SPA, assente (array vuoto) per forme giuridiche che non pubblicano i soci (es. cooperative con molti soci, consorzi, fondazioni). Ogni elemento distingue
persona_fisica (campi nome, nascita, CF) da persona_giuridica (campo ragione_sociale). Il campo num_azioni è presente solo per SPA (in alternativa a quota_eur). Il campo percentuale è il float della % di partecipazione.poteri_rappresentanza: testo verbatim estratto dalla visura (sez. "Poteri di rappresentanza" o simile). Può essere
null se assente o non riconosciuto nel layout del PDF.cariche[] include tutti i campi anagrafici disponibili: nome, cognome, CF, data e luogo di nascita, domicilio, PEC personale (se presente nella visura). Il campo
data_cessazione indica la fine del mandato (presente nella visura storica per cariche cessate). contesto è "administrator" per cariche societarie normali e "procedure" per soggetti nominati in procedure concorsuali (curatore, liquidatore, ecc.).eventi[]: presente solo per
visura_storica — contiene la storia completa degli eventi societari dalla fondazione. Ogni evento ha: data (YYYY-MM-DD), tipo (es. nomina, deposito_bilancio, cambio_sede), categoria (structural/governance/financial/operational/compliance/ownership), soggetto (nome persona/società coinvolta, opzionale), descrizione (testo sintetico), dettagli (oggetto con info aggiuntive, es. notaio, giudice delegato). Per la visura_camerale questo campo è null.oggetto_sociale non viene troncato — può essere molto lungo (anche 2000+ caratteri). data_scadenza è la data di termine societaria (presente solo per società a tempo determinato,
null nella grande maggioranza dei casi).numero_addetti e addetti: estratti dalla sezione "Distribuzione dipendenti (elaborazione da fonte INPS)" della visura.
numero_addetti contiene la media annua totale. addetti è null se la sezione INPS è assente nel documento, altrimenti contiene: anno, data_rilievo, trimestri (con breakdown dipendenti/indipendenti/totale per Q1, Q2, Q3 e media annua), totale_medio (coincide con numero_addetti), addetti_per_comune (distribuzione per sede) e le tre distribuzioni percentuali trimestrali:•
distribuzione_contratto[]: % per tipo contratto (es. Tempo Indeterminato, Tempo Determinato)•
distribuzione_orario[]: % per orario di lavoro (Tempo Pieno / Tempo Parziale)•
distribuzione_qualifica[]: % per qualifica (Apprendista, Impiegato, Quadro, ecc.)Ciascuna distribuzione è
null quando il PDF non riporta valori percentuali per quella categoria (tipico in aziende con dipendenti omogenei per tipo/orario/qualifica).
Codici di stato
| HTTP | Significato |
|---|---|
| 200 | Dati strutturati disponibili |
| 202 | Documento ancora in elaborazione — riprova dopo il completamento |
| 422 | Tipo documento non supporta il parsing (solo visure) |
| 404 | File PDF non trovato su disco |
Guida: Dati strutturati — Quickstart
Vuoi ottenere in JSON i dati anagrafici di un'azienda italiana (ragione sociale, CF, P.IVA, sede, ATECO, cariche) a partire dalla sola Partita IVA? Questo è il flusso minimo.
visura_camerale, non la visura storica: contiene gli stessi dati anagrafici attuali, costa meno (€ 4,95 vs € 5,90) ed è più veloce. La visura storica serve solo se hai bisogno anche della storia completa degli eventi societari.
Richiedi la visura camerale
Invia il body con la P.IVA dell'azienda e "type": "visura_camerale". Se la stessa P.IVA è già stata richiesta nelle ultime 24h, il documento viene restituito dalla cache a costo zero (campo "cached": true).
curl -X POST "https://certisource.it/atti-service.php?action=richiesta" \ -H "Authorization: Bearer cs_pat_IL_TUO_TOKEN" \ -H "Content-Type: application/json" \ -d '{"vat":"01234567890","type":"visura_camerale"}' // Risposta immediata { "success": true, "id": 42, // salva questo id "status": "processing", "cached": false, "cost": 4.95, "data_url": "?action=dati&id=42" }
Se "cached": true → salta al passo 3, i dati sono già disponibili.
Fai polling su stato ogni 15 secondi
La visura camerale è pronta tipicamente in 30–120 secondi. Continua a interrogare ?action=stato finché "completed": true.
curl -H "Authorization: Bearer cs_pat_IL_TUO_TOKEN" \ "https://certisource.it/atti-service.php?action=stato&id=42" // Quando pronta: { "completed": true, "status": "completed", "download_url": "?action=scarica&id=42&token=...", "data_url": "?action=dati&id=42" }
In alternativa: usa i webhook (vedi Guida webhook) per ricevere una notifica push ed evitare il polling.
Leggi i dati strutturati JSON
Chiama ?action=dati&id=42. Il parsing viene eseguito automaticamente alla prima chiamata, poi i risultati sono in cache nel database CertiSource.
curl -H "Authorization: Bearer cs_pat_IL_TUO_TOKEN" \ "https://certisource.it/atti-service.php?action=dati&id=42" { "success": true, "structured_data": { "ragione_sociale": "ACME SRL", "forma_giuridica": "srl", "codice_fiscale": "01234567890", "partita_iva": "01234567890", "pec": "acme@pec.it", "rea": "MI - 2345678", "sedi": [ { "tipo": "sede_legale", "via": "Via Montenapoleone 1", "comune": "Milano", "provincia": "MI", "cap": "20121" }, { "tipo": "unita_locale", "via": "Via Roma 5", "comune": "Torino", "provincia": "TO", "attivita": "Magazzino", "ateco_codes": [{ "code": "62.01.00", "description": "Produzione di software", "type": "primary" }] } ], "ateco_codes": [{ "code": "62.01.00", "description": "Produzione di software", "type": "primary" }], "capitale_sociale": 10000, "data_rilascio": "2026-02-27", // data di emissione ufficiale CCIAA "cariche": [{ "nome_completo": "ROSSI MARIO", "codice_fiscale": "RSSMRA70A01F205X", "ruolo": "Amministratore Unico", "data_nomina": "2020-01-15", "rappresentante_legale": true }], "soci": [{ "tipo": "persona_fisica", "nome_completo": "ROSSI MARIO", "quota_eur": 10000, "percentuale": 100.0 }], "eventi": null // null per visura_camerale; array per visura_storica } }
Flusso completo in PHP
function getDatiAzienda(string $piva, string $pat): array { $base = 'https://certisource.it/atti-service.php'; $auth = ['Authorization: Bearer ' . $pat, 'Content-Type: application/json']; // 1. Richiesta $ch = curl_init($base . '?action=richiesta'); curl_setopt_array($ch, [CURLOPT_POST=>true, CURLOPT_HTTPHEADER=>$auth, CURLOPT_RETURNTRANSFER=>true, CURLOPT_POSTFIELDS=>json_encode(['vat'=>$piva, 'type'=>'visura_camerale'])]); $r = json_decode(curl_exec($ch), true); curl_close($ch); if (!$r['success']) throw new \Exception($r['error'] ?? 'Errore richiesta'); $id = $r['id']; if ($r['cached'] ?? false) goto dati; // cache hit → salta il polling // 2. Polling (max 3 minuti) for ($i=0; $i<12; $i++) { sleep(15); $ch = curl_init($base . '?action=stato&id=' . $id); curl_setopt_array($ch, [CURLOPT_HTTPHEADER=>$auth, CURLOPT_RETURNTRANSFER=>true]); $s = json_decode(curl_exec($ch), true); curl_close($ch); if ($s['completed'] ?? false) break; } // 3. Dati strutturati dati: $ch = curl_init($base . '?action=dati&id=' . $id); curl_setopt_array($ch, [CURLOPT_HTTPHEADER=>$auth, CURLOPT_RETURNTRANSFER=>true]); $d = json_decode(curl_exec($ch), true); curl_close($ch); return $d['structured_data'] ?? []; } // Uso: $dati = getDatiAzienda('01234567890', getenv('CERTISOURCE_PAT')); echo $dati['ragione_sociale']; // "ACME SRL" echo $dati['codice_fiscale']; // "01234567890" echo $dati['cariche'][0]['ruolo']; // "Amministratore Unico"
Note importanti
- La cache è automatica: se chiami la stessa P.IVA entro 24h, ricevi i dati in <1 secondo a costo zero.
- codice_fiscale: per le persone fisiche coincide con la P.IVA. Il campo è estratto direttamente dal PDF della visura (sezione 1).
- oggetto_sociale: non viene troncato — può contenere 2000+ caratteri. Filtra i newline (
\n) se necessario. - sedi[]: il primo elemento è sempre
"tipo": "sede_legale", i successivi sono unità locali (se presenti nella visura). - cariche[]: include tutti i campi anagrafici disponibili nel PDF. Il campo
codice_fiscaleper ogni persona è quello del soggetto (non dell'azienda). - numero_addetti + addetti: estratti dalla sezione INPS della visura (non sempre presente).
addettiènullse assente; altrimenti include: dettaglio trimestrale dipendenti/indipendenti/totale,addetti_per_comune, e le distribuzioni % per contratto, orario e qualifica (nullquando il PDF non riporta valori, tipico in aziende omogenee).
Guida: Personal API Token
Il modo più semplice per integrare un'applicazione che agisce per conto di un utente CertiSource con credito proprio.
Genera il token dal tuo account CertiSource
Vai su Profilo → Token API e crea un nuovo token con un nome che identifichi l'applicazione (es. "AgileApp ERP").
curl -X POST "https://certisource.it/api/auth/api-tokens" \ -H "Authorization: Bearer <jwt-sessione-certisource>" \ -H "Content-Type: application/json" \ -d '{"name":"AgileApp","permissions":["richiesta","stato","scarica"]}' // Risposta — il token appare UNA SOLA VOLTA: { "token": "cs_pat_9580bfab...", "warning": "Salva subito: non sarà più visibile" }
Incolla il token nella tua applicazione
Conserva il token in una variabile d'ambiente o un secret store. Non hardcodarlo nel codice sorgente.
CERTISOURCE_API_TOKEN=cs_pat_9580bfab2c71a...
Usalo nelle chiamate API
Aggiungi l'header Authorization: Bearer cs_pat_... ad ogni richiesta.
curl -X POST "https://certisource.it/atti-service.php?action=richiesta" \ -H "Authorization: Bearer $CERTISOURCE_API_TOKEN" \ -H "Content-Type: application/json" \ -d '{"vat":"04058890361","type":"visura_camerale"}'
Ciclo di vita del token
| Fase | Chi agisce | Cosa fare |
|---|---|---|
| Creazione | Titolare account CertiSource | Vai su Profilo → Token API → + Genera token. Scegli nome, permessi e scadenza. |
| Consegna | Titolare account CertiSource | Il token raw (cs_pat_…) è visibile una sola volta. Copialo e invialo all'amministratore tecnico dell'applicazione tramite canale sicuro (password manager condiviso, email cifrata, ecc.). |
| Configurazione | Amministratore tecnico app esterna | Salva il token come variabile d'ambiente (CERTISOURCE_TOKEN=cs_pat_…). Non includerlo nel codice sorgente né nei log. |
| Monitoraggio scadenza | Entrambi | Il campo expires_at è incluso nella risposta GET /api/auth/api-tokens. Imposta un alert nel tuo sistema di monitoring per almeno 30 giorni prima della scadenza. |
| Rotazione | Titolare account CertiSource | Genera il nuovo token → consegnalo all'app esterna → aggiorna la variabile d'ambiente → revoca il vecchio token. Ordine importante: aggiorna prima il nuovo, poi revoca il vecchio. |
| Revoca emergenza | Titolare account CertiSource | Clicca Revoca nella pagina Token API. Effetto immediato: tutte le chiamate successive con quel token ricevono HTTP 401. |
- Salvare
expires_atalla ricezione del token - Configurare un alert 30 giorni prima della scadenza (cron, monitoring, reminder in calendario)
- Contattare il referente CertiSource (titolare account) per ricevere il nuovo token prima della scadenza
- Verificare che HTTP 401 in produzione triggeri una notifica immediata al team (token scaduto o revocato)
GET /api/auth/api-tokens Authorization: Bearer <jwt-sessione-certisource> // Risposta: { "tokens": [{ "id": 2, "name": "Lg231.certisource.it", "permissions": ["richiesta", "stato", "scarica"], "expires_at": "2027-02-27T00:00:00", // null = nessuna scadenza "last_used_at": "2026-02-27T10:14:00", "is_active": 1 }] }
Endpoint: Verifica PAT
Controlla se un Personal API Token è valido, scaduto o revocato — senza consumare credito né generare richieste. Utile per health-check all'avvio dell'applicazione o per mostrare messaggi di errore chiari all'utente.
curl "https://certisource.it/atti-service.php?action=verifica-pat" \ -H "Authorization: Bearer cs_pat_IL_TUO_TOKEN"
La risposta è sempre HTTP 200. Controlla il campo valid e status:
| status | valid | Significato |
|---|---|---|
| active | true | Token valido e operativo |
| expired | false | Token scaduto — rinnova o genera uno nuovo |
| revoked | false | Token disattivato manualmente dall'utente |
| user_suspended | false | Account utente sospeso |
| not_found | false | Token non esiste nel sistema |
| no_token | false | Header Authorization mancante |
{
"valid": true,
"status": "active",
"name": "Lg231",
"permissions": { "read": true, "write": true },
"expires_at": null, // null = nessuna scadenza
"last_used_at": "2026-02-27T12:47:53"
}
// Token scaduto:
{ "valid": false, "status": "expired", "name": "Lg231", "expires_at": "2026-01-01T00:00:00" }
// Token non trovato:
{ "valid": false, "status": "not_found" }
last_used_at e non addebita nulla. Ideale per health-check periodici o per validare il token al bootstrap della tua applicazione.
Guida: Integrazione B2B (Client Credentials)
Per applicazioni che non hanno un utente CertiSource associato. Le credenziali client vengono fornite da CertiSource.
Ricevi client_id e client_secret
CertiSource genera le credenziali e te le fornisce una tantum (il secret non è recuperabile). Conservale in un secret store.
CS_CLIENT_ID=2d5c2723-294c-4a80-a61e-90e224c466ba CS_CLIENT_SECRET=54244aee8e48249600e233966b7a1bbf...
Ottieni il JWT (all'avvio o quando scade)
curl -X POST "https://certisource.it/atti-service.php?action=token" \ -H "Content-Type: application/json" \ -d '{"client_id":"$CS_CLIENT_ID","client_secret":"$CS_CLIENT_SECRET"}' // Risposta: { "access_token": "eyJ...", "expires_in": 86400 }
Usa il JWT — rinnovalo prima della scadenza
Il JWT scade dopo expires_in secondi. Salva la scadenza e rinnova il token qualche minuto prima. Il pattern di rinnovo automatico:
let token = null, tokenExpiry = 0; async function getToken() { if (Date.now() < tokenExpiry - 60000) return token; // rinnova 1 min prima const res = await fetch("?action=token", { method: "POST", body: JSON.stringify({ client_id: CS_CLIENT_ID, client_secret: CS_SECRET }), headers: { "Content-Type": "application/json" } }); const d = await res.json(); token = d.access_token; tokenExpiry = Date.now() + d.expires_in * 1000; return token; }
Guida: Esempio completo (visura)
Flusso end-to-end: richiesta → polling → download del PDF in PHP.
/** * Scarica una visura camerale per P.IVA. * Salva il PDF nella directory indicata. */ function scaricaVisura(string $vat, string $token, string $outputDir): string { define('API', 'https://certisource.it/atti-service.php'); define('AUTH', ['Authorization: Bearer ' . $token, 'Content-Type: application/json']); // 1. Richiesta documento $ch = curl_init(API . '?action=richiesta'); curl_setopt_array($ch, [CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => AUTH, CURLOPT_POSTFIELDS => json_encode(['vat' => $vat, 'type' => 'visura_camerale'])]); $res = json_decode(curl_exec($ch), true); if (!$res['success']) { throw new \RuntimeException($res['error'] ?? 'Errore richiesta'); } $id = $res['id']; echo "Richiesta #{$id} inviata. Costo: €{$res['cost']}\n"; // 2. Polling ogni 15s (max 10 minuti) for ($i = 0; $i < 40; $i++) { sleep(15); $ch = curl_init(API . "?action=stato&id={$id}"); curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => AUTH]); $stato = json_decode(curl_exec($ch), true); if ($stato['completed']) break; if ($stato['status'] === 'failed') throw new \RuntimeException($stato['error']); echo "Stato: {$stato['status']}...\n"; } if (!$stato['completed']) throw new \RuntimeException('Timeout'); // 3. Scarica PDF $ch = curl_init(API . "?action=scarica&id={$id}"); curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => AUTH]); $pdf = curl_exec($ch); $path = rtrim($outputDir, '/') . "/visura_{$vat}.pdf"; file_put_contents($path, $pdf); echo "PDF salvato: {$path}\n"; return $path; } // Utilizzo: scaricaVisura('04058890361', getenv('CERTISOURCE_API_TOKEN'), __DIR__ . '/downloads');
Guida: Webhook (event-driven)
Invece di interrogare ripetutamente ?action=stato puoi ricevere una notifica push quando il documento è pronto. CertiSource invierà un POST al tuo endpoint non appena la visura viene completata.
Aggiungi webhook_url alla richiesta
curl -X POST "https://certisource.it/atti-service.php?action=richiesta" \ -H "Authorization: Bearer cs_pat_IL_TUO_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "vat": "04058890361", "type": "visura_camerale", "webhook_url": "https://tua-app.it/callbacks/certisource", "webhook_secret": "un_segreto_condiviso" }'
Ricevi il webhook nel tuo endpoint
CertiSource invierà un POST con i seguenti header:
| Header | Valore |
|---|---|
| Content-Type | application/json |
| X-CertiSource-Event | atti_request.completed oppure atti_request.failed |
| X-CertiSource-Signature | sha256=<hmac> — presente solo se hai impostato webhook_secret |
| X-CertiSource-Attempt | Numero del tentativo corrente (1, 2 o 3). Utile per gestire i duplicati in caso di retry. |
{
"event": "atti_request.completed",
"id": 42,
"status": "completed",
"document_type":"visura_camerale",
"vat_number": "04058890361",
"file_name": "visura_camerale_123_20260226.pdf",
"cost_eur": 4.95,
"completed_at": "2026-02-27T12:47:53",
"cached": false,
"download_url": "https://certisource.it/atti-service.php?action=scarica&id=42",
"data_url": "https://certisource.it/atti-service.php?action=dati&id=42"
}
Il tuo endpoint deve rispondere con HTTP 2xx entro 10 secondi per confermare la ricezione. Qualsiasi altro codice (o timeout) viene considerato un fallimento e innesca il retry automatico.
Verifica la firma HMAC (opzionale ma consigliato)
$secret = 'un_segreto_condiviso'; $payload = file_get_contents('php://input'); $incomingSig = $_SERVER['HTTP_X_CERTISOURCE_SIGNATURE'] ?? ''; $expected = 'sha256=' . hash_hmac('sha256', $payload, $secret); if (!hash_equals($expected, $incomingSig)) { http_response_code(403); exit('Firma non valida'); } $data = json_decode($payload, true); // $data['id'] → id richiesta, $data['data_url'] → endpoint dati strutturati
Il webhook viene inviato immediatamente al completamento del documento. Se il tuo endpoint non risponde con
2xx, il sistema riprova automaticamente fino a 3 volte (ogni 5 minuti). Dopo 3 tentativi falliti l'evento è considerato abbandonato — puoi comunque recuperare il documento con ?action=stato o ?action=scarica.Importante per l'idempotenza: potresti ricevere lo stesso evento più volte (retry). Usa
id + X-CertiSource-Attempt per deduplicare sul tuo sistema.
Guida: Codici ATECO multipli e per sede
Ogni visura può contenere un codice ATECO primario (attività prevalente) e uno o più codici secondari a livello aziendale. Inoltre, ogni unità locale ha i propri codici ATECO registrati alla Camera di Commercio territoriale competente.
ATECO aziendali (livello azienda)
Il campo ateco_codes a livello top è un array ordinato: primo elemento = primario, gli altri = secondari.
// structured_data.ateco_codes — attività prevalente + secondarie dell'azienda [ { "code": "62.10.00", "description": "Attività di programmazione informatica", "type": "primary" }, { "code": "63.10.10", "description": "Fornitura di infrastrutture informatiche e hosting", "type": "secondary" }, { "code": "63.91.00", "description": "Attività dei portali di ricerca sul web", "type": "secondary" } ]
ATECO per unità locale (livello sede)
Ogni elemento di sedi[] di tipo unita_locale include il campo ateco_codes[] con i codici registrati presso la CCIAA di competenza di quella sede. Utile per sapere cosa fa concretamente ciascuna sede (es. sede di Roma fa consulenza, sede di Modena fa produzione).
// structured_data.sedi[] — sede_legale non ha ateco_codes, unità locali sì [ { "tipo": "sede_legale", "comune": "Roma", "provincia": "RM", "via": "Piazza di Campitelli 2" }, { "tipo": "unita_locale", "comune": "Modena", "provincia": "MO", "via": "Strada Scaglia Est 15", "cap": "41126", "ateco_codes": [ { "code": "62.10.00", "description": "Attività di programmazione informatica", "type": "primary" } ] } ]
const sd = data.structured_data; // ATECO aziendali const primario = sd.ateco_codes.find(c => c.type === 'primary'); const secondari = sd.ateco_codes.filter(c => c.type === 'secondary'); const tuttiCodici = sd.ateco_codes.map(c => c.code); // es. ['62.10.00', '63.10.10'] // ATECO per singola unità locale const unitaLocali = sd.sedi.filter(s => s.tipo === 'unita_locale'); unitaLocali.forEach(sede => { const atecoSede = sede.ateco_codes ?? []; // può essere assente se non registrato console.log(sede.comune, atecoSede.map(a => a.code)); }); // Matching template 231 per settore (usa ATECO prevalente) const templateId = getTemplateByAteco(primario?.code); // tua logica
GET ?action=credito
Restituisce il saldo credito dell'utente autenticato (reale + voucher) e lo storico degli ultimi movimenti. Richiede autenticazione utente (PAT obbligatorio — non disponibile con API Key B2B senza utente associato).
Parametri query (opzionali)
| Param | Default | Note |
|---|---|---|
| limit | 20 | N° movimenti da restituire (max 100) |
| order_id | — | Se presente: verifica stato di un ordine di ricarica specifico |
curl -H "Authorization: Bearer cs_pat_IL_TUO_TOKEN" \ "https://certisource.it/atti-service.php?action=credito&limit=10"
{
"success": true,
"credito": {
"reale": 45.60, // credito acquistato con pagamento
"voucher": 10.00, // credito promozionale (usato per primo)
"totale": 55.60 // da usare nei documenti
},
"ultimi_movimenti": [
{
"id": 88,
"transaction_type": "investigation_debit",
"credit_type": "voucher",
"amount": -4.95,
"balance_after": 55.60,
"description": "Richiesta Visura Camerale — P.IVA 04058890361",
"created_at": "2026-02-27 10:05:11"
}
],
"ricarica_url": "?action=ricarica"
}
{
"success": true,
"credito": { "reale": 145.60, "voucher": 0, "totale": 145.60 },
"ordine": {
"id": 67,
"status": "paid", // pending | paid | cancelled
"payment_status": "completed", // pending | completed | failed
"amount_eur": 100,
"bonus_amount": 10,
"total_credit": 110,
"created_at": "2026-02-27 09:00:00",
"paid_at": "2026-02-27 09:02:33"
}
}
POST ?action=ricarica
Avvia una ricarica credito con pagamento Revolut. Restituisce una checkout_url a cui reindirizzare l'utente per completare il pagamento con carta/Apple Pay/Google Pay. Richiede PAT.
Parametri body (JSON)
| Campo | Tipo | Note |
|---|---|---|
| amount | float | obbligatorio Importo in EUR da pagare (min €10, max €1000) |
| webhook_url | string | opzionale URL a cui ricevere la conferma quando il pagamento è completato |
| webhook_secret | string | opzionale Segreto HMAC-SHA256 per X-CertiSource-Signature |
| return_url | string | opzionale URL dove Revolut reindirizza l'utente dopo il pagamento |
curl -X POST "https://certisource.it/atti-service.php?action=ricarica" \ -H "Authorization: Bearer cs_pat_IL_TUO_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "amount": 100, "webhook_url": "https://tua-app.it/callbacks/pagamento", "webhook_secret": "segreto_hmac", "return_url": "https://tua-app.it/grazie" }'
const res = await fetch("https://certisource.it/atti-service.php?action=ricarica", { method: "POST", headers: { "Authorization": "Bearer cs_pat_...", "Content-Type": "application/json" }, body: JSON.stringify({ amount: 100, return_url: window.location.origin + "/grazie" }) }); const data = await res.json(); // Reindirizza l'utente al checkout Revolut if (data.checkout_url) { window.location.href = data.checkout_url; }
{
"success": true,
"order_id": 67,
"amount": 100, // EUR da pagare
"bonus_amount": 10, // EUR bonus (0 se amount < 100)
"total_credit": 110, // EUR che verranno aggiunti al saldo
"status": "pending",
"checkout_url": "https://checkout.revolut.com/payment-link/...",
"stato_url": "?action=credito&order_id=67",
"message": "Pagherai €100 e riceverai €110 di credito (bonus 10% incluso)."
}
Flusso completo
POST ?action=ricarica → checkout_url
Ottieni la URL di pagamento Revolut e reindirizza l'utente.
L'utente paga su Revolut
Carta, Apple Pay o Google Pay. CertiSource riceve conferma via webhook Revolut.
Credito accreditato automaticamente
CertiSource aggiunge il credito (incluso il bonus se applicabile). Il webhook_url che hai fornito riceve un POST con l'evento credit.recharged.
{
"event": "credit.recharged",
"order_id": 67,
"amount_paid": 100,
"credit_added": 110,
"bonus_amount": 10,
"paid_at": "2026-02-27T09:02:33+01:00"
}
Verifica il saldo aggiornato
GET ?action=credito&order_id=67
Oppure polling su ?action=credito per vedere il saldo aggiornato.
Codici di errore
| HTTP | code | Causa | Soluzione |
|---|---|---|---|
| 202 | PROCESSING | Documento ancora in elaborazione (solo action=dati) |
Attendi il completamento (action=stato) prima di richiedere i dati |
| 400 | BAD_REQUEST | Parametro mancante o azione non riconosciuta | Controlla i campi obbligatori |
| 401 | UNAUTHORIZED | Token mancante, scaduto o non valido | Rinnova il JWT o verifica il PAT |
| 402 | INSUFFICIENT_CREDIT | Credito account insufficiente | Ricarica il credito su CertiSource |
| 403 | FORBIDDEN | Richiesta appartenente ad altro utente | Usa l'account proprietario della richiesta |
| 404 | NOT_FOUND | ID richiesta non esistente | Verifica l'id restituito da richiesta |
| 409 | NOT_READY | Scarica chiamata ma documento non ancora pronto | Attendi completed: true in stato |
| 422 | VALIDATION | Parametri non validi (tipo doc errato, VAT formato errato) | Controlla la documentazione del campo |
| 429 | RATE_LIMIT | Troppe richieste | Aggiungi un backoff esponenziale |
| 502 | PROVIDER_ERROR | Errore del provider upstream (OpenAPI.it) | Riprova dopo 30s; il credito non viene addebitato |
Formato errore
{
"success": false,
"error": "Credito insufficiente",
"code": "INSUFFICIENT_CREDIT",
"needed": 4.95,
"available": 2.10,
"recharge_url": "https://certisource.it/pricing.html"
}
Informative — REST API
API REST per creare, avviare e monitorare Informative (indagini documentali a cascata): il sistema acquisisce automaticamente visure, dossier societari, cariche, partecipazioni e altri documenti per il soggetto richiesto, costruendo un grafo di relazioni aziendali.
Come funziona
Crea l'informativa
POST /api/investigations — passa P.IVA (o CF), tipo indagine e opzionalmente webhook_url. Ricevi subito l'investigation_id.
Avvia l'elaborazione
POST /api/investigations/{id}/start — CertiSource acquisisce tutti i documenti del piano in background (~30–120s). Il credito viene addebitato automaticamente.
Ricevi il webhook o fai polling
Se hai passato webhook_url, ricevi una POST al completamento. Altrimenti fai polling su GET /api/investigations/{id} finché status === "completed".
Leggi i dossier
GET /api/investigations/{id}/dossiers — ottieni il grafo completo: azienda target, persone fisiche collegate, aziende correlate, con documenti e dati strutturati per ciascun nodo.
Authorization: Bearer cs_pat_...) oppure JWT B2B. I costi scalano dal credito account.
POST /api/investigations — Crea Informativa
Crea una nuova informativa in stato draft. Non avvia ancora l'elaborazione né addebita credito.
Body (JSON)
| Campo | Tipo | Descrizione |
|---|---|---|
| target_type | string | richiesto "company" o "person" |
| target_vat_number | string | richiesto se company Partita IVA (11 cifre) o Codice Fiscale azienda |
| target_fiscal_code | string | richiesto se person Codice fiscale persona fisica (16 car.) |
| target_name | string | opzionale Nome/ragione sociale (migliora matching) |
| investigation_type | string | opzionale "company_full" (default) · "company_basic" · "person_full" · "network_analysis" |
| webhook_url | string | opzionale URL HTTPS per notifica push al completamento (evita polling) |
| webhook_secret | string | opzionale Segreto HMAC per verificare firma X-CertiSource-Signature |
curl -X POST "https://certisource.it/api/investigations" \ -H "Authorization: Bearer cs_pat_IL_TUO_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "target_type": "company", "target_vat_number": "04223920366", "investigation_type": "company_full", "webhook_url": "https://tua-app.it/webhook/certisource", "webhook_secret": "segreto_condiviso" }'
Risposta 201
{
"success": true,
"investigation_id": 42,
"investigation_code": "INV-20260317-A3F9BC",
"estimated_cost": 6.45,
"requires_delegations": false
}
POST /api/investigations/{id}/start — Avvia
Avvia l'elaborazione dell'informativa. CertiSource acquisisce in background tutti i documenti del piano, costruisce il grafo societario e indicizza i dati. Il credito viene addebitato progressivamente.
Body vuoto — nessun parametro richiesto.
curl -X POST "https://certisource.it/api/investigations/42/start" \ -H "Authorization: Bearer cs_pat_IL_TUO_TOKEN"
Risposta 200
{
"success": true,
"status": "processing",
"message": "Informativa avviata"
}
company_full. L'informativa passa da processing a completed (o partial se alcuni documenti falliscono). Usa il webhook o il polling su GET /{id} per sapere quando è pronta.
GET /api/investigations/{id} — Stato
Legge lo stato corrente dell'informativa con contatori e costo effettivo. Usa questo endpoint per il polling se non hai configurato un webhook.
{
"id": 42,
"investigation_code": "INV-20260317-A3F9BC",
"status": "completed", // draft|pending|processing|completed|partial|failed
"target_type": "company",
"target_vat_number": "04223920366",
"target_name": "RALLY S.R.L.",
"total_dossiers": 5,
"total_documents": 7,
"total_persons_found": 3,
"total_companies_found": 2,
"estimated_cost_eur": "6.45",
"actual_cost_eur": "5.94",
"started_at": "2026-03-17T14:20:00",
"completed_at": "2026-03-17T14:21:43"
}
Stati possibili
| Status | Significato |
|---|---|
| draft | Creata, non ancora avviata |
| processing | In elaborazione — non leggere i dossier ancora |
| completed | ✅ Completata, tutti i dossier disponibili |
| partial | ⚠️ Completata parzialmente (alcuni documenti falliti) |
| failed | ❌ Fallita — nessun addebito ulteriore |
GET /api/investigations/{id}/dossiers — Dossier
Restituisce il grafo completo: ogni nodo (azienda o persona) ha i propri documenti acquisiti, dati strutturati e servizi disponibili per acquisto aggiuntivo.
{
"dossiers": [
{
"id": 101,
"entity_type": "company", // "company" | "person"
"is_root": true,
"vat_number": "04223920366",
"business_name": "RALLY S.R.L.",
"documents_completed": 3,
"documents": [
{
"document_type_code": "visura_camerale",
"status": "completed",
"file_url": "https://certisource.it/uploads/documents/visura_..."
}
],
"structured_data": { // dati parsati dalla visura
"ragione_sociale": "RALLY S.R.L.",
"forma_giuridica": "SOCIETA' A RESPONSABILITA' LIMITATA",
"codice_fiscale": "04223920366",
"pec": "rally@pec.it",
"capitale_sociale": "10000",
"ateco_codes": ["..."],
"cariche": ["..."],
"sedi": ["..."]
}
},
{
"id": 102,
"entity_type": "person",
"is_root": false,
"person_cf": "TRTRMH89S21Z129V",
"first_name": "RADU",
"last_name": "MIHAI TRUTA",
"role_type": "Amministratore Unico",
"service_data": { // dati da servizi acquistati
"current_positions": { "..." },
"person_report": { "..." } // se acquistato
}
}
]
}
company includono structured_data con tutti i campi parsati dalla visura (cariche, soci, ATECO, sedi, capitale sociale, addetti, ecc.). Vedi la sezione Dati strutturati per la struttura completa.
POST /api/investigations/{id}/dossiers/{dossierId}/services — Acquista Servizio
Acquista un servizio aggiuntivo per un nodo del grafo. Il credito viene addebitato immediatamente. I servizi asincroni (es. person_report) vengono elaborati in background e notificati via webhook.
| Campo | Tipo | Descrizione |
|---|---|---|
| service_code | string | richiesto Codice servizio (vedi tabella sotto) |
Servizi disponibili per persone fisiche
| Codice | Descrizione | Costo | Tipo |
|---|---|---|---|
| person_report | Report completo: cariche storiche, immobili, protesti, score affidabilità PIN | € 1,50 | |
| current_positions | Cariche attuali in altre aziende | € 0,50 | |
| ricerca_immobili | Ricerca immobili intestati (catasto nazionale) | € 0,50 | |
| pra_proprietari | Veicoli intestati (PRA proprietari) | € 29,90 | |
| ispezione_ipotecaria | Ispezione ipotecaria nazionale | € 5,90 |
Servizi disponibili per aziende
| Codice | Descrizione | Costo | Tipo |
|---|---|---|---|
| visura_camerale | Visura camerale ordinaria aggiornata | € 4,95 | |
| visura_storica | Visura storica completa dalla fondazione | € 5,90 | |
| dossier_societa | Dossier societario completo (full company report) | € 0,89 | |
| protesti | Ricerca protesti | € 0,50 | |
| credit_scoring | Score di credito aziendale | € 0,50 |
curl -X POST "https://certisource.it/api/investigations/42/dossiers/102/services" \ -H "Authorization: Bearer cs_pat_IL_TUO_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "service_code": "person_report" }'
Risposta — servizio asincrono (person_report)
{
"success": true,
"async": true, // elaborazione in background (~1h)
"new_credit_balance": 98.35
}
Quando il servizio asincrono è completato, CertiSource aggiorna i service_data del dossier. Se l'informativa aveva un webhook_url, riceverai una notifica push.
Webhook Informative
Se passi webhook_url alla creazione dell'informativa, CertiSource invia una POST al completamento — sia per il completamento dell'intera informativa, sia per i servizi aggiuntivi asincroni acquistati successivamente.
Evento: informativa completata
POST https://tua-app.it/webhook/certisource Content-Type: application/json X-CertiSource-Event: investigation.completed X-CertiSource-Signature: sha256=<hmac-sha256-del-body> X-CertiSource-Attempt: 1
{
"event": "investigation.completed",
"investigation_id": 42,
"investigation_code": "INV-20260317-A3F9BC",
"status": "completed",
"target_type": "company",
"target_vat_number": "04223920366",
"target_name": "RALLY S.R.L.",
"completed_at": "2026-03-17T14:21:43",
"actual_cost_eur": "5.94",
"result_url": "https://certisource.it/api/investigations/42",
"dossiers_url": "https://certisource.it/api/investigations/42/dossiers"
}
Verifica firma HMAC
$secret = 'segreto_condiviso'; $payload = file_get_contents('php://input'); $sig = $_SERVER['HTTP_X_CERTISOURCE_SIGNATURE'] ?? ''; $expected = 'sha256=' . hash_hmac('sha256', $payload, $secret); if (!hash_equals($expected, $sig)) { http_response_code(403); exit; } $data = json_decode($payload, true); // $data['investigation_id'] → id informativa // Chiama $data['dossiers_url'] per leggere il grafo
2xx entro 10 secondi.Idempotenza: usa
investigation_id per deduplicare (possibili retry).Fallback: se non ricevi il webhook puoi sempre fare polling su
GET /api/investigations/{id}.