Lead
I lead sono i contatti non ancora qualificati in cima all'imbuto. Oltre alla CRUD completa, hanno l'operazione distintiva di conversione: da un lead nascono account, contatto ed eventuale trattativa in un colpo solo.
Envelope, errori, paginazione e advanced_filters sono comuni:
vedi Introduzione alle API. Ogni richiesta richiede
Authorization: Bearer <accessToken>.
01L'oggetto Lead
Ogni lead restituito dall'API ha questa forma. Le date sono stringhe ISO 8601 in UTC; i campi non leggibili dal tuo ruolo vengono omessi dalla risposta.
| Attributo | Tipo | Descrizione |
|---|---|---|
| id | integer | Identificativo univoco del lead. |
| source | string | null | Provenienza del lead (es. fiera, sito). |
| status | string | Stato del lead (default new). |
| first_name | string | Nome. |
| last_name | string | null | Cognome. |
| string | null | Email del lead. | |
| phone | string | null | Telefono. |
| company_name | string | null | Azienda del lead. |
| job_title | string | null | Ruolo/mansione. |
| estimated_value | number | Valore stimato (default 0). |
| owner_user_id | integer | null | Utente proprietario del record. |
| assigned_user_id | integer | null | Utente assegnatario. |
| created_by | integer | null | Utente che ha creato il record. |
| updated_by | integer | null | Ultimo utente che l'ha modificato. |
| is_deleted | boolean | true se in cestino (soft delete). |
| created_at | string | Data/ora di creazione (ISO 8601). |
| updated_at | string | Data/ora ultima modifica (ISO 8601). |
{ "id": 57, "source": "Fiera MECSPE", "status": "new", "first_name": "Marco", "last_name": "Rossi", "email": "m.rossi@brembotech.it", "phone": "+39 035 998877", "company_name": "Brembo Tech S.r.l.", "job_title": "Direttore tecnico", "estimated_value": 24000, "owner_user_id": 7, "assigned_user_id": 7, "created_by": 7, "updated_by": 7, "is_deleted": false, "created_at": "2026-07-07T15:24:00.000Z", "updated_at": "2026-07-07T15:24:00.000Z" }
02Endpoint
| Metodo | Path | Azione | Cosa fa |
|---|---|---|---|
| GET | /api/leads | read | Elenco paginato e filtrabile. |
| GET | /api/leads/:id | read | Un singolo lead. |
| GET | /api/leads/:id/history | read | Storico modifiche del record. |
| GET | /api/leads/lookup | read | Opzioni per i campi lookup (id + etichetta). |
| POST | /api/leads | create | Crea un lead. |
| PATCH | /api/leads/:id | update | Modifica parziale. |
| POST | /api/leads/:id/convert | update | Converte il lead in account + contatto (+ trattativa). |
| PATCH | /api/leads/bulk | update | Aggiornamento massivo. |
| DELETE | /api/leads/:id | delete | Soft delete. |
| POST | /api/leads/:id/restore | update | Ripristina un record eliminato. |
| GET | /api/leads/export.csv · .xlsx | export | Esporta l'elenco filtrato. |
| POST | /api/leads/import/preview · /execute | create | Import CSV. |
03Elencare i lead
Restituisce i lead visibili all'utente (secondo lo scope del ruolo), paginati.
Parametri query| Parametro | Tipo | Descrizione | |
|---|---|---|---|
| limit | integer | opzionale | Righe per pagina. Default 50, max 200. |
| offset | integer | opzionale | Righe da saltare (default 0). |
| sort_by | string | opzionale | Colonna di ordinamento (es. status, estimated_value, created_at). |
| sort_dir | string | opzionale | asc o desc. |
| advanced_filters | string (JSON) | opzionale | Array di condizioni: vedi Filtri avanzati. |
curl "https://crm.tuodominio.it/api/leads?limit=2&sort_by=created_at&sort_dir=desc" \ -H "Authorization: Bearer <accessToken>"
const res = await fetch("https://crm.tuodominio.it/api/leads?limit=2&sort_by=created_at&sort_dir=desc", { headers: { Authorization: `Bearer ${accessToken}` }, }); const { data } = await res.json();
{ "success": true, "data": { "items": [ { "id": 57, "first_name": "Marco", "status": "new", … }, { "id": 56, … } ], "pagination": { "limit": 2, "offset": 0, "count": 2, "sortBy": "created_at", "sortDir": "desc" } } }
04Recuperare un lead
| Parametro | Tipo | Descrizione |
|---|---|---|
| id | integer | Id del lead. |
| Stato | Corpo |
|---|---|
| 200 | { success: true, data: { …lead } } |
| 404 | NOT_FOUND: inesistente o fuori dal tuo scope. |
05Creare un lead
| Campo | Tipo | Note | |
|---|---|---|---|
| first_name | string | richiesto | Nome. 1–120 caratteri. |
| last_name | string | opzionale | Cognome. Max 120. |
| string | opzionale | Email, validata. | |
| phone | string | opzionale | Max 40 caratteri. |
| company_name | string | opzionale | Azienda del lead. Max 255. |
| job_title | string | opzionale | Ruolo/mansione. Max 120. |
| source | string | opzionale | Provenienza (es. fiera, sito). Max 80. |
| status | string | opzionale | Stato del lead. Max 40. |
| estimated_value | number | opzionale | Valore stimato (≥ 0). |
| owner_user_id | integer | opzionale | Proprietario. Assegnabile solo a sé o a un sottoposto nella gerarchia dei ruoli (admin: chiunque). Vedi Utenti e team. |
| assigned_user_id | integer | opzionale | Utente assegnatario. |
curl -X POST https://crm.tuodominio.it/api/leads \ -H "Authorization: Bearer <accessToken>" \ -H "Content-Type: application/json" \ -d '{ "first_name": "Marco", "last_name": "Rossi", "company_name": "Brembo Tech S.r.l.", "source": "Fiera MECSPE", "estimated_value": 24000 }'
const res = await fetch("https://crm.tuodominio.it/api/leads", { method: "POST", headers: { Authorization: `Bearer ${accessToken}`, "Content-Type": "application/json", }, body: JSON.stringify({ first_name: "Marco", last_name: "Rossi", company_name: "Brembo Tech S.r.l.", source: "Fiera MECSPE", estimated_value: 24000 }), }); const { data } = await res.json();
{ "success": true, "data": { "id": 57, "first_name": "Marco", "status": "new", "is_deleted": false, … } }
| Stato | Codice | Quando |
|---|---|---|
| 201 | · | Lead creato; nel corpo l'oggetto completo. |
| 422 | VALIDATION_ERROR | first_name mancante, campo fuori misura o valore picklist non valido. |
| 403 | FORBIDDEN | Campo non scrivibile dal ruolo (nei details l'elenco dei campi negati). |
06Aggiornare un lead
Modifica parziale: invia solo i campi da cambiare (gli stessi del body di creazione, tutti opzionali). Risponde 200 con l'oggetto aggiornato, 404 se fuori scope, 422 in validazione.
curl -X PATCH https://crm.tuodominio.it/api/leads/57 \ -H "Authorization: Bearer <accessToken>" \ -H "Content-Type: application/json" \ -d '{ "status": "qualified" }'
07Convertire un lead
Trasforma il lead in un account e un contatto, e facoltativamente crea una trattativa. Puoi agganciarlo a un account esistente oppure lasciarne creare uno nuovo dai dati del lead, con la possibilità di sovrascrivere singoli campi.
Body · tutti i campi sono opzionali| Campo | Tipo | Descrizione |
|---|---|---|
| existing_account_id | integer | Aggancia a un account già esistente invece di crearne uno nuovo. |
| create_deal | boolean | Se true, crea anche una trattativa. |
| account | object | Override dei campi del nuovo account: name, email, phone, website, industry, status, owner_user_id, assigned_user_id. |
| contact | object | Override dei campi del contatto creato: first_name, last_name, email, phone, job_title, owner_user_id, assigned_user_id. |
| deal | object | Campi della trattativa (usati con create_deal): name, stage, status, amount, close_date, owner_user_id, assigned_user_id. |
Non passare insieme existing_account_id e gli override di
account: o agganci un account esistente, o ne crei uno
nuovo. Le due cose insieme danno 422.
curl -X POST https://crm.tuodominio.it/api/leads/57/convert \ -H "Authorization: Bearer <accessToken>" \ -H "Content-Type: application/json" \ -d '{ "create_deal": true, "deal": { "name": "Fornitura 2026", "amount": 24000 } }'
const res = await fetch("https://crm.tuodominio.it/api/leads/57/convert", { method: "POST", headers: { Authorization: `Bearer ${accessToken}`, "Content-Type": "application/json", }, body: JSON.stringify({ create_deal: true, deal: { name: "Fornitura 2026", amount: 24000 } }), }); const { data } = await res.json();
{ "success": true, "data": { "account": { "id": 128, "name": "Brembo Tech S.r.l.", … }, "contact": { "id": 341, "first_name": "Marco", … }, "deal": { "id": 88, "name": "Fornitura 2026", … } // null se create_deal non era true } }
| Stato | Codice | Quando |
|---|---|---|
| 200 | · | Lead convertito; nel corpo account, contact ed eventuale deal. |
| 422 | VALIDATION_ERROR | existing_account_id passato insieme agli override di account, o campo non valido. |
| 404 | NOT_FOUND | Lead inesistente o fuori dal tuo scope. |
08Eliminare e ripristinare
Soft delete: il record viene marcato eliminato (is_deleted: true), non cancellato. Risponde 200 { deleted: true, id }.
Ripristina un lead eliminato (richiede il permesso update). Risponde 200 con l'oggetto ripristinato.
09Aggiornamento massivo
Applica gli stessi valori a una lista di record. Gli id fuori dal tuo scope vengono saltati; la risposta riporta quanti record sono stati effettivamente aggiornati.
Body{ "ids": [57, 56, 55], "changes": { "status": "qualified" } }
{ "success": true, "data": { "requested": 3, "updated": 2 } }
10Import ed export
- Export:
GET /export.csvo/export.xlsxrispettano gli stessi filtri della lista (advanced_filters, ordinamento). Richiedono il permessoexport. - Import:
POST /import/previewrestituisce un'anteprima con la mappatura colonne e gli errori riga per riga;POST /import/executeapplica. L'import richiede scopealle rispetta i permessi di scrittura per campo.