Vai al contenuto
Zentra
DemoProva gratuita

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

  1. Nell’app Zentra, apri Impostazioni › API, negozi e posta. Oppure passa dal tuo account online.
  2. 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.
  3. Copia subito la chiave: inizia con zk_ e non verrà più mostrata. Custodiscila come una password, solo lato server.
  4. 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/v1
Esempio
curl 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 }.
Esempio di risposta
{
  "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 /drafts
curl -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.
Cosa riceve il tuo server
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 disiscriversi
POST 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

  1. In Claude aprite Impostazioni, poi Connettori, e scegliete Aggiungi connettore personalizzato. Con un piano Team o Enterprise lo aggiunge un proprietario dell’organizzazione Claude.
  2. Chiamatelo Zentra e incollate l’indirizzo del server. Lasciate vuote le impostazioni avanzate.
  3. Cliccate su Connetti. Si apre Zentra: accedete, scegliete l’azienda e autorizzate l’accesso.
  4. Aprite Zentra una volta su un computer dell’azienda. L’app pubblica allora i dati che l’assistente legge.
Indirizzo del server
https://zentraapp.ch/api/mcp

Solo 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

Terminale
claude mcp add --transport http zentra https://zentraapp.ch/api/mcp

Avviate 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 posta

Prova l’API sui tuoi dati.

Quattordici giorni gratis, API e webhook compresi.

Senza carta di credito. Nessun pagamento automatico.