Per gli sviluppatori
L’API di Zentra.
Collega a Zentra il tuo sito, il tuo negozio o i tuoi strumenti. Leggi i tuoi dati, invia bozze e ricevi un avviso a ogni fattura pagata.
- Lettura in JSON
- Clienti, articoli, preventivi, ordini, fatture e pagamenti, con una semplice API REST.
- Niente senza il tuo consenso
- Ciò che inviano i tuoi strumenti arriva come bozza. La convalidi nell’app.
- Incluso
- In Solo, Team e Pro, senza supplemento. 600 chiamate all’ora per chiave.
Prima di iniziare
- Nell’app Zentra, apri Impostazioni › API, negozi e posta. Oppure passa dal tuo account online.
- Crea una chiave e dalle un nome, per esempio «sito web». Scegli «Lettura», oppure «Lettura e bozze» se il tuo strumento deve anche inviare richieste.
- Copia subito la chiave: inizia con zk_ e non verrà più mostrata. Custodiscila come una password, solo lato server.
- Apri Zentra su un computer dell’azienda. L’app pubblica allora i dati che l’API può leggere e li tiene aggiornati finché resta aperta.
Solo il titolare e gli amministratori dell’azienda creano e revocano le chiavi. Una chiave revocata smette subito di funzionare.
I tuoi dati restano nell’app: il server conserva solo l’ultima versione pubblicata di questi sei tipi di record, per le aziende che hanno creato una chiave o un webhook. Il campo publishedAt di ogni risposta indica quando l’app li ha pubblicati.
Autenticazione
Ogni chiamata invia la chiave nell’intestazione Authorization. Tutti gli indirizzi iniziano con:
https://zentraapp.ch/api/v1Esempiocurl https://zentraapp.ch/api/v1/invoices?status=issued&limit=20 \
-H "Authorization: Bearer zk_votre_cle"Le risposte sono in JSON, in UTF-8, e non vengono mai memorizzate in cache. Non chiamare l’API da un browser: la chiave sarebbe visibile.
Risorse
Sei risorse in sola lettura. Ognuna si legge come elenco, oppure un record alla volta tramite il suo identificativo.
/customers- Clienti
id, number, name, company, contactPerson, email, phone, addressLine1, addressLine2, postalCode, city, country, archived /articles- Articoli e prestazioni del catalogo
id, kind, sku, name, description, unit, unitPriceCents, vatBp, trackStock, stockQuantityMilli, archived /quotes- Preventivi
id, number, customerId, title, status, currency, issueDate, validUntil, subtotalCents, discountCents, vatCents, totalCents, lines /orders- Ordini dei clienti
id, number, customerId, title, status, currency, orderDate, externalReference, totalCents, lines /invoices- Fatture
id, number, customerId, title, status, type, currency, issueDate, dueDate, subtotalCents, discountCents, vatCents, totalCents, paidCents, openCents, lines /payments- Pagamenti ricevuti
id, invoiceId, date, amountCents, currency, method, reference
Preventivi, ordini e fatture contengono le loro righe, con position, articleId, description, quantityMilli, unit, unitPriceCents, discountBp, vatBp e totalCents. Ogni record riporta anche updatedAt e changedAt.
Elenchi e paginazione
Gli elenchi sono ordinati per data di modifica. Per riprendere tutto senza perdere nulla, segui nextCursor finché hasMore vale true.
limit- Numero di risultati per pagina, da 1 a 100. 50 per impostazione predefinita.
cursor- Il valore nextCursor della pagina precedente.
updated_since- Solo ciò che è cambiato da questa data (ISO 8601 o timestamp Unix).
status- Filtro sullo stato, per esempio issued, paid o draft.
customer_id- Solo i documenti di un cliente.
include_deleted- true per ricevere anche le eliminazioni, nella forma { id, deleted: true }.
{
"object": "list",
"entity": "invoices",
"data": [
{
"object": "invoice",
"id": "inv_8f2c",
"number": "2026-0142",
"customerId": "cus_51a0",
"status": "issued",
"currency": "CHF",
"issueDate": "2026-10-20",
"dueDate": "2026-11-19",
"totalCents": 129690,
"paidCents": 0,
"openCents": 129690,
"lines": [ … ],
"changedAt": "2026-10-20T09:14:03.000Z"
}
],
"hasMore": true,
"nextCursor": "c1_WzE3OTI…",
"publishedAt": "2026-10-26T07:55:12.000Z"
}Sincronizzare i clienti// Node 18 ou plus récent : reprendre tout ce qui a changé depuis la dernière fois
const headers = { Authorization: `Bearer ${process.env.ZENTRA_API_KEY}` };
let url = 'https://zentraapp.ch/api/v1/customers?limit=100&include_deleted=true&updated_since=2026-10-01';
while (url) {
const response = await fetch(url, { headers });
if (!response.ok) throw new Error((await response.json()).error.message);
const page = await response.json();
for (const customer of page.data) console.log(customer.id, customer.name ?? 'supprimé');
url = page.nextCursor ? `https://zentraapp.ch/api/v1/customers?limit=100&include_deleted=true&cursor=${page.nextCursor}` : null;
}Importi e quantità
Tutti i numeri sono interi calcolati dall’app. Il server non ricalcola nulla.
…Cents- Importi in centesimi: 129690 = CHF 1’296.90.
…Milli- Quantità in millesimi: 1000 = un’unità.
vatBp, discountBp- Aliquote in punti base: 100 = 1 %. L’aliquota IVA normale si scrive 810.
currency- CHF o EUR.
openCents- Saldo ancora dovuto su una fattura.
Inviare una bozza
Un modulo del tuo sito può creare una richiesta di preventivo, un ordine o un nuovo cliente. La bozza arriva nell’app, da convalidare o rifiutare. Nulla viene registrato o inviato senza di te.
POST /draftscurl -X POST https://zentraapp.ch/api/v1/drafts \
-H "Authorization: Bearer zk_votre_cle" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: site-demande-20261026-0042" \
-d '{
"kind": "quote",
"customer": { "name": "Marie Rochat", "email": "marie.rochat@example.ch" },
"reference": "Formulaire du site",
"note": "Pose prévue en novembre",
"lines": [
{ "sku": "RAD-600", "description": "Radiateur 600 W", "quantity": "3" },
{ "description": "Pose et mise en service", "quantity": "1.5" }
]
}'Risposta 202{ "object": "draft", "id": "in_3b9e…", "kind": "quote", "state": "pending", "duplicate": false }- Il campo kind vale customer, quote o order. Un preventivo o un ordine conta da 1 a 200 righe.
- Indica un cliente esistente con il suo id, oppure i suoi dati: name, company, email, phone, addressLine1, addressLine2, postalCode, city, country.
- Ogni riga ha una quantità, e uno sku, un articleId o una descrizione. Gli eventuali prezzi sono solo indicativi: l’app applica il tuo catalogo e calcola i totali.
- Con l’intestazione Idempotency-Key, uno stesso invio ripetuto crea una sola bozza. La risposta indica allora duplicate: true.
- Per seguire una bozza, leggi /drafts/ seguito dal suo id: lo stato vale pending, imported o rejected, con il riferimento del documento creato.
Webhook
Zentra avvisa il tuo indirizzo https a ogni evento scelto. Aggiungi il webhook nello stesso posto delle chiavi. Il suo segreto di firma inizia con whsec_ e viene mostrato una sola volta.
customer.created- Viene creato un cliente.
quote.created- Viene emesso un preventivo.
quote.accepted- Un preventivo viene accettato.
order.created- Un ordine viene confermato.
invoice.created- Viene emessa una fattura.
invoice.paid- Una fattura è pagata per intero.
payment.created- Viene registrato un pagamento.
draft.imported- Una bozza inviata dall’API è stata convalidata nell’app.
draft.rejected- Una bozza inviata dall’API è stata rifiutata.
POST https://exemple.ch/zentra
Zentra-Event: invoice.paid
Zentra-Event-Id: evt_…
Zentra-Delivery-Id: dlv_…
Zentra-Signature: t=1793091600,v1=5d41c0…
{
"id": "evt_…",
"type": "invoice.paid",
"apiVersion": 1,
"createdAt": "2026-10-26T08:20:00.000Z",
"data": { "object": "invoice", "record": { "id": "inv_8f2c", "status": "paid", … } }
}La firma è un HMAC-SHA256 esadecimale, calcolato con il tuo segreto sul timestamp t, un punto e poi il corpo ricevuto. Rifiuta un timestamp di oltre cinque minuti.
Verificare la firma (Node)import { createHmac, timingSafeEqual } from 'node:crypto';
// rawBody : le corps reçu, tel quel, avant tout JSON.parse
export function isFromZentra(rawBody, signatureHeader, secret) {
const parts = Object.fromEntries(signatureHeader.split(',').map((part) => part.split('=')));
const timestamp = Number(parts.t);
if (!Number.isInteger(timestamp) || Math.abs(Date.now() / 1000 - timestamp) > 300) return false;
const expected = createHmac('sha256', secret).update(`${timestamp}.${rawBody}`).digest('hex');
return parts.v1?.length === expected.length && timingSafeEqual(Buffer.from(parts.v1), Buffer.from(expected));
}Iscrizioni tramite l’API
Zapier, Make, n8n o il vostro strumento possono creare e rimuovere i loro webhook con la chiave API. GET /me verifica la chiave e dà il nome dell’azienda; GET /webhooks elenca le iscrizioni.
Iscriversi e disiscriversiPOST https://zentraapp.ch/api/v1/webhooks
Authorization: Bearer zk_votre_cle
Content-Type: application/json
{ "url": "https://hooks.zapier.com/hooks/catch/…", "events": ["invoice.paid"] }
201 { "object": "webhook", "id": "whe_…", "events": ["invoice.paid"], "secret": "whsec_…" }
DELETE https://zentraapp.ch/api/v1/webhooks/whe_…- Rispondi con un codice 2xx entro dieci secondi. I reindirizzamenti non vengono seguiti.
- In caso di errore, l’invio viene ripetuto fino a otto volte: dopo 1 minuto, 5 minuti, 30 minuti, poi 2, 6, 12 e 24 ore.
- Dopo venti errori di fila, il webhook va in pausa. Il pulsante «Riprendi» lo riattiva.
- Lo stesso evento può arrivare due volte: elimina i doppioni con Zentra-Event-Id.
- Il pulsante «Invia un test» invia un evento ping.
Assistenti IA (MCP)
Claude, ChatGPT o qualsiasi assistente compatibile MCP può leggere i vostri dati Zentra. Risponde a «Chi mi deve ancora dei soldi?» partendo dagli importi calcolati dall’app.
In Claude, senza chiave
- In Claude aprite Impostazioni, poi Connettori, e scegliete Aggiungi connettore personalizzato. Con un piano Team o Enterprise lo aggiunge un proprietario dell’organizzazione Claude.
- Chiamatelo Zentra e incollate l’indirizzo del server. Lasciate vuote le impostazioni avanzate.
- Cliccate su Connetti. Si apre Zentra: accedete, scegliete l’azienda e autorizzate l’accesso.
- Aprite Zentra una volta su un computer dell’azienda. L’app pubblica allora i dati che l’assistente legge.
https://zentraapp.ch/api/mcpSolo il titolare e gli amministratori possono collegare un assistente, un’azienda alla volta. Gli assistenti collegati sono elencati nel vostro account, in Integrazioni: basta un clic per scollegarli.
In Claude Code
Terminaleclaude mcp add --transport http zentra https://zentraapp.ch/api/mcpAvviate poi /mcp in Claude Code e scegliete Zentra per accedere.
Domande pronte
Il server propone anche domande già pronte. In Claude compaiono nel menu «+» della conversazione.
qui_me_doit- Chi mi deve dei soldi?
ma_journee- Cosa mi aspetta oggi?
relances_semaine- Preparare i solleciti della settimana
resume_mois- Riassumere il mio mese
creer_devis- Creare un preventivo
nouveau_client- Aggiungere un cliente
Con una chiave API
Uno strumento che non offre l’accesso con l’account può usare una chiave API, inviata nell’intestazione Authorization.
Configurazione{
"mcpServers": {
"zentra": {
"type": "http",
"url": "https://zentraapp.ch/api/mcp",
"headers": { "Authorization": "Bearer zk_votre_cle" }
}
}
}search_customers- Cerca clienti per nome, società o e-mail.
get_customer- Un cliente e le sue ultime fatture.
list_invoices- Fatture aperte, scadute, pagate o in bozza.
get_invoice- Una fattura con le sue righe e i suoi pagamenti.
list_quotes- Preventivi per stato e per cliente.
list_orders- Ordini dei clienti.
search_articles- Articoli del catalogo, con prezzo e scorte.
company_summary- Cifre chiave: fatture aperte e scadute, numero di record.
prepare_draft- Deposita da convalidare un cliente, un fornitore, un articolo, un progetto, un’attività di progetto, un appuntamento, un preventivo, un ordine, una fattura in bozza o una nota. Se manca un dettaglio, risponde con le domande da porre. Solo se le bozze sono autorizzate.
draft_requirements- Le informazioni obbligatorie di ogni bozza, con la domanda da porre.
search_projects- Progetti e cantieri, per collegarvi un’attività, un appuntamento o una nota.
search_suppliers- Fornitori per nome o contatto.
list_autopilot_tasks- Le attività in attesa in Autopilota, con le azioni che l’assistente può richiedere.
act_on_autopilot_task- Conferma un’attività su vostra richiesta: creare una scheda o una bozza ricevuta, aggiungere un appuntamento, rimandare, ignorare, segnare un’attività come fatta. Solo se al collegamento avete spuntato «Confermare attività di Autopilota».
check_request- Indica se una bozza o un’azione richiesta è già stata trattata dall’app.
L’assistente non può inviare, pagare né eliminare nulla. Una bozza che prepara attende la vostra convalida nell’app, a meno che non gli chiediate di confermarla.
Quando manca un dettaglio, Zentra non tira a indovinare: un articolo senza prezzo, un cliente che somiglia a più schede o un progetto introvabile tornano all’assistente come domande, che vi pone prima di creare.
Un’azione confermata viene eseguita dall’app Zentra non appena è aperta su un computer dell’azienda, poi registrata nel giornale di Autopilota. Inviare un’e-mail o un sollecito, registrare un pagamento, emettere una fattura e avviare un’esecuzione si fanno sempre nell’app.
Errori e limiti
Un errore restituisce un codice HTTP e un oggetto error con un codice stabile e un messaggio in francese.
{ "error": { "code": "rate_limited", "message": "Trop d’appels pour cette clé. Réessayez dans une heure." } }- 400
invalid_query, invalid_draft, invalid_body - La richiesta non è valida. Il messaggio indica quale campo correggere.
- 401
unauthorized - Chiave mancante, copiata male o revocata.
- 402
subscription_inactive - L’abbonamento dell’azienda non è più attivo.
- 403
forbidden - La chiave può solo leggere. Crea una chiave «Lettura e bozze».
- 404
not_found - Risorsa o identificativo sconosciuto.
- 405
method_not_allowed - È accettato solo GET, tranne POST su drafts.
- 429
rate_limited - Oltre 600 chiamate nell’ora per questa chiave. L’intestazione Retry-After indica l’attesa in secondi.
- 503
unavailable - Servizio momentaneamente non disponibile. Riprova più tardi.
Limiti: 600 chiamate all’ora per chiave, 100 risultati per pagina, 64 KB per bozza.
Collegare Shopify, WooCommerce o la postaProva l’API sui tuoi dati.
Quattordici giorni gratis, API e webhook compresi.
Senza carta di credito. Nessun pagamento automatico.
