Acquisire contatti dal sito
Collega un modulo web al CRM con recapiti, provenienza, informativa e ritentativi sicuri.
POST /api/v1/contact-intakes è un ingresso server-to-server. Il tuo backend
valida il modulo e chiama SmartCQ; non inserire la chiave nel JavaScript pubblico.
Scope richiesto: contacts:write, con ruolo della chiave che consenta contact.create.
Configurare prima il responsabile dei nuovi contatti in Impostazioni → Team.
Usare una chiave dedicata per ogni integrazione, revocabile dalle impostazioni.
Il nuovo contatto entra in fase Lead assegnato all'inbox configurata. Il
messaggio compare nelle note. Da qui la lavorazione è quella ordinaria del CRM.
Non vengono aggiunti task o create trattative. L’API non invia email direttamente;
eventuali automazioni già configurate sul normale contact.created continuano
a seguire i propri filtri e tempi.
Corpo JSON
{
"source": "sito-agenzia-contatti",
"externalId": "1f0208e9-cf3d-4f06-81b2-e6c76f0b2e8a",
"occurredAt": "2026-09-21T10:00:00.000Z",
"contact": {
"firstName": "Nome",
"lastName": "Esempio",
"email": "persona@example.invalid",
"phone": "+393331234567"
},
"subject": "Richiesta di informazioni",
"message": "Vorrei essere ricontattato.",
"privacy": {
"noticeUrl": "https://agenzia.example/privacy",
"noticeVersion": "privacy-2026-09",
"presentedAt": "2026-09-21T09:59:30.000Z"
},
"attribution": {
"pageUrl": "https://agenzia.example/contatti",
"utmSource": "facebook",
"utmMedium": "paid-social",
"utmCampaign": "settembre"
}
}
Almeno email o telefono è obbligatorio. Omettere i campi opzionali assenti, non
inviare stringhe vuote/null. source è un'etichetta stabile (lettere, numeri,
punto, trattino e underscore; massimo 100 caratteri). externalId è un ID tecnico
opaco di massimo 200 caratteri: non usare nome, email o telefono.
Nome/cognome massimo 150 caratteri, email 254, telefono 40, oggetto 300, messaggio
5000; date ISO 8601 con fuso, non future. Corpo massimo 16 KiB. Campi sconosciuti
sono rifiutati: in particolare niente tenantId, stage, owner o emailStatus.
Attribuzione opzionale: pageUrl, utmSource, utmMedium, utmCampaign,
utmContent, utmTerm, externalLeadId; valori UTM/ID massimo 200 caratteri.
URL massimo 2048 caratteri e HTTP(S); nessun URL viene aperto dal server.
Non inviare documenti, credenziali o dati finanziari nel messaggio/metadati.
privacy dichiara quale informativa il sito ha presentato e quando. La versione
deve corrispondere al testo effettivo: SmartCQ non verifica la pagina remota e
non trasforma la dichiarazione in una presa visione avvenuta sui suoi portali.
Marketing opzionale
Solo se il modulo ha raccolto una scelta separata, può aggiungere:
{
"marketing": {
"granted": true,
"noticeVersion": "marketing-2026-09",
"text": "Testo esatto della scelta presentata alla persona",
"occurredAt": "2026-09-21T10:00:00.000Z"
}
}
Questo oggetto si aggiunge al corpo completo, non è un endpoint distinto.
Serve un'email per granted: true. Sui nuovi contatti viene registrata la
prova nel ledger marketing. Su contatti già esistenti la dichiarazione rimane
nell'audit/nota e non sostituisce consensi, revoche o suppression: utilizzare il
normale percorso di verifica del consenso. Omettere marketing o inviare false
non revoca un precedente consenso. La richiesta è acquisibile senza opt-in.
Risposta e idempotenza
{
"id": "uuid-ricevuta",
"contactId": "uuid-contatto",
"outcome": "created",
"replayed": false
}
201: transazione completata, contatto creato o riconosciuto (matched), nota e audit salvati.200: stesso invio già completato (replayed: true), nessuna duplicazione.contactIdpuò essere null se il contatto è stato successivamente eliminato; ripetere un vecchio invio non lo ricrea.
La chiave di idempotenza è tenant + source + externalId, indipendente dalla
rotazione della chiave API. Ripetere lo stesso corpo, comprese le date; cambiare
il corpo con lo stesso ID dà 409. Un nuovo messaggio reale usa un nuovo ID,
anche se la persona è già censita. Generare l'ID prima del primo tentativo e
conservarlo nel proprio registro durevole degli invii.
Su un contatto riconosciuto non vengono cambiati stage, owner, origine iniziale, recapiti o permessi marketing. Recapiti discordanti e contatti archiviati/cestinati richiedono verifica: l'API non effettua merge o ripristino automatico.
Errori e recupero
| HTTP | Significato | Azione |
|---|---|---|
| 400 / 415 / 422 | JSON, tipo contenuto o campi non validi | Correggere il payload; non ritentare invariato |
| 401 / 403 | Credenziali, scope/ruolo, stato organizzazione o piano | Correggere configurazione; non perdere l'invio nel sito |
| 409 | ID riutilizzato, identità ambigua, contatto archiviato, inbox/configurazione/quota | Leggere error.code e risolvere; niente retry continuo |
| 413 | Corpo oltre 16 KiB | Ridurre il corpo |
| 429 | Rate limit | Rispettare Retry-After |
| 503 / timeout / errore di rete | Acquisizione non confermata | Ritentare identico ID e corpo con backoff |
Non mostrare successo se la chiamata non è confermata. Un timeout può avvenire anche dopo il commit: il retry idempotente restituisce la ricevuta. Non fare fallback silenzioso a una destinazione alternativa. L'API eredita il rate limit per chiave attuale (60/minuto per istanza); non è un endpoint pubblico antispam. Il backend del sito deve proteggere il proprio modulo e la coda degli invii.
Esempio backend JavaScript
const response = await fetch(`${process.env.SMARTCQ_URL}/api/v1/contact-intakes`, {
method: "POST",
redirect: "error",
signal: AbortSignal.timeout(12000),
headers: {
Authorization: `Bearer ${process.env.SMARTCQ_API_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify(savedSubmission)
});
if (!response.ok) throw new Error(`SmartCQ HTTP ${response.status}`);
const receipt = await response.json();
savedSubmission è il corpo già validato e registrato dal tuo backend, riutilizzato
nei retry. Non loggare chiave o payload personali. La specifica OpenAPI
è esposta dall'host dell'app SmartCQ; il contratto include tutti i campi.
Questa API non implementa ancora ricezione Meta nativa o feedback Conversions API.