Vai al contenuto
All articles
Setup

Riferimento per sviluppatori: API REST e MCP

Il riferimento completo dell'API Sellio: autenticazione con API key, scoperta dei campi, endpoint REST, formato degli errori, rate limit e il server MCP per agenti IA.

Integra Sellio via HTTP o collega il tuo agente IA tramite MCP. In entrambi i casi, è la stessa chiave, lo stesso ambito di tenant e lo stesso rate limit. Scopri i campi di qualsiasi oggetto e inizia a leggere e scrivere record in pochi minuti.

💡 È disponibile anche un portale sviluppatori pubblico su www.selliocrm.com/developers con questo stesso riferimento, i webhook in uscita, la specifica OpenAPI da scaricare e una collection Postman.

Autenticazione

Ogni richiesta contiene una API key nell'header Authorization: Bearer. Quella chiave identifica il tenant proprietario, quindi tutto viene automaticamente delimitato ad esso. Non esporre mai la chiave nel browser; usala solo lato server. Le chiavi si generano e revocano in Impostazioni → API e sviluppatori.

curl -H "Authorization: Bearer sk_live_..." \
  https://www.selliocrm.com/api/v1/objects

Ambiti della chiave

Quando generi una chiave in Impostazioni → API e sviluppatori scegli il suo ambito. Concedi a ogni integrazione solo l'accesso di cui ha bisogno. I limiti si applicano allo stesso modo in REST e MCP, perché entrambe le superfici usano la stessa chiave e lo stesso controllo.

  • Solo lettura: la chiave legge i dati ma non può creare, modificare o eliminare. Blocca POST, PATCH e DELETE in REST e gli strumenti create_record, update_record e delete_record in MCP. I tentativi di scrittura o eliminazione ricevono 403 con { "error": "errors.apiKeyReadOnly" }.
  • Limitata agli oggetti: scegli gli oggetti a cui la chiave può accedere. Qualsiasi oggetto fuori dall'elenco restituisce 403 con { "error": "errors.apiKeyObjectDenied" }. L'elenco degli oggetti (GET /api/v1/objects e lo strumento list_objects) arriva già filtrato in base all'ambito, e le attività (/api/v1/activities) contano come l'oggetto activity: la chiave le raggiunge solo se activity è nell'ambito.
  • Consenti eliminazione: per impostazione predefinita una chiave non elimina MAI, anche con la scrittura abilitata. Quando generi la chiave puoi attivare l'eliminazione per abilitare DELETE /api/v1/{object}/{id} e lo strumento MCP delete_record. Senza questo ambito, l'eliminazione restituisce 403 con { "error": "errors.apiKeyDeleteDenied" }. L'eliminazione è soft: i record vanno nel cestino e possono essere ripristinati.

Una chiave senza ambito impostato (predefinito) ha accesso completo in lettura e scrittura a tutti gli oggetti, come prima. Le chiavi create prima di questa modifica mantengono l'accesso completo finché non generi una nuova chiave con ambito definito.

OAuth e app collegate

Quando un sistema DI TERZE PARTI deve integrarsi per conto dell'utente (senza che il cliente incolli una chiave admin), usa il flusso OAuth 2.0 Authorization Code con PKCE. L'utente vede una schermata di consenso con gli ambiti richiesti, approva, e l'app riceve un token di accesso che può fare solo ciò a cui è stato acconsentito. Le app sono curate: lo sviluppatore registra e pubblica l'app per ottenere un client_id e un client_secret.

  • Reindirizza l'utente a GET /api/oauth/authorize con client_id, redirect_uri (corrispondenza esatta con la lista consentita dell'app), scope, state e PKCE (code_challenge con code_challenge_method=S256). PKCE è obbligatorio.
  • L'utente autenticato approva nella schermata di consenso e il CRM reindirizza con code e lo stesso state.
  • Sul tuo server, scambia il code presso POST /api/oauth/token (grant_type=authorization_code, con code_verifier, client_id, client_secret e redirect_uri) per un token di accesso (Bearer, circa 1 ora) e un refresh token.
  • Chiama l'API v1 e il server MCP con Authorization: Bearer at_..., delimitato al consenso. Rinnova con grant_type=refresh_token; il refresh viene ruotato (quello vecchio muore all'uso) e il riutilizzo revoca l'intera famiglia. Revoca presso POST /api/oauth/revoke.
# 1) Consenso (l'utente approva → redirect_uri?code=...&state=...)
GET https://www.selliocrm.com/api/oauth/authorize?response_type=code&client_id=app_...&redirect_uri=https://your-app/callback&scope=records:read%20activities:read&state=abc&code_challenge=...&code_challenge_method=S256

# 2) Scambia il code per i token (lato server)
curl -X POST https://www.selliocrm.com/api/oauth/token \
  -d grant_type=authorization_code -d code=<authcode> -d code_verifier=<verifier> \
  -d client_id=app_... -d client_secret=secret_... -d redirect_uri=https://your-app/callback

# → { "access_token": "at_...", "token_type": "Bearer", "expires_in": 3600,
#     "refresh_token": "rt_...", "scope": "records:read activities:read" }

Ambiti OAuth: records:read e records:write (tutti gli oggetti); records:read:contact e records:write:opportunity (per oggetto); activities:read e activities:write; objects:read (scoperta). Corrispondono agli stessi controlli di lettura, scrittura e per-oggetto delle chiavi.

Widget incorporati (iframe)

La tua app può incorporare la propria schermata (un widget) nel dettaglio di un record o nella dashboard. Il widget viene eseguito in un iframe sandboxed, servito dalla tua origine sulla lista consentita dell'app, e richiede l'ambito widgets:embed. L'amministratore del tenant sceglie dove appare ciascun widget in App → Installate.

L'host invia al widget solo il contesto UI tramite postMessage (sellio:widget:context, versione 1): recordId, objectApiName, locale, theme e installId. Nessun dato di business, token o segreto viaggia in quel messaggio. Per leggere o scrivere dati, il widget usa l'API OAuth con il proprio token (gli ambiti concessi all'installazione). Il widget può rispondere solo con sellio:widget:ready (per ricevere di nuovo il contesto) e sellio:widget:resize con { height } (per adattare la propria altezza, con un limite massimo); qualsiasi altro messaggio viene ignorato.

Sicurezza: l'iframe è sandboxed e cross-origin, quindi il widget non può raggiungere il DOM o i cookie dell'host. L'host convalida l'origine esatta a ogni postMessage e l'embedUrl viene sempre verificato rispetto alla lista consentita dell'app. Nel tuo widget, accetta messaggi solo quando event.origin è l'origine dell'host.

window.addEventListener('message', (event) => {
  if (event.origin !== 'https://www.selliocrm.com') return; // solo host
  const msg = event.data;
  if (!msg || msg.version !== 1) return;
  if (msg.type === 'sellio:widget:context') {
    const { recordId, objectApiName, locale, theme } = msg.payload;
    // dati: usa l'API OAuth con IL TUO token (non arriva mai via postMessage)
  }
});
parent.postMessage({ type: 'sellio:widget:ready', version: 1 }, 'https://www.selliocrm.com');

Scoperta dei campi

Prima di creare o aggiornare un record, scopri i campi dell'oggetto: cosa esiste, cosa è obbligatorio e quali valori accetta una select. Nessuna supposizione, e non serve ispezionare un record esistente.

In REST, ottieni l'oggetto e i suoi campi, con required, options (per select) e targetObject (per lookup):

GET https://www.selliocrm.com/api/v1/objects/contact

# → {
#   "apiName": "contact",
#   "label": "Contact",
#   "fields": [
#     { "apiName": "name",  "label": "Name",   "type": "text",  "required": true },
#     { "apiName": "email", "label": "Email",  "type": "email", "required": false },
#     { "apiName": "source", "label": "Source", "type": "select", "required": true,
#       "options": [ { "value": "site", "label": "Website" },
#                    { "value": "referral", "label": "Referral" } ] },
#     { "apiName": "company", "label": "Company", "type": "lookup",
#       "required": false, "targetObject": "company" }
#   ]
# }

In MCP, lo strumento describe_object restituisce gli stessi campi all'agente:

{ "method": "tools/call",
  "params": { "name": "describe_object", "arguments": { "object": "contact" } } }

API REST v1

Record di qualsiasi oggetto, inviando e ricevendo JSON. {object} è l'apiName (per esempio contact, lead, opportunity) e {id} è l'uuid del record.

  • GET /api/v1/objects: elenca gli oggetti del tenant.
  • GET /api/v1/objects/{object}: campi dell'oggetto (scoperta).
  • GET /api/v1/{object}: elenca e cerca record.
  • GET /api/v1/{object}/{id}: un record.
  • POST /api/v1/{object}: crea un record.
  • POST /api/v1/{object}/bulk: crea in blocco (fino a 500; successo parziale per elemento).
  • PATCH /api/v1/{object}/{id}: aggiorna i campi (parziale).
  • PATCH /api/v1/{object}/bulk: aggiorna in blocco ({ updates: [{ id, ...fields }] }).
  • DELETE /api/v1/{object}/{id}: elimina (soft, va nel cestino; richiede l'ambito delete sulla chiave).

Parametri di elenco (GET): limit (da 1 a 500, predefinito 50), offset (offset di paginazione, predefinito 0; il totale senza paginazione è nel campo total), search (ricerca per nome, senza distinzione tra maiuscole/minuscole e accenti), order (campo con :asc o :desc per ordinare) e filter. Filtri avanzati: ripeti filter=field:operator:value per combinare più condizioni con AND logico (non esiste OR; fino a 12 per chiamata). Operatori: eq, neq, contains, gt, lt, gte, lte, empty, not_empty (empty e not_empty non richiedono un valore). La forma vecchia filter=field:value (senza operatore) continua a significare uguaglianza esatta.

# Elenco (limit, offset, search, filter, order)
curl -H "Authorization: Bearer sk_live_..." \
  "https://www.selliocrm.com/api/v1/opportunity?limit=20&order=updated_at:desc&filter=stage:won"

# Filtri avanzati (AND logico: amount >= 1000 AND stage = won)
curl -H "Authorization: Bearer sk_live_..." \
  "https://www.selliocrm.com/api/v1/opportunity?filter=amount:gte:1000&filter=stage:eq:won"

# Un record
curl -H "Authorization: Bearer sk_live_..." \
  https://www.selliocrm.com/api/v1/contact/8f3c...

# Crea
curl -X POST -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"name":"Ana Souza","email":"ana@acme.com","source":"site"}' \
  https://www.selliocrm.com/api/v1/contact

# Creazione in blocco (successo parziale per elemento)
curl -X POST -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"records":[{"name":"Ana"},{"name":"Bruno"}]}' \
  https://www.selliocrm.com/api/v1/contact/bulk
# → { "results": [ { "index": 0, "ok": true, "id": "..." } ], "created": 1, "failed": 0 }

# Aggiorna (parziale)
curl -X PATCH -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"source":"referral"}' \
  https://www.selliocrm.com/api/v1/contact/8f3c...

# Elimina (soft, va nel cestino; richiede l'ambito delete sulla chiave)
curl -X DELETE -H "Authorization: Bearer sk_live_..." \
  https://www.selliocrm.com/api/v1/contact/8f3c...

Formato degli errori

Gli errori restituiscono JSON nella forma { "error": "message" } con lo status HTTP corrispondente:

{ "error": "required field: source" }   # HTTP 400
  • 200 e 201: successo (201 alla creazione).
  • 400: validazione o regola di business.
  • 401: chiave mancante o non valida.
  • 403: nessun permesso (RBAC) per l'oggetto, oppure bloccato dall'ambito della chiave (solo lettura, oggetto fuori ambito, o eliminazione non abilitata).
  • 404: oggetto o record non trovato (include DELETE/PATCH di un id inesistente).
  • 429: rate limit superato (vedi l'header Retry-After).

Server MCP (agenti IA)

Sellio espone un server MCP (Model Context Protocol) nativo affinché il tuo agente IA possa leggere e scrivere nel CRM in modo sicuro. È la stessa API key, lo stesso rate limit, le stesse validazioni e lo stesso RBAC. L'URL del server è https://www.selliocrm.com/api/mcp.

  • list_objects: elenca gli oggetti del tenant.
  • describe_object: i campi di un oggetto (obbligatori, tipi, opzioni).
  • list_records: elenca e cerca record.
  • get_record: un record per id.
  • create_record: crea un record.
  • update_record: aggiorna i campi.
  • delete_record: elimina (soft, va nel cestino); richiede l'ambito delete sulla chiave.

I client che supportano MCP remoto via HTTP usano l'URL con l'header Authorization: Bearer. Sui client senza HTTP remoto nativo, usa il bridge mcp-remote:

{
  "mcpServers": {
    "sellio-crm": {
      "command": "npx",
      "args": [
        "-y", "mcp-remote",
        "https://www.selliocrm.com/api/mcp",
        "--header", "Authorization: Bearer sk_live_..."
      ]
    }
  }
}

Rate limit

Ogni chiave ha un limite al minuto (predefinito 120, configurabile). Le risposte includono gli header X-RateLimit-Limit, X-RateLimit-Remaining e X-RateLimit-Reset. In caso di superamento, l'API restituisce 429 con Retry-After.

Modello a oggetti

Ogni tenant ha oggetti standard (Contatto, Azienda, Lead, Opportunità e altri) e oggetti personalizzati no-code. Scoprili tutti con GET /api/v1/objects e i campi di ciascuno con GET /api/v1/objects/{object} o con describe_object. Lo schema è sempre quello del tuo tenant.

💡 Genera la tua chiave in Impostazioni → API e sviluppatori e fai la tua prima chiamata in pochi minuti. L'eliminazione dei record è disponibile tramite l'API REST e MCP, ma è un'eliminazione soft (va nel cestino, reversibile) e funziona solo con chiavi che hanno l'ambito delete abilitato, disattivato per impostazione predefinita.

Open this article inside the system

Read it and want to see it working?

The account is free and the whole manual is available inside the system, with an assistant that answers from this very content.

Crea un account gratuito
Riferimento per sviluppatori: API REST e MCP · Sellio