API REST
Endpoint Contatti
GET, POST, PATCH su /api/v1/contacts e /api/v1/contacts/:id con esempi cURL, Node.js e Python.
Endpoint per leggere e scrivere contatti del tenant.
GET /api/v1/contacts
Lista paginata con cursor-based pagination.
Scope richiesto: contacts:read
Query params
| Param | Tipo | Default | Descrizione |
|---|---|---|---|
limit | int | 50 | Numero di contatti per pagina (1–200) |
cursor | ISO timestamp | — | Restituisce contatti più vecchi di created_at < cursor. Lascia vuoto per la prima pagina. |
emailStatus | enum | — | active | unsubscribed | bounced | complained | suppressed | pending_review |
stage | enum | — | lead | prospect | customer | ex_customer |
includeArchived | bool | false | Se true, include i contatti archiviati |
Esempio cURL
curl -s -H "Authorization: Bearer $SMARTCQ_KEY" \
"https://app.smartcq.it/api/v1/contacts?limit=20&emailStatus=active"
Risposta 200
{
"data": [
{
"id": "00000000-0000-0000-0000-000000000001",
"email": "mario.rossi@example.com",
"firstName": "Mario",
"lastName": "Rossi",
"emailStatus": "active",
"stage": "lead",
"source": "manual",
"consentType": "contract",
"tags": ["cliente-storico", "milano"],
"archivedAt": null,
"acquiredAt": "2026-01-15T08:00:00.000Z",
"createdAt": "2026-01-15T08:00:00.000Z",
"updatedAt": "2026-01-15T08:00:00.000Z"
}
],
"next": "2026-01-15T08:00:00.000Z"
}
Per la pagina successiva, passa il valore di next come ?cursor=. Quando next è null, sei all'ultima pagina.
Esempio paginazione completa (Node.js)
async function fetchAllContacts() {
const all: Contact[] = [];
let cursor: string | null = null;
do {
const url = new URL("https://app.smartcq.it/api/v1/contacts");
url.searchParams.set("limit", "200");
if (cursor) url.searchParams.set("cursor", cursor);
const res = await fetch(url, {
headers: { Authorization: `Bearer ${process.env.SMARTCQ_KEY}` },
});
const j = await res.json();
all.push(...j.data);
cursor = j.next;
} while (cursor);
return all;
}
GET /api/v1/contacts/:id
Recupera un singolo contatto.
Scope richiesto: contacts:read
Esempio
curl -s -H "Authorization: Bearer $SMARTCQ_KEY" \
"https://app.smartcq.it/api/v1/contacts/00000000-0000-0000-0000-000000000001"
Risposta
200: oggettoContact(stesso schema della lista)404: contatto non trovato o non appartenente al tenant della chiave (no leak cross-tenant)
POST /api/v1/contacts
Crea un nuovo contatto. Idempotente per email all'interno dello stesso tenant.
Scope richiesto: contacts:write
Body
{
"email": "mario.rossi@example.com",
"firstName": "Mario",
"lastName": "Rossi",
"consentType": "contract",
"tags": ["cliente-storico", "milano"]
}
| Campo | Tipo | Obbligatorio | Note |
|---|---|---|---|
email | string (email) | sì | Validato lato server |
firstName | string | no | |
lastName | string | no | |
consentType | string | no | contract, consent, ... |
tags | string[] | no | Nomi dei tag (devono già esistere nel tenant) |
Nota — I tag devono già esistere nel tenant. Se passi un nome inesistente, ricevi
400 unknown_tag. Crea i tag dalla UI prima.
Esempio cURL
curl -s -X POST \
-H "Authorization: Bearer $SMARTCQ_KEY" \
-H "Content-Type: application/json" \
-d '{"email":"mario.rossi@example.com","firstName":"Mario"}' \
"https://app.smartcq.it/api/v1/contacts"
Risposta
201: oggettoContactappena creato400: body malformato o tag inesistente409: email già presente nel tenant (conexisting.idnel payload errore)
// 409
{
"error": {
"code": "conflict",
"message": "Contatto già esistente con questa email",
"existing": { "id": "00000000-0000-0000-0000-000000000001", "status": "active" }
}
}
Esempio Python
import os
import requests
resp = requests.post(
"https://app.smartcq.it/api/v1/contacts",
headers={"Authorization": f"Bearer {os.environ['SMARTCQ_KEY']}"},
json={
"email": "mario.rossi@example.com",
"firstName": "Mario",
"consentType": "contract",
},
)
if resp.status_code == 409:
existing = resp.json()["error"]["existing"]
print(f"Già esistente: {existing['id']}")
else:
resp.raise_for_status()
print(resp.json())
PATCH /api/v1/contacts/:id
Modifica un contatto esistente. Solo i campi presenti nel body sono aggiornati.
Scope richiesto: contacts:write
Body (tutti i campi opzionali)
{
"firstName": "Mario",
"lastName": "Rossi",
"emailStatus": "unsubscribed",
"stage": "prospect",
"consentType": "contract"
}
Esempio cURL
curl -s -X PATCH \
-H "Authorization: Bearer $SMARTCQ_KEY" \
-H "Content-Type: application/json" \
-d '{"stage":"prospect"}' \
"https://app.smartcq.it/api/v1/contacts/00000000-0000-0000-0000-000000000001"
Risposta
200: oggettoContactaggiornato400: body malformato (es.stagecon valore sconosciuto)404: contatto non trovato o non del tenant