Sviluppatori

API, webhook e MCP

Collegare Hakubase ad altri sistemi e agli assistenti AI, con le stesse regole di chi lo usa dall'interfaccia.

Hakubase ha tre modi per collegare i sistemi esterni: l’API REST v1, per leggere e scrivere da un ERP o da un’integrazione scritta da voi; i webhook, per sapere quando qualcosa cambia senza chiederlo di continuo; e il server MCP, per gli assistenti AI. API e MCP vedono gli stessi dati con gli stessi permessi: una risorsa aggiunta all’API compare anche nel server MCP, senza una riga in più.

Autenticazione

Le chiavi si creano in Impostazioni → Sviluppatori. Ogni chiave appartiene a un workspace, porta dei permessi e una portata, e va nell’intestazione:

GET /api/v1/companies HTTP/1.1
Host: <workspace>.hakubase.com
Authorization: Bearer hb_…

Una rotta chiede il permesso del modulo che governa la risorsa, non un generico permesso “di integrazione”: una chiave che legge le fatture non per questo vede i progetti.

La promessa di v1

Dentro una versione un campo si aggiunge, mai si toglie e mai cambia significato. Togliere o cambiare significa v2. Il vostro codice scritto oggi contro v1 funziona domani.

/api/v1 è un indirizzo diverso da /api, che serve l’interfaccia e cambia insieme alle schermate: non usatela.

Le risorse

RisorsaLetturaScrittura
/companiesregistry.readregistry.write — crea, aggiorna
/peopleregistry.readregistry.write — crea, aggiorna
/leadsleads.readleads.write — crea
/dealsdeals.read—
/offersoffers.read—
/contractscontracts.read—
/projectsprojects.read—
/ticketstickets.read—
/invoicesbilling.read—
/credit_notesbilling.read—
/expensesbilling.read—
/catalog_itemscatalog.read—
/price_listscatalog.read—

Su /projects il budget (budget_amount) arriva solo a una chiave che ha anche projects.economics; senza, il campo è null.

La reference completa si trova nell’app. In Impostazioni → Sviluppatori → API REST trovate lo schema OpenAPI generato dalle rotte, con la prova delle chiamate contro il vostro workspace. È sempre allineato alla versione in produzione: Hakubase è un servizio, non c’è una versione vecchia da documentare.

Webhook

Un webhook è un evento che esce: quando in Hakubase succede qualcosa, il vostro indirizzo riceve una chiamata. Le iscrizioni si creano in Impostazioni → Sviluppatori → Webhook, con un nome, l’indirizzo (solo https) e gli eventi che volete ricevere.

Gli eventi sono quelli che il prodotto emette, area per area: lead.created, deal.stage_changed, invoice.issued, ticket.closed, project.delivered e gli altri. Sono di più di quelli su cui scattano le automazioni, perché un’integrazione vuole sapere anche quello che nessuna regola guarda. L’elenco completo è nella schermata dell’iscrizione.

Un webhook non ha una portata. Manda gli eventi di tutto il workspace, chiunque li abbia causati: non filtra per i permessi di chi l’ha creato. La schermata lo dice.

La consegna

Ogni evento arriva come una POST in JSON:

POST /hooks/hakubase HTTP/1.1
Host: example.com
Content-Type: application/json
User-Agent: Hakubase-Webhooks/1
X-Hakubase-Event: invoice.issued
X-Hakubase-Delivery: 01a1599c-5e2b-7c41-9d3a-6b0f2e8c7a14
X-Hakubase-Timestamp: 1791561612
X-Hakubase-Signature: sha256=9f2c41d7…

{
  "id": "01a1599c-5d90-7e02-8b61-3c7a9f04d2e8",
  "type": "invoice.issued",
  "occurred_at": "2026-10-09T15:40:12+00:00",
  "subject": { "type": "invoice", "id": "01a1599c-5d1f-…" },
  "data": {
    "public_number": "FT-2026-041",
    "total": "30256.00",
    "customer": "Fornace Nord S.r.l."
  }
}
CampoCosa contiene
idL’identificativo dell’evento.
typeIl tipo, lo stesso di X-Hakubase-Event.
occurred_atQuando è successo, in UTC.
subjectIl record di cui parla l’evento: il tipo e l’identificativo, da leggere con l’API se vi serve tutto.
dataQuello che l’evento porta con sé, diverso per ogni tipo.

Verificare la firma

Alla creazione dell’iscrizione nasce un segreto whsec_…, mostrato una volta sola. Ogni consegna è firmata con quello: X-Hakubase-Signature è sha256= seguito dall’HMAC-SHA256, in esadecimale, di {X-Hakubase-Timestamp}.{corpo}. La chiave è il segreto intero, prefisso whsec_ compreso, e il corpo è quello grezzo, prima di qualunque parsing.

Il momento entra nella firma, così una consegna registrata oggi non si può riusare domani: controllate anche che il timestamp sia recente.

import crypto from 'node:crypto';

function verify(rawBody, headers, secret) {
  const ts = headers['x-hakubase-timestamp'];
  const expected = 'sha256=' + crypto
    .createHmac('sha256', secret)
    .update(`${ts}.`)
    .update(rawBody)
    .digest('hex');
  const got = headers['x-hakubase-signature'] ?? '';
  const same = got.length === expected.length &&
    crypto.timingSafeEqual(Buffer.from(got), Buffer.from(expected));
  const fresh = Math.abs(Date.now() / 1000 - Number(ts)) < 300;
  return same && fresh;
}
import hashlib, hmac, time

def verify(raw_body: bytes, headers, secret: str) -> bool:
    ts = headers["X-Hakubase-Timestamp"]
    expected = "sha256=" + hmac.new(
        secret.encode(), f"{ts}.".encode() + raw_body, hashlib.sha256
    ).hexdigest()
    fresh = abs(time.time() - int(ts)) < 300
    return fresh and hmac.compare_digest(expected, headers["X-Hakubase-Signature"])

Ruotare il segreto non fa perdere consegne: per 24 ore il vecchio resta valido, e ogni consegna porta anche X-Hakubase-Signature-Previous, firmata con quello. Avete un giorno per cambiare il segreto dalla vostra parte.

Rispondere, e i nuovi tentativi

Rispondete con un codice 2xx entro 10 secondi: qualunque altra risposta, o il silenzio, vale come consegna non riuscita.

Una consegna non riuscita si riprova dopo 1, 5, 15, 60, 180, 360, 720, 1440 e 1440 minuti — circa settanta ore in tutto — con un piccolo scarto a caso, perché le consegne accumulate mentre il vostro indirizzo era giù non tornino tutte nello stesso istante. Finiti i tentativi, la consegna resta tra quelle non riuscite e si riprova a mano.

X-Hakubase-Delivery non cambia fra un tentativo e l’altro: è così che riconoscete un doppione e lo scartate. Fate in modo che ricevere due volte la stessa consegna non faccia danni.

Un’iscrizione che non riesce a consegnare niente per sette giorni si sospende da sola, e lo scrive nello storico. Si riattiva dalla sua scheda, e da quel momento riceve gli eventi nuovi: quelli di mentre era sospesa non tornano.

Provare

Dalla scheda dell’iscrizione, Invia un evento di prova manda una consegna vera, firmata con il segreto vero, del primo tipo di evento a cui siete iscritti. Il corpo, però, è d’esempio: {"test": true, "by": "…"}. Ogni tentativo — quando, che risposta, quanto ci ha messo, il prossimo — si legge nella scheda Esecuzioni accanto.

Server MCP

POST https://<workspace>.hakubase.com/api/mcp

Per ogni risorsa ci sono gli strumenti hakubase_list_… e hakubase_get_…, e dove la risorsa si scrive anche hakubase_create_… e hakubase_update_…: trentuno in tutto, generati dalle stesse definizioni dell’API.

Il permesso apre lo strumento, e senza non si vede: un assistente non riceve nemmeno l’elenco degli strumenti che poi gli verrebbero rifiutati.

Collegarsi

Con OAuth — la strada giusta per una persona. Il client MCP si collega da solo: scopre il server di autorizzazione, si registra, apre il consenso nel browser e riceve il suo token. Nessun segreto da copiare, e l’app collegata compare nel profilo della persona, da dove si stacca in un clic.

  • Due scope, read e write. Con read gli strumenti che scrivono spariscono, anche per chi avrebbe il permesso.
  • Il token porta il ruolo, non i permessi: un permesso tolto in Hakubase sparisce subito anche per l’assistente.
  • Il token vale un’ora; il rinnovo trenta giorni, e cambia a ogni uso.

Con la chiave, per un client che non sa fare OAuth: la stessa Authorization: Bearer hb_… dell’API.