Sigillo

API e webhook · incluse in Premium

Collega Sigillo al resto del tuo lavoro.

Crea preventivi dal form del tuo sito, porta i clienti nel CRM, scarica le fatture con l'XML per lo SDI e ricevi un avviso quando il cliente firma o paga. API REST in JSON, una chiave per autenticarti, webhook firmati.

Base URLhttps://app.mysigillo.com/api/v1

Introduzione

A chi servono le API

Le API di Sigillo sono per chi vuole far parlare i preventivi con altri strumenti: il form del proprio sito, un CRM, un foglio di calcolo, Zapier o Make, il gestionale del commercialista. Se fai tutto dall'app non ti servono.

Leggi e crei preventivi e clienti, pubblichi il link da mandare al cliente, scarichi PDF, fatture e XML per lo SDI, leggi le richieste arrivate dalla vetrina. Con i webhook Sigillo ti avvisa quando succede qualcosa, senza che tu debba controllare di continuo.

API e webhook sono inclusi nel piano Premium, senza costi aggiuntivi. Le chiavi le creano il titolare e gli admin del workspace. Confronta i piani.

Autenticazione

Una chiave per workspace

  1. Apri l'app, vai in Impostazioni → API e webhook e premi Nuova chiave.
  2. Dai un nome alla chiave (es. “Sito web”) e scegli il permesso.
  3. Copia la chiave: inizia con sgl_live_ e la vedi una volta sola. Sigillo ne conserva solo un'impronta, quindi se la perdi ne crei una nuova e revochi la vecchia.

Mandala in ogni richiesta nell'header Authorization:

header
Authorization: Bearer sgl_live_…
PermessoCosa può fare
LetturaTutti gli endpoint GET: preventivi, rate, PDF, clienti, fatture, XML, richieste.
Lettura e scritturaTutto quello della lettura, più POST e PATCH: creare e modificare clienti, creare e pubblicare preventivi.

Una chiave di sola lettura su un endpoint di scrittura riceve 403 forbidden. Una chiave revocata, sbagliata o mancante riceve 401 unauthorized. Ogni chiave vale per un solo workspace.

Ogni workspace può avere al massimo 5 chiavi attive: una per integrazione (il form del sito, Zapier, il gestionale) e una di scorta per cambiare chiave senza interruzioni. Crea la nuova, aggiorna l'integrazione, poi revoca la vecchia. Le chiavi revocate non contano.

Tieni la chiave sul server, mai nel codice JavaScript di una pagina web o in un'app distribuita: chi la legge può agire sul tuo workspace. Se pensi che sia finita in giro, revocala da Impostazioni: smette di funzionare subito.

Base URL e formato

JSON su HTTPS

base url
https://app.mysigillo.com/api/v1
  • Solo HTTPS. Le richieste con body usano Content-Type: application/json.
  • I campi sono in snake_case. Gli importi sono in euro, come numeri con i decimali (1628.7), non in centesimi.
  • Le date civili sono AAAA-MM-GG (2026-09-15); i momenti sono ISO 8601 in UTC (2026-09-15T09:12:44.000Z).
  • I campi senza valore valgono null, non spariscono dalla risposta.

Limiti

60 richieste al minuto

Ogni chiave può fare fino a 60 richieste al minuto. Il limite è per chiave, non per workspace. Ogni risposta ti dice a che punto sei:

HeaderSignificato
X-RateLimit-LimitRichieste consentite nella finestra (60).
X-RateLimit-RemainingRichieste che puoi ancora fare con questa chiave nel minuto corrente.

Oltre il limite ricevi 429 rate_limited: aspetta qualche secondo e riprova, meglio con un'attesa che cresce a ogni tentativo. Per sincronizzare molti dati usa la paginazione con limit=100 invece di tante richieste piccole, e i webhook invece di interrogare l'API a intervalli.

Errori

Sempre lo stesso formato

Le risposte con errore hanno uno status HTTP 4xx o 5xx e questo body. code è stabile e fatto per il tuo codice; message è in italiano e fatto per le persone.

errore
{
  "error": {
    "code": "invalid_request",
    "message": "items deve contenere almeno una riga."
  }
}
HTTPcodeQuando
400invalid_requestParametri o body non validi (il messaggio dice quale campo), campi sconosciuti, oppure metodo HTTP non previsto su un percorso esistente.
401unauthorizedChiave mancante, sbagliata o revocata.
402plan_limitIl workspace non è più Premium, o hai raggiunto un limite del piano.
403forbiddenLa chiave non ha il permesso per questa operazione (es. scrittura con chiave di lettura).
404not_foundL’oggetto non esiste o appartiene a un altro workspace.
409conflictL’operazione non è possibile nello stato attuale dell’oggetto.
429rate_limitedTroppe richieste: vedi i limiti.
500internalErrore nostro. Riprova tra poco; se continua scrivici.

Un metodo non previsto su un percorso che esiste (per esempio DELETE /clients/{id}) riceve 400 invalid_request, non 405, con l'header Allow che elenca i metodi accettati:

risposta 400
HTTP/1.1 400 Bad Request
Allow: GET, PATCH
Content-Type: application/json

{
  "error": {
    "code": "invalid_request",
    "message": "Metodo DELETE non previsto su questo percorso."
  }
}

Paginazione

Liste a cursore

Gli endpoint che restituiscono liste (GET /quotes, /clients, /invoices, /requests) partono dagli elementi più recenti e accettano:

ParametroDescrizione
limitQuanti elementi per pagina, da 1 a 100. Predefinito 20.
starting_afterL’id dell’ultimo elemento della pagina precedente.

La risposta ha has_more (ci sono altre pagine?) e next_cursor, da passare come starting_after alla richiesta successiva. Quando has_more è false, next_cursor è null.

curl
curl "https://app.mysigillo.com/api/v1/clients?limit=2&starting_after=cl_8Hq2Lm4Tz9" \
  -H "Authorization: Bearer sgl_live_…"
risposta 200
{
  "object": "list",
  "data": [
    {
      "id": "cl_2Wn7Rt5Kx3",
      "object": "client",
      "…": "…"
    },
    {
      "id": "cl_6Jd1Pq8Vy4",
      "object": "client",
      "…": "…"
    }
  ],
  "has_more": true,
  "next_cursor": "cl_6Jd1Pq8Vy4"
}

Endpoint

Riferimento

Tutti i percorsi sono relativi a https://app.mysigillo.com/api/v1.

MetodoPercorsoCosa fa
GET/meWorkspace e chiave in uso
GET/quotesElenco preventivi
GET/quotes/{id}Un preventivo
POST/quotesCrea un preventivo in bozza
POST/quotes/{id}/publishPubblica il link per il cliente
GET/quotes/{id}/pdfPDF del preventivo
GET/quotes/{id}/paymentsRate e pagamenti
GET · POST/clientsElenco e creazione clienti
GET · PATCH/clients/{id}Leggi o modifica un cliente
GET/invoicesElenco fatture e note di credito
GET/invoices/{id}Una fattura
GET/invoices/{id}/xmlXML FatturaPA per lo SDI
GET/requestsRichieste dalla vetrina

Account

GET/mechiave lettura

Verifica la chiave

Il primo test da fare: se risponde 200, la chiave funziona. Restituisce il workspace a cui appartiene la chiave e il suo permesso.

curl
curl https://app.mysigillo.com/api/v1/me \
  -H "Authorization: Bearer sgl_live_…"
risposta 200
{
  "workspace": {
    "id": "ws_Ab12Cd34",
    "name": "Studio Rossi Design",
    "plan": "premium"
  },
  "key": {
    "id": "ak_Q8wE2rT6yU",
    "name": "Sito web",
    "scope": "write"
  }
}

Preventivi

GET/quoteschiave lettura

Elenco dei preventivi

Dal più recente. Accetta limit e starting_after. Gli stati possibili sono draft, sent, accepted, rejected, expired.

curl
curl "https://app.mysigillo.com/api/v1/quotes?limit=20" \
  -H "Authorization: Bearer sgl_live_…"
risposta 200
{
  "object": "list",
  "data": [
    {
      "id": "qt_3Kf9Xw2Pa7",
      "object": "quote",
      "number": "2026-014",
      "status": "sent",
      "client": {
        "id": "cl_8Hq2Lm4Tz9",
        "name": "Marta Bianchi",
        "company": "Studio Bianchi Srl",
        "email": "marta@studiobianchi.it",
        "vat_number": "IT01234567890",
        "fiscal_code": null,
        "address": "Via Roma 12"
      },
      "items": [
        {
          "description": "Logo e identità visiva",
          "quantity": 1,
          "unit_price": 1200,
          "vat_rate": 22,
          "discount": 0
        },
        {
          "description": "Biglietti da visita (500 pz)",
          "quantity": 1,
          "unit_price": 150,
          "vat_rate": 22,
          "discount": 10
        }
      ],
      "currency": "EUR",
      "totals": {
        "subtotal": 1335,
        "vat": 293.7,
        "cassa": 0,
        "total": 1628.7
      },
      "issue_date": "2026-09-15",
      "valid_until": "2026-10-15",
      "public_url": "https://app.mysigillo.com/q/Tk7wQ2…",
      "signed_at": null,
      "signer_name": null,
      "created_at": "2026-09-15T09:12:44.000Z",
      "updated_at": "2026-09-15T09:20:02.000Z",
      "created_by_name": "Alessio Bertolini"
    }
  ],
  "has_more": true,
  "next_cursor": "qt_3Kf9Xw2Pa7"
}
GET/quotes/{id}chiave lettura

Un preventivo

curl
curl https://app.mysigillo.com/api/v1/quotes/qt_3Kf9Xw2Pa7 \
  -H "Authorization: Bearer sgl_live_…"
risposta 200
{
  "id": "qt_3Kf9Xw2Pa7",
  "object": "quote",
  "number": "2026-014",
  "status": "sent",
  "client": {
    "id": "cl_8Hq2Lm4Tz9",
    "name": "Marta Bianchi",
    "company": "Studio Bianchi Srl",
    "email": "marta@studiobianchi.it",
    "vat_number": "IT01234567890",
    "fiscal_code": null,
    "address": "Via Roma 12"
  },
  "items": [
    {
      "description": "Logo e identità visiva",
      "quantity": 1,
      "unit_price": 1200,
      "vat_rate": 22,
      "discount": 0
    },
    {
      "description": "Biglietti da visita (500 pz)",
      "quantity": 1,
      "unit_price": 150,
      "vat_rate": 22,
      "discount": 10
    }
  ],
  "currency": "EUR",
  "totals": {
    "subtotal": 1335,
    "vat": 293.7,
    "cassa": 0,
    "total": 1628.7
  },
  "issue_date": "2026-09-15",
  "valid_until": "2026-10-15",
  "public_url": "https://app.mysigillo.com/q/Tk7wQ2…",
  "signed_at": null,
  "signer_name": null,
  "created_at": "2026-09-15T09:12:44.000Z",
  "updated_at": "2026-09-15T09:20:02.000Z",
  "created_by_name": "Alessio Bertolini"
}
POST/quoteschiave scrittura

Crea un preventivo in bozza

Il preventivo nasce in bozza: lo trovi nell'app, pronto da rivedere o da pubblicare. La risposta è 201 con l'oggetto quote completo.

CampoDescrizione
client_idId di un cliente in rubrica. In alternativa a client.
clientDati del cliente scritti nel preventivo: stessi campi dell'oggetto client (name obbligatorio, notes escluso). Vengono copiati solo nel preventivo: non creano un cliente in rubrica (per quello usa POST /clients).
itemsAlmeno una riga: description, quantity, unit_price (euro), vat_rate (percentuale, es. 22), discount (percentuale, facoltativo).
issue_dateData del preventivo, AAAA-MM-GG. Facoltativa.
valid_untilScadenza, AAAA-MM-GG. Facoltativa.
notesNote visibili al cliente. Facoltative.
termsTermini e condizioni. Facoltativi.

Ritenuta, cassa previdenziale e marca da bollo seguono le impostazioni fiscali del workspace, come quando crei il preventivo dall'app.

Serve esattamente uno tra client_id e client: se li mandi entrambi, o nessuno dei due, ricevi 400 invalid_request.

curl
curl https://app.mysigillo.com/api/v1/quotes \
  -H "Authorization: Bearer sgl_live_…" \
  -H "Content-Type: application/json" \
  -d '{
  "client": {
    "name": "Luca Verdi",
    "email": "luca@verdi.it",
    "company": "Trattoria Verdi"
  },
  "items": [
    {
      "description": "Sito vetrina 5 pagine",
      "quantity": 1,
      "unit_price": 1800,
      "vat_rate": 22,
      "discount": 0
    },
    {
      "description": "Modulo prenotazioni",
      "quantity": 1,
      "unit_price": 400,
      "vat_rate": 22,
      "discount": 0
    }
  ],
  "issue_date": "2026-09-17",
  "valid_until": "2026-10-17",
  "notes": "Consegna in 4 settimane dalla firma.",
  "terms": "Acconto 30% alla firma, saldo alla consegna."
}'
risposta 201
{
  "id": "qt_7Lp2Qs9Dm4",
  "object": "quote",
  "number": "2026-015",
  "status": "draft",
  "client": {
    "id": "cl_8Hq2Lm4Tz9",
    "name": "Marta Bianchi",
    "company": "Studio Bianchi Srl",
    "email": "marta@studiobianchi.it",
    "vat_number": "IT01234567890",
    "fiscal_code": null,
    "address": "Via Roma 12"
  },
  "items": [
    {
      "description": "Logo e identità visiva",
      "quantity": 1,
      "unit_price": 1200,
      "vat_rate": 22,
      "discount": 0
    },
    {
      "description": "Biglietti da visita (500 pz)",
      "quantity": 1,
      "unit_price": 150,
      "vat_rate": 22,
      "discount": 10
    }
  ],
  "currency": "EUR",
  "totals": {
    "subtotal": 1335,
    "vat": 293.7,
    "cassa": 0,
    "total": 1628.7
  },
  "issue_date": "2026-09-15",
  "valid_until": "2026-10-15",
  "public_url": null,
  "signed_at": null,
  "signer_name": null,
  "created_at": "2026-09-15T09:12:44.000Z",
  "updated_at": "2026-09-15T09:20:02.000Z",
  "created_by_name": "Alessio Bertolini"
}
POST/quotes/{id}/publishchiave scrittura

Pubblica il link per il cliente

Crea il link pubblico, come il bottone “Pubblica” nell'app. Il cliente lo apre, legge, firma e paga. pin è il codice che il cliente inserisce per aprire il link; null se il link non è protetto. Mandali con canali diversi, per esempio link via email e PIN via WhatsApp.

curl
curl -X POST https://app.mysigillo.com/api/v1/quotes/qt_7Lp2Qs9Dm4/publish \
  -H "Authorization: Bearer sgl_live_…"
risposta 200
{
  "public_url": "https://app.mysigillo.com/q/Tk7wQ2…",
  "pin": "4821"
}
GET/quotes/{id}/pdfchiave lettura

Scarica il PDF

Risponde con il file (Content-Type: application/pdf), lo stesso PDF che scarichi dall'app.

curl
curl https://app.mysigillo.com/api/v1/quotes/qt_3Kf9Xw2Pa7/pdf \
  -H "Authorization: Bearer sgl_live_…" \
  -o preventivo-2026-014.pdf
GET/quotes/{id}/paymentschiave lettura

Rate e pagamenti

Il piano dei pagamenti del preventivo. payment_url è il link di pagamento Stripe della rata, se l'hai creato. È una lista standard, sempre completa in una pagina: has_more vale false.

curl
curl https://app.mysigillo.com/api/v1/quotes/qt_3Kf9Xw2Pa7/payments \
  -H "Authorization: Bearer sgl_live_…"
risposta 200
{
  "object": "list",
  "data": [
    {
      "id": "pay_1",
      "label": "Acconto 30%",
      "amount": 488.61,
      "due_date": "2026-09-20",
      "paid": true,
      "paid_at": "2026-09-18",
      "method": "stripe",
      "payment_url": "https://buy.stripe.com/…"
    },
    {
      "id": "pay_2",
      "label": "Saldo",
      "amount": 1140.09,
      "due_date": "2026-10-30",
      "paid": false,
      "paid_at": null,
      "method": null,
      "payment_url": "https://buy.stripe.com/…"
    }
  ],
  "has_more": false,
  "next_cursor": null
}

Clienti

GET/clientschiave lettura

Elenco dei clienti

curl
curl "https://app.mysigillo.com/api/v1/clients?limit=50" \
  -H "Authorization: Bearer sgl_live_…"
risposta 200
{
  "object": "list",
  "data": [
    {
      "id": "cl_8Hq2Lm4Tz9",
      "object": "client",
      "name": "Marta Bianchi",
      "company": "Studio Bianchi Srl",
      "email": "marta@studiobianchi.it",
      "phone": "+39 347 123 4567",
      "vat_number": "IT01234567890",
      "fiscal_code": null,
      "sdi_code": "M5UXCR1",
      "pec": null,
      "address": "Via Roma 12",
      "city": "Milano",
      "zip": "20121",
      "province": "MI",
      "country": "IT",
      "notes": null,
      "created_at": "2026-09-02T08:14:03.000Z",
      "updated_at": "2026-09-10T16:40:21.000Z"
    }
  ],
  "has_more": false,
  "next_cursor": null
}
POST/clientschiave scrittura

Crea un cliente

Campi dell'oggetto client, tutti stringhe. name è obbligatorio. Un campo che non esiste nell'oggetto client riceve 400 invalid_request.

curl
curl https://app.mysigillo.com/api/v1/clients \
  -H "Authorization: Bearer sgl_live_…" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "Marta Bianchi",
  "company": "Studio Bianchi Srl",
  "email": "marta@studiobianchi.it",
  "vat_number": "IT01234567890",
  "sdi_code": "M5UXCR1"
}'
risposta 201
{
  "id": "cl_8Hq2Lm4Tz9",
  "object": "client",
  "name": "Marta Bianchi",
  "company": "Studio Bianchi Srl",
  "email": "marta@studiobianchi.it",
  "phone": "+39 347 123 4567",
  "vat_number": "IT01234567890",
  "fiscal_code": null,
  "sdi_code": "M5UXCR1",
  "pec": null,
  "address": "Via Roma 12",
  "city": "Milano",
  "zip": "20121",
  "province": "MI",
  "country": "IT",
  "notes": null,
  "created_at": "2026-09-02T08:14:03.000Z",
  "updated_at": "2026-09-10T16:40:21.000Z"
}
GET/clients/{id}chiave lettura

Un cliente

curl
curl https://app.mysigillo.com/api/v1/clients/cl_8Hq2Lm4Tz9 \
  -H "Authorization: Bearer sgl_live_…"
risposta 200
{
  "id": "cl_8Hq2Lm4Tz9",
  "object": "client",
  "name": "Marta Bianchi",
  "company": "Studio Bianchi Srl",
  "email": "marta@studiobianchi.it",
  "phone": "+39 347 123 4567",
  "vat_number": "IT01234567890",
  "fiscal_code": null,
  "sdi_code": "M5UXCR1",
  "pec": null,
  "address": "Via Roma 12",
  "city": "Milano",
  "zip": "20121",
  "province": "MI",
  "country": "IT",
  "notes": null,
  "created_at": "2026-09-02T08:14:03.000Z",
  "updated_at": "2026-09-10T16:40:21.000Z"
}
PATCH/clients/{id}chiave scrittura

Modifica un cliente

Mandi solo i campi da cambiare; quelli che non mandi restano com'erano. Un valore null rimuove il campo (non vale per name, che è obbligatorio). Un campo sconosciuto riceve 400 invalid_request. I preventivi già fatti non cambiano: tengono i dati del cliente di quel momento.

curl
curl -X PATCH https://app.mysigillo.com/api/v1/clients/cl_8Hq2Lm4Tz9 \
  -H "Authorization: Bearer sgl_live_…" \
  -H "Content-Type: application/json" \
  -d '{
  "pec": "studiobianchi@pec.it",
  "phone": null
}'
risposta 200
{
  "id": "cl_8Hq2Lm4Tz9",
  "object": "client",
  "name": "Marta Bianchi",
  "company": "Studio Bianchi Srl",
  "email": "marta@studiobianchi.it",
  "phone": null,
  "vat_number": "IT01234567890",
  "fiscal_code": null,
  "sdi_code": "M5UXCR1",
  "pec": "studiobianchi@pec.it",
  "address": "Via Roma 12",
  "city": "Milano",
  "zip": "20121",
  "province": "MI",
  "country": "IT",
  "notes": null,
  "created_at": "2026-09-02T08:14:03.000Z",
  "updated_at": "2026-09-10T16:40:21.000Z"
}

Fatture

GET/invoiceschiave lettura

Elenco di fatture e note di credito

from e to (AAAA-MM-GG, inclusi) filtrano per data di emissione; entrambi facoltativi. document_type è il tipo SDI: TD01 fattura, TD04 nota di credito.

curl
curl "https://app.mysigillo.com/api/v1/invoices?from=2026-09-01&to=2026-09-30" \
  -H "Authorization: Bearer sgl_live_…"
risposta 200
{
  "object": "list",
  "data": [
    {
      "id": "inv_5Rt8Yc1Mn2",
      "object": "invoice",
      "number": "2026/0004",
      "document_type": "TD01",
      "status": "issued",
      "issue_date": "2026-09-16",
      "client": {
        "name": "Studio Bianchi Srl",
        "vat_number": "IT01234567890"
      },
      "currency": "EUR",
      "totals": {
        "subtotal": 1335,
        "vat": 293.7,
        "total": 1628.7
      },
      "quote_id": "qt_3Kf9Xw2Pa7",
      "created_at": "2026-09-16T10:02:11.000Z"
    }
  ],
  "has_more": false,
  "next_cursor": null
}
GET/invoices/{id}chiave lettura

Una fattura

curl
curl https://app.mysigillo.com/api/v1/invoices/inv_5Rt8Yc1Mn2 \
  -H "Authorization: Bearer sgl_live_…"
risposta 200
{
  "id": "inv_5Rt8Yc1Mn2",
  "object": "invoice",
  "number": "2026/0004",
  "document_type": "TD01",
  "status": "issued",
  "issue_date": "2026-09-16",
  "client": {
    "name": "Studio Bianchi Srl",
    "vat_number": "IT01234567890"
  },
  "currency": "EUR",
  "totals": {
    "subtotal": 1335,
    "vat": 293.7,
    "total": 1628.7
  },
  "quote_id": "qt_3Kf9Xw2Pa7",
  "created_at": "2026-09-16T10:02:11.000Z"
}
GET/invoices/{id}/xmlchiave lettura

XML FatturaPA

Risponde con il file XML (application/xml) nel formato FatturaPA 1.2, lo stesso che scarichi dall'app da caricare sul portale SDI o da girare al commercialista.

curl
curl https://app.mysigillo.com/api/v1/invoices/inv_5Rt8Yc1Mn2/xml \
  -H "Authorization: Bearer sgl_live_…" \
  -o IT18522971003_00004.xml

Richieste

GET/requestschiave lettura

Richieste dalla vetrina

Le richieste di preventivo arrivate dalla tua vetrina pubblica. status è facoltativo: new, viewed, converted, archived, spam.

curl
curl "https://app.mysigillo.com/api/v1/requests?status=new" \
  -H "Authorization: Bearer sgl_live_…"
risposta 200
{
  "object": "list",
  "data": [
    {
      "id": "rq_9Pz4Kd7Wb1",
      "object": "request",
      "status": "new",
      "name": "Luca Verdi",
      "email": "luca@verdi.it",
      "phone": null,
      "service": "Sito web",
      "budget": "1_5k",
      "message": "Mi serve un sito vetrina per il mio ristorante, 5 pagine e prenotazioni.",
      "created_at": "2026-09-17T07:45:30.000Z"
    }
  ],
  "has_more": false,
  "next_cursor": null
}

Oggetti

Cosa restituisce l’API

Ogni oggetto ha id e object (il tipo). Gli oggetti non espongono mai dati interni come la firma grafica, gli indirizzi IP o i token dei link.

quote

CampoTipoDescrizione
numberstringNumero del preventivo.
statusstringdraft, sent, accepted, rejected, expired.
clientobjectid, name, company, email, vat_number, fiscal_code, address: i dati del cliente scritti nel preventivo.
itemsarrayRighe: description, quantity, unit_price, vat_rate, discount.
currencystringSempre EUR.
totalsobjectsubtotal, vat, cassa, total in euro.
issue_date · valid_untildateData del preventivo e scadenza.
public_urlstring | nullLink per il cliente, se pubblicato.
signed_at · signer_namedatetime · string | nullQuando e chi ha firmato.
created_at · updated_atdatetimeCreazione e ultima modifica.
created_by_namestring | nullChi l’ha creato.
quote
{
  "id": "qt_3Kf9Xw2Pa7",
  "object": "quote",
  "number": "2026-014",
  "status": "sent",
  "client": {
    "id": "cl_8Hq2Lm4Tz9",
    "name": "Marta Bianchi",
    "company": "Studio Bianchi Srl",
    "email": "marta@studiobianchi.it",
    "vat_number": "IT01234567890",
    "fiscal_code": null,
    "address": "Via Roma 12"
  },
  "items": [
    {
      "description": "Logo e identità visiva",
      "quantity": 1,
      "unit_price": 1200,
      "vat_rate": 22,
      "discount": 0
    },
    {
      "description": "Biglietti da visita (500 pz)",
      "quantity": 1,
      "unit_price": 150,
      "vat_rate": 22,
      "discount": 10
    }
  ],
  "currency": "EUR",
  "totals": {
    "subtotal": 1335,
    "vat": 293.7,
    "cassa": 0,
    "total": 1628.7
  },
  "issue_date": "2026-09-15",
  "valid_until": "2026-10-15",
  "public_url": "https://app.mysigillo.com/q/Tk7wQ2…",
  "signed_at": null,
  "signer_name": null,
  "created_at": "2026-09-15T09:12:44.000Z",
  "updated_at": "2026-09-15T09:20:02.000Z",
  "created_by_name": "Alessio Bertolini"
}

payment

CampoTipoDescrizione
labelstringNome della rata (es. Acconto 30%).
amountnumberImporto in euro.
due_datedate | nullScadenza.
paid · paid_atboolean · date | nullSe è pagata e quando.
methodstring | nullbonifico, stripe, paypal, contanti, assegno, altro.
payment_urlstring | nullLink di pagamento Stripe della rata.
payment
{
  "id": "pay_1",
  "label": "Acconto 30%",
  "amount": 488.61,
  "due_date": "2026-09-20",
  "paid": true,
  "paid_at": "2026-09-18",
  "method": "stripe",
  "payment_url": "https://buy.stripe.com/…"
}

client

CampoTipoDescrizione
namestringNome e cognome o nome di riferimento. Obbligatorio.
companystring | nullRagione sociale.
email · phonestring | nullContatti.
vat_number · fiscal_codestring | nullPartita IVA e codice fiscale.
sdi_code · pecstring | nullCodice destinatario SDI (7 caratteri) e PEC per la fattura elettronica.
address · city · zip · province · countrystring | nullIndirizzo. province è la sigla (MI).
notesstring | nullNote interne, non visibili al cliente.
created_at · updated_atdatetimeCreazione e ultima modifica.

invoice

CampoTipoDescrizione
numberstringNumero della fattura (es. 2026/0004).
document_typestringTipo documento SDI: TD01 fattura, TD04 nota di credito.
statusstringdraft, issued, paid, cancelled.
issue_datedateData di emissione.
clientobjectname e vat_number del cliente.
totalsobjectsubtotal, vat, total in euro.
quote_idstring | nullIl preventivo da cui è nata.
created_atdatetimeCreazione.
invoice
{
  "id": "inv_5Rt8Yc1Mn2",
  "object": "invoice",
  "number": "2026/0004",
  "document_type": "TD01",
  "status": "issued",
  "issue_date": "2026-09-16",
  "client": {
    "name": "Studio Bianchi Srl",
    "vat_number": "IT01234567890"
  },
  "currency": "EUR",
  "totals": {
    "subtotal": 1335,
    "vat": 293.7,
    "total": 1628.7
  },
  "quote_id": "qt_3Kf9Xw2Pa7",
  "created_at": "2026-09-16T10:02:11.000Z"
}

request

CampoTipoDescrizione
statusstringnew, viewed, converted, archived, spam.
name · email · phonestringChi ha scritto.
servicestring | nullIl servizio scelto nel form.
budgetstring | nullFascia: lt_1k, 1_5k, 5_15k, 15k_plus, unknown.
messagestringDescrizione del progetto.
created_atdatetimeQuando è arrivata.
request
{
  "id": "rq_9Pz4Kd7Wb1",
  "object": "request",
  "status": "new",
  "name": "Luca Verdi",
  "email": "luca@verdi.it",
  "phone": null,
  "service": "Sito web",
  "budget": "1_5k",
  "message": "Mi serve un sito vetrina per il mio ristorante, 5 pagine e prenotazioni.",
  "created_at": "2026-09-17T07:45:30.000Z"
}

Webhook

Ti avvisiamo noi

Un webhook è un URL tuo che Sigillo chiama con una richiesta POST quando succede qualcosa. Lo crei in Impostazioni → API e webhook → Nuovo webhook: inserisci l'URL (solo https://), scegli gli eventi e copia il segreto di firma (whsec_…), che vedi una volta sola. Da lì puoi mandare un evento di prova, vedere le ultime consegne, disattivarlo o ruotare il segreto. Puoi configurare fino a 10 webhook per workspace.

Eventi

EventoQuandodata
quote.publishedHai pubblicato il link di un preventivo.object: quote
quote.viewedIl cliente ha aperto il link (al massimo un evento ogni 10 minuti per preventivo).object: quote
quote.signedIl cliente ha accettato e firmato.object: quote
quote.rejectedIl cliente ha rifiutato.object: quote
payment.receivedUna rata risulta pagata.object: payment, quote_id
invoice.createdÈ stata emessa una fattura.object: invoice
creditnote.createdÈ stata emessa una nota di credito (document_type TD04).object: invoice
request.receivedÈ arrivata una richiesta dalla vetrina.object: request
pingEvento di prova inviato con “Invia test” in Impostazioni, anche se il webhook è disattivato. Non conta per le statistiche né per la disattivazione automatica.

Cosa ricevi

Il body è JSON. id identifica l'evento: se ricevi due volte lo stesso id (può succedere con i nuovi tentativi), elaboralo una volta sola.

POST al tuo URL
POST /webhook/sigillo HTTP/1.1
Content-Type: application/json
Sigillo-Event: quote.signed
Sigillo-Signature: t=1789640400,v1=5f2b0c…e91a

{
  "id": "evt_4Hs8Nq2Lw6",
  "type": "quote.signed",
  "created": 1789640400,
  "workspace_id": "ws_Ab12Cd34",
  "data": {
    "object": {
      "id": "qt_3Kf9Xw2Pa7",
      "object": "quote",
      "number": "2026-014",
      "status": "accepted",
      "client": {
        "id": "cl_8Hq2Lm4Tz9",
        "name": "Marta Bianchi",
        "company": "Studio Bianchi Srl",
        "email": "marta@studiobianchi.it",
        "vat_number": "IT01234567890",
        "fiscal_code": null,
        "address": "Via Roma 12"
      },
      "items": [
        {
          "description": "Logo e identità visiva",
          "quantity": 1,
          "unit_price": 1200,
          "vat_rate": 22,
          "discount": 0
        },
        {
          "description": "Biglietti da visita (500 pz)",
          "quantity": 1,
          "unit_price": 150,
          "vat_rate": 22,
          "discount": 10
        }
      ],
      "currency": "EUR",
      "totals": {
        "subtotal": 1335,
        "vat": 293.7,
        "cassa": 0,
        "total": 1628.7
      },
      "issue_date": "2026-09-15",
      "valid_until": "2026-10-15",
      "public_url": "https://app.mysigillo.com/q/Tk7wQ2…",
      "signed_at": "2026-09-17T10:20:00.000Z",
      "signer_name": "Marta Bianchi",
      "created_at": "2026-09-15T09:12:44.000Z",
      "updated_at": "2026-09-15T09:20:02.000Z",
      "created_by_name": "Alessio Bertolini"
    }
  }
}

Per payment.received, data.object è la rata (oggetto payment) e data.quote_id è il preventivo a cui appartiene:

payment.received
{
  "id": "evt_7Qm3Vx9Tc2",
  "type": "payment.received",
  "created": 1789726800,
  "workspace_id": "ws_Ab12Cd34",
  "data": {
    "object": {
      "id": "pay_1",
      "label": "Acconto 30%",
      "amount": 488.61,
      "due_date": "2026-09-20",
      "paid": true,
      "paid_at": "2026-09-18",
      "method": "stripe",
      "payment_url": "https://buy.stripe.com/…"
    },
    "quote_id": "qt_3Kf9Xw2Pa7"
  }
}

Gli eventi di prova hanno type: "ping": rispondi 2xx e ignorali. Servono solo a controllare che URL e verifica della firma funzionino.

HeaderContenuto
Sigillo-EventIl tipo di evento, uguale a type nel body.
Sigillo-Signaturet= momento dell'invio in secondi Unix, v1= HMAC SHA-256 in esadecimale di <t>.<body> calcolato con il segreto del webhook.

Verifica la firma

Prima di fidarti di un evento, ricalcola la firma sul body grezzo (non su un JSON riformattato), confrontala a tempo costante e scarta i timestamp più vecchi di 5 minuti.

Node.js · Express
import crypto from "node:crypto";
import express from "express";

const app = express();
const SECRET = process.env.SIGILLO_WEBHOOK_SECRET; // whsec_…

// Serve il body grezzo: la firma è calcolata sui byte esatti.
app.post("/webhook/sigillo", express.raw({ type: "application/json" }), (req, res) => {
  const header = req.get("Sigillo-Signature") || "";
  const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
  const t = Number(parts.t);
  const body = req.body.toString("utf8");

  const expected = crypto
    .createHmac("sha256", SECRET)
    .update(`${t}.${body}`)
    .digest("hex");

  const fresh = Math.abs(Date.now() / 1000 - t) < 300; // 5 minuti
  const valid =
    parts.v1?.length === expected.length &&
    crypto.timingSafeEqual(Buffer.from(parts.v1), Buffer.from(expected));

  if (!fresh || !valid) return res.status(400).send("firma non valida");

  const event = JSON.parse(body);
  // Rispondi subito, lavora dopo.
  res.sendStatus(200);

  if (event.type === "quote.signed") {
    console.log("Firmato:", event.data.object.number);
  }
});

app.listen(3000);
Python · Flask
import hashlib, hmac, json, os, time
from flask import Flask, request, abort

app = Flask(__name__)
SECRET = os.environ["SIGILLO_WEBHOOK_SECRET"].encode()  # whsec_…

@app.post("/webhook/sigillo")
def sigillo_webhook():
    header = request.headers.get("Sigillo-Signature", "")
    parts = dict(p.split("=", 1) for p in header.split(",") if "=" in p)
    body = request.get_data(as_text=True)  # body grezzo

    try:
        t = int(parts["t"])
    except (KeyError, ValueError):
        abort(400)

    expected = hmac.new(SECRET, f"{t}.{body}".encode(), hashlib.sha256).hexdigest()
    if abs(time.time() - t) > 300 or not hmac.compare_digest(expected, parts.get("v1", "")):
        abort(400)

    event = json.loads(body)
    if event["type"] == "payment.received":
        print("Pagamento:", event["data"]["object"]["amount"], "preventivo", event["data"]["quote_id"])
    return "", 200

Consegna e nuovi tentativi

  • Rispondi con uno status 2xx entro 10 secondi. Se hai lavoro lungo da fare, rispondi subito e fallo dopo.
  • Qualsiasi altra risposta, un timeout o un errore di rete contano come fallimento. Sigillo riprova dopo 1 minuto, 5 minuti, 30 minuti, 2 ore e 6 ore.
  • Dopo 20 consegne fallite di fila il webhook si disattiva da solo e in Impostazioni vedi il motivo. Sistemato il tuo server, lo riattivi con un click.
  • Gli eventi possono arrivare in ordine diverso da quello in cui sono successi: se ti serve lo stato aggiornato, rileggi l'oggetto con l'API.
Se ruoti il segreto, quello vecchio smette subito di valere: aggiorna la variabile sul tuo server appena lo copi.

Casi d’uso

Cosa ci puoi fare

Il form del tuo sito crea il preventivo

Il visitatore compila il form sul tuo sito, il tuo server chiama POST /quotes con i suoi dati e le righe del servizio scelto. Trovi la bozza in Sigillo, la controlli e la pubblichi. La chiave resta sul server, mai nella pagina.

Zapier e Make con i webhook

Crea uno Zap o uno scenario con il trigger “Webhook” (Catch Hook in Zapier, Custom webhook in Make), incolla l'URL in Sigillo e scegli gli eventi. Esempi: messaggio su Slack quando arriva quote.signed, riga su Google Sheets per ogni payment.received, contatto nella newsletter per ogni request.received.

Export mensile delle fatture

Il primo del mese uno script legge le fatture del mese prima con GET /invoices e scarica l'XML di ognuna, pronte per il gestionale o per il commercialista.

bash
FROM=2026-08-01; TO=2026-08-31
curl -s "https://app.mysigillo.com/api/v1/invoices?from=$FROM&to=$TO&limit=100" \
  -H "Authorization: Bearer $SIGILLO_API_KEY" \
  | jq -r '.data[].id' \
  | while read id; do
      curl -s "https://app.mysigillo.com/api/v1/invoices/$id/xml" \
        -H "Authorization: Bearer $SIGILLO_API_KEY" -o "$id.xml"
    done

Sincronizza il CRM

Tieni allineati i clienti tra Sigillo e il CRM con GET /clients, POST /clients e PATCH /clients/{id}, e aggiorna la trattativa quando arrivano quote.signed o quote.rejected.

Ti manca un endpoint o un evento? Scrivici a info@mysigillo.com.

Incluse in Premium

La prima chiamata in cinque minuti

Crea la chiave in Impostazioni, prova GET /me e sei pronto. Premium include anche fatture con XML per lo SDI, team fino a 3 persone e il portale per il commercialista.