Guida per sviluppatori · REST e MCP
Sincronizza la tua base di conoscenza
Continua a scrivere nel tuo sistema attuale e invia le modifiche a Sonny. Questa guida crea una categoria Fatturazione, sincronizza un articolo come bozza e poi lo pubblica per un pubblico di clienti verificati.
1. Scegli un canale e crea una chiave
- Apri Canali → il tuo canale. Copia l'ID dopo /app/sources/ nell'URL della dashboard. L'API chiama questo ID del canale sourceId; è diverso dal siteId del widget e dallo slug pubblico del centro assistenza.
- In Impostazioni → Sviluppatori → Chiavi API → Crea chiave, concedi kb:read e kb:write. Limita Accesso ai canali al canale che intendi sincronizzare. Salva la chiave, mostrata una sola volta, nel gestore dei segreti del tuo server.
- Imposta le variabili qui sotto nell'ambiente del tuo backend. Questi esempi usano curl; sostituisci gli ID in maiuscolo con i valori restituiti da Sonny. Eseguili su un canale di prova prima di sincronizzare un centro assistenza pubblicato.
# Load SONNY_API_KEY from your server's secret manager first.
# SOURCE_ID is the ID in the channel dashboard URL: /app/sources/SOURCE_ID
export SOURCE_ID="YOUR_SOURCE_ID"
export BASE="https://www.usesonny.com/api/v1/sources/$SOURCE_ID"Rilevamento facoltativo: GET /api/v1/sources e lo strumento MCP list_sources restituiscono i canali accessibili e richiedono conversations:read. Non ti serve questo ambito se hai già l'ID del canale. Il collegamento del dominio resta un'operazione da dashboard.
Configurazione completa della chiave API2. Crea o aggiorna la categoria
Usa nell'URL un ID stabile del tuo sistema di origine. Inviare di nuovo lo stesso ID esterno aggiorna la categoria esistente invece di crearne un duplicato. La prima creazione inizializza automaticamente il centro assistenza di questo canale.
curl --fail-with-body -X PUT "$BASE/categories/by-external-id/billing" \
-H "Authorization: Bearer $SONNY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"Billing","position":0}'Aspettati 201 alla creazione o 200 all'aggiornamento, con la categoria in data. Salva data.id quando ti serve l'ID interno della categoria in Sonny. Codifica gli ID esterni per l'URL e mantienili stabili anche quando cambiano i titoli.
3. Sincronizza un articolo come bozza
curl --fail-with-body -X PUT "$BASE/articles/by-external-id/billing-guide" \
-H "Authorization: Bearer $SONNY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"title":"Manage billing","body":"## Find your invoices\n\nOpen **Settings → Billing** in your account.","bodyFormat":"markdown","categoryExternalId":"billing","status":"draft"}'La risposta contiene data.id e l'HTML ripulito in data.body. Apri l'articolo in Canali → il tuo canale → Centro assistenza per controllarne la formattazione. Il Markdown viene convertito in HTML; è accettato anche HTML grezzo con bodyFormat: "html" (il valore predefinito). Il titolo dell'articolo è separato dai titoli nel corpo.
Usa categoryExternalId per fare riferimento alla categoria del passaggio 2, oppure categoryId per il suo ID Sonny. Indicane solo uno. Imposta uno dei due su null per togliere la categoria a un articolo. Ogni upsert richiede title e body; PATCH è disponibile per modifiche parziali. I nuovi articoli sono bozze per impostazione predefinita quando status è omesso.
4. Imposta l'accesso, poi pubblica
Per questo esempio di centro privato, collega prima il sistema di accesso dei clienti verificati. Crea il pubblico e salva il data.id restituito:
curl --fail-with-body -X POST "$BASE/audiences" \
-H "Authorization: Bearer $SONNY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"Pro customers","rules":{"match":"all","conditions":[{"trait":"plan","op":"in","value":["pro","business"]}]}}'Sostituisci AUDIENCE_ID, ARTICLE_ID e l'URL di login qui sotto. La prima richiesta rende il centro assistenza Pubblicato e lo riserva ai clienti Pro. La seconda pubblica l'articolo. Il flusso di login della tua app deve scambiare un JWT firmato del cliente con il centro assistenza; impostare solo signInUrl non fa accedere nessuno.
curl --fail-with-body -X PATCH "$BASE/help-center" \
-H "Authorization: Bearer $SONNY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"enabled":true,"title":"Acme Help Center","audience":"verified","audienceId":"AUDIENCE_ID","signInUrl":"https://app.example.com/login"}'
# Replace ARTICLE_ID and AUDIENCE_ID with the returned data.id values.
curl --fail-with-body -X PATCH "$BASE/articles/ARTICLE_ID" \
-H "Authorization: Bearer $SONNY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"audienceId":"AUDIENCE_ID","status":"published"}'Usa l'URL restituito da GET /help-center per provare la vista del lettore con accesso e un browser senza accesso. Le chiavi API e MCP agiscono come staff e possono leggere i contenuti entro i loro ambiti; una loro risposta positiva non dimostra che un cliente possa vedere l'articolo.
Per un centro pubblico, usa audience: "everyone" e audienceId: null sul centro e sull'articolo, e controlla anche l'accesso della categoria. Per rimuovere solo un gruppo con nome, invia audienceId: null; l'accesso riservato ai verificati resta a meno che tu non cambi esplicitamente audience. Un audienceId omesso mantiene l'assegnazione precedente. Tutte le restrizioni di centro assistenza, categoria e articolo devono essere soddisfatte.
Le regole con nome usano match: "all" o "any", fino a 10 condizioni e valori con tipo rigoroso. Operatori: eq, neq, in, not_in, exists, not_exists, gt, gte, lt, lte. I confronti numerici accettano numeri; in/not_in accettano array da 1 a 100 valori scalari; exists/not_exists omettono value. Gli attributi mancanti non soddisfano i confronti. Vedi comportamento delle regole, ereditarietà e risoluzione dei problemi di accesso.
5. Mantieni aggiornata la sincronizzazione
Ripeti le scritture senza duplicare i contenuti
Ripeti PUT con lo stesso ID esterno ogni volta che la tua fonte cambia. Gli ID esterni sono univoci all'interno di un centro assistenza. I campi omessi in un aggiornamento mantengono i valori attuali. Ometti status negli upsert successivi per conservare la pubblicazione; inviare esplicitamente draft ritira un articolo pubblicato. publishedAt viene impostato alla prima pubblicazione e non cambia più. È di sola lettura, quindi non si possono importare date di pubblicazione storiche. I contenuti invariati e le modifiche ai soli metadati non attivano nuovi embedding inutili.
Leggi modifiche e statistiche
curl --fail-with-body --get "$BASE/articles" \
-H "Authorization: Bearer $SONNY_API_KEY" \
--data-urlencode "page=1" --data-urlencode "limit=100" \
--data-urlencode "status=published" \
--data-urlencode "updatedSince=2026-09-01T00:00:00Z"
# Get the full sanitized HTML and read-only analytics for one article.
curl --fail-with-body "$BASE/articles/ARTICLE_ID" \
-H "Authorization: Bearer $SONNY_API_KEY"Gli elenchi di articoli e categorie restituiscono data più pagination: page, limit, total. Le pagine partono da 1; limit vale 50 per impostazione predefinita e accetta fino a 100. Mantieni gli stessi filtri e richiedi pagine finché page × limit non raggiunge total. Entrambi gli elenchi accettano externalId e updatedSince; gli articoli accettano anche categoryId e status (draft o published). Usa per updatedSince un timestamp ISO con fuso orario; include i record aggiornati in quell'istante.
Leggi il dettaglio di ogni articolo per ottenere il body completo, viewCount, helpfulYes e helpfulNo. Queste statistiche sono di sola lettura. updatedSince elenca i record attuali; non segnala le eliminazioni. Tieni traccia delle rimozioni nel tuo sistema di origine ed elimina esplicitamente il record Sonny corrispondente quando serve.
Carica un'immagine
curl --fail-with-body -X POST "$BASE/media" \
-H "Authorization: Bearer $SONNY_API_KEY" \
-F "file=@billing.png;type=image/png"Usa il data.url restituito nella sintassi Markdown per le immagini o in un elemento HTML img, poi sincronizza il body dell'articolo. I caricamenti accettano JPEG, PNG, GIF e WebP fino a 25 MB e richiedono un centro assistenza inizializzato. Gli URL caricati sono pubblici; la restrizione di pubblico di un articolo non protegge l'URL dell'immagine. MCP usa upload_kb_media con sourceId, fileName, contentType e dataBase64 del file, invece di un form multipart.
Ordina articoli e categorie
curl --fail-with-body -X PUT "$BASE/articles/reorder" \
-H "Authorization: Bearer $SONNY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"ids":["ARTICLE_ID_1","ARTICLE_ID_2"]}'Per prima cosa recupera tutte le pagine senza filtri di stato, categoria o data, comprese le bozze. Sostituisci gli ID di esempio con ogni ID di articolo attuale, esattamente una volta, nell'ordine desiderato. Usa /categories/reorder per l'elenco completo delle categorie. Un riordino riuscito restituisce 204 senza corpo. Se l'elenco è cambiato o contiene ID estranei, duplicati o mancanti, aggiornalo prima di riprovare. Puoi anche impostare un position non negativo nelle singole scritture.
Usa lo stesso flusso tramite MCP
- Collega il tuo client MCP e scegli lo spazio di lavoro corretto. Verifica che abbia kb:read e kb:write, con accesso al tuo canale.
- Usa l'ID del canale della dashboard, oppure chiama list_sources se la tua credenziale ha anche conversations:read. Non usare mai al suo posto il siteId del widget.
- Esegui in ordine i primi cinque esempi qui sotto. Sostituisci SOURCE_ID con l'ID del tuo canale e ARTICLE_ID/AUDIENCE_ID con il data.id di ciascun risultato precedente. Sostituisci l'URL di login e collega l'accesso prima di pubblicare.
- Usa list_kb_articles per controllare le modifiche. Esegui un riordino solo dopo aver raccolto l'elenco completo non filtrato, comprese le bozze. Aggiorna i tuoi elenchi dopo le scritture riuscite.
Ogni esempio mostra il nome dello strumento e i suoi argomenti. I campi di upsert vanno direttamente negli argomenti; gli strumenti di aggiornamento mettono i campi modificati dentro updates. Sono input di chiamate agli strumenti, non richieste HTTP all'endpoint MCP.
1. upsert_kb_category
{
"name": "upsert_kb_category",
"arguments": {
"sourceId": "SOURCE_ID",
"externalId": "billing",
"name": "Billing",
"position": 0
}
}2. upsert_kb_article
{
"name": "upsert_kb_article",
"arguments": {
"sourceId": "SOURCE_ID",
"externalId": "billing-guide",
"title": "Manage billing",
"body": "## Find your invoices\n\nOpen **Settings → Billing** in your account.",
"bodyFormat": "markdown",
"categoryExternalId": "billing",
"status": "draft"
}
}3. create_kb_audience
{
"name": "create_kb_audience",
"arguments": {
"sourceId": "SOURCE_ID",
"name": "Pro customers",
"rules": {
"match": "all",
"conditions": [
{
"trait": "plan",
"op": "in",
"value": [
"pro",
"business"
]
}
]
}
}
}4. update_help_center
{
"name": "update_help_center",
"arguments": {
"sourceId": "SOURCE_ID",
"updates": {
"enabled": true,
"title": "Acme Help Center",
"audience": "verified",
"audienceId": "AUDIENCE_ID",
"signInUrl": "https://app.example.com/login"
}
}
}5. update_kb_article
{
"name": "update_kb_article",
"arguments": {
"sourceId": "SOURCE_ID",
"articleId": "ARTICLE_ID",
"updates": {
"audience": "verified",
"audienceId": "AUDIENCE_ID",
"status": "published"
}
}
}6. list_kb_articles
{
"name": "list_kb_articles",
"arguments": {
"sourceId": "SOURCE_ID",
"page": 1,
"limit": 100,
"updatedSince": "2026-09-01T00:00:00Z"
}
}7. reorder_kb_articles
{
"name": "reorder_kb_articles",
"arguments": {
"sourceId": "SOURCE_ID",
"ids": [
"ARTICLE_ID_1",
"ARTICLE_ID_2"
]
}
}8. update_kb_audience
{
"name": "update_kb_audience",
"arguments": {
"sourceId": "SOURCE_ID",
"audienceId": "AUDIENCE_ID",
"updates": {
"name": "Paid customers"
}
}
}Operazioni correlate
I percorsi REST qui sotto sono relativi a BASE. Consulta il riferimento API per ogni campo e schema di risposta.
| Attività | REST | MCP |
|---|---|---|
| Elenca / ottieni articoli | GET /articles · GET /articles/{articleId} | list_kb_articles · get_kb_article |
| Elenca / ottieni categorie | GET /categories · GET /categories/{categoryId} | list_kb_categories · get_kb_category |
| Crea senza ID esterno | POST /articles · POST /categories | create_kb_article · create_kb_category |
| Modifica contenuti esistenti | PATCH /articles/{articleId} · PATCH /categories/{categoryId} | update_kb_article · update_kb_category |
| Ordina le categorie | PUT /categories/reorder | reorder_kb_categories |
| Leggi / modifica le impostazioni del centro assistenza | GET /help-center · PATCH /help-center | get_help_center · update_help_center |
| Elenca / modifica i pubblici | GET /audiences · PATCH /audiences/{audienceId} | list_kb_audiences · update_kb_audience |
| Elimina | DELETE /articles/{articleId} · /categories/{categoryId} · /audiences/{audienceId} | delete_kb_article · delete_kb_category · delete_kb_audience |
L'eliminazione di un articolo è definitiva. Eliminare una categoria toglie la categoria ai suoi articoli e rimuove la restrizione ereditata da quella categoria. Eliminare un pubblico rimuove le sue regole sugli attributi, lasciando i contenuti collegati riservati ai clienti verificati. Controlla l'accesso interessato prima di eliminare; usa le bozze per ritirare gli articoli che vuoi conservare.
Risolvere i problemi di sincronizzazione
- 400 · Richiesta non valida
- Controlla title/body o name obbligatori, i nomi esatti dei campi, i tipi delle regole validi e gli ID completi per il riordino. Invia categoryId o categoryExternalId, non entrambi.
- 401 · Non autorizzato
- Fornisci una chiave Bearer valida. Controlla se è scaduta o è stata revocata.
- 403 · Accesso negato
- Controlla gli ambiti della chiave, i permessi del proprietario della chiave e la fatturazione dello spazio di lavoro. Ricollega un client MCP con l'accesso necessario se i suoi strumenti sono di sola lettura.
- 404 · Non trovato
- Verifica che la sorgente appartenga allo spazio di lavoro selezionato e sia consentita dalla credenziale. Inizializza un nuovo centro assistenza creando prima dei contenuti; le letture non lo creano.
- 409 · Conflitto
- Recupera di nuovo i contenuti attuali e risolvi l'ID in conflitto o l'ordine non aggiornato prima di riprovare.
- 413 · Troppo grande
- Riduci l'immagine sotto il limite di 25 MB.
- 429 · Limite di richieste raggiunto
- Attendi il tempo indicato da Retry-After prima di riprovare. Usa RateLimit-Limit, RateLimit-Remaining e RateLimit-Reset per regolare il ritmo delle richieste.
Guide correlate
- Centro assistenza
Pubblica risposte, organizza le categorie, scegli chi può leggere e mantieni aggiornato il tuo centro assistenza.
- Pubblici del centro assistenza
Crea gruppi di clienti, rendi privato il tuo centro assistenza e verifica chi può leggere ogni risposta.
- API pubblicaBeta
Smista e sincronizza le conversazioni, condividi il contesto dei clienti, leggi i report e invia file con chiavi API con ambiti.
- Sonny MCPBeta
Collega gli assistenti AI ai flussi della posta in arrivo, alle memorie dei clienti, ai report e ai file con OAuth o chiavi con ambiti.