API Reference / Moduli custom

Moduli custom

Il registry dei moduli definisce la struttura: quali moduli esistono e quali campi hanno. Qui si crea un modulo e se ne modella lo schema; i record che ci vivono dentro si gestiscono con le API dei record generici.

Solo amministratori

Cambiare la struttura (creare moduli, aggiungere o eliminare campi, cambiare tipo) richiede il ruolo amministratore. La sola lettura della definizione è accessibile a ogni utente autenticato. Vedi anche le convenzioni per errori ed envelope. Ogni richiesta richiede l'header Authorization: Bearer <accessToken>.

01L'oggetto Modulo

La definizione completa di un modulo (quella restituita da GET /api/modules/:moduleKey e dalle mutazioni) è un oggetto con la riga module, l'elenco groups (le sezioni) e l'elenco fields (il catalogo campi).

AttributoTipoDescrizione
module.module_keystringChiave univoca (slug); usata negli URL /api/records/:moduleKey.
module.label_singularstringEtichetta al singolare (es. Ticket).
module.label_pluralstringEtichetta al plurale.
module.iconstring | nullIcona del modulo (opzionale).
module.descriptionstring | nullDescrizione libera.
module.is_custombooleantrue per i moduli personalizzati (i soli modificabili).
groupsarraySezioni del form: id, group_key, label, sort_order.
fieldsarray<Campo>Il catalogo campi: vedi lo schema Campo.
json · l'oggetto Modulo
{
  "module": {
    "module_key": "tickets",
    "label_singular": "Ticket",
    "label_plural": "Ticket",
    "icon": null,
    "description": null,
    "is_custom": true
  },
  "groups": [ { "id": 4, "group_key": "dettagli", "label": "Dettagli", "sort_order": 0 } ],
  "fields": [
    { "field_key": "titolo", "field_label": "Titolo", "data_type": "text", "is_required": true,  }
  ]
}

02Campo (field)

Ogni voce di fields descrive un campo del modulo. In creazione i campi si passano nella forma abbreviata (key, label, type, required, config); in lettura tornano con le colonne persistite (field_key, field_label, data_type…).

AttributoTipoDescrizione
field_keystringChiave del campo (slug); è la proprietà usata nel body dei record.
field_labelstringEtichetta mostrata nel form.
data_typestringTipo del campo: vedi Tipi di campo.
is_requiredbooleantrue se obbligatorio in creazione.
config.optionsstring[]Opzioni statiche: obbligatorio per select; opzioni iniziali per picklist.
config.targetstringModulo puntato, obbligatorio per lookup: core (accounts/contacts/leads) o un modulo custom attivo (anche il modulo stesso).
sort_orderintegerOrdine di visualizzazione.
group_idinteger | nullSezione a cui il campo appartiene.

03Endpoint

MetodoPathCosa fa
GET/api/modulesauthElenco dei moduli (base + custom).
GET/api/modules/:moduleKeyauthDefinizione completa di un modulo (campi, gruppi).
POST/api/modulesadminCrea un nuovo modulo custom.
PATCH/api/modules/:moduleKeyadminRinomina / aggiorna il modulo (etichette, icona, descrizione).
DELETE/api/modules/:moduleKeyadminElimina il modulo (con conferma della chiave).
POST/api/modules/:moduleKey/fieldsadminAggiunge un campo.
PATCH/api/modules/:moduleKey/fields/:fieldIdadminModifica un campo (etichetta, required, config).
POST/api/modules/:moduleKey/fields/:fieldId/typeadminCambia il tipo di un campo (con conversione dati).
PATCH/api/modules/:moduleKey/fields/:fieldId/placementadminSposta un campo in un gruppo e ne fissa l'ordine.
DELETE/api/modules/:moduleKey/fields/:fieldIdadminElimina un campo (?purge=true rimuove anche i dati).
POST/api/modules/:moduleKey/field-groupsadminCrea un gruppo di campi (sezione del form).
PATCH/api/modules/:moduleKey/field-groups/:groupIdadminRinomina / riordina un gruppo.
DELETE/api/modules/:moduleKey/field-groups/:groupIdadminElimina un gruppo.

04Elencare i moduli

GET /api/modules bearer richiesto

Restituisce i moduli base più i moduli custom leggibili dal ruolo (i moduli custom su cui non hai permesso di lettura vengono omessi).

Risposta · 200
json
{
  "success": true,
  "data": {
    "items": [
      { "module_key": "accounts", "label_plural": "Account", "is_custom": false },
      { "module_key": "tickets", "label_plural": "Ticket", "is_custom": true }
    ]
  }
}

05Definizione di un modulo

GET /api/modules/:moduleKey bearer richiesto
Parametri path
ParametroTipoDescrizione
moduleKeystringChiave del modulo (es. tickets).
Esiti
StatoCorpo
200{ success: true, data: { module, groups, fields } }: vedi L'oggetto Modulo.
403FORBIDDEN: modulo custom non leggibile dal tuo ruolo.
404NOT_FOUND: modulo inesistente.

06Creare un modulo

POST /api/modules admin

Definisci la chiave del modulo (usata poi negli URL /api/records/:moduleKey), le etichette singolare/plurale e i campi iniziali. La chiave viene normalizzata a slug e non può essere una riservata (accounts, contacts, deals…).

Parametri body
CampoTipoNote
moduleKeystringopzionaleChiave desiderata; se assente è derivata da labelPlural. Slug ^[a-z][a-z0-9_]{1,40}$.
labelSingularstringrichiestoEtichetta al singolare.
labelPluralstringrichiestoEtichetta al plurale.
iconstringopzionaleIcona del modulo.
descriptionstringopzionaleDescrizione libera.
groupsarrayopzionaleSezioni: [{ "label": "Dettagli" }], nell'ordine di visualizzazione.
fieldsarray<Campo>opzionaleCampi iniziali: vedi Campo. Ogni groupIndex punta a groups.
Richiesta
curl -X POST https://crm.tuodominio.it/api/modules \
  -H "Authorization: Bearer <accessToken>" \
  -H "Content-Type: application/json" \
  -d '{ "moduleKey": "tickets", "labelSingular": "Ticket", "labelPlural": "Ticket",
       "fields": [ { "key": "titolo", "label": "Titolo", "type": "text", "required": true } ] }'
const res = await fetch("https://crm.tuodominio.it/api/modules", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${accessToken}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    moduleKey: "tickets", labelSingular: "Ticket", labelPlural: "Ticket",
    fields: [{ key: "titolo", label: "Titolo", type: "text", required: true }],
  }),
});
const { data } = await res.json();
Risposta · 201
json
{ "success": true, "data": { "module": { "module_key": "tickets",  }, "groups": [], "fields": [  ] } }
Esiti
StatoCodiceQuando
201·Modulo creato; nel corpo la definizione completa.
422VALIDATION_ERROREtichette mancanti, chiave non valida o riservata, campo select senza opzioni, lookup con target non valido.
403FORBIDDENChiamante senza ruolo amministratore.

07Aggiungere un campo

POST /api/modules/:moduleKey/fields admin

Aggiunge un campo a un modulo custom esistente. Se il campo è required e il modulo ha già dei record, devi passare defaultValue per riempirli (backfill).

Parametri body
CampoTipoNote
labelstringrichiestoEtichetta; la field_key è lo slug derivato.
typestringopzionaleTipo del campo (default text). Vedi Tipi.
requiredbooleanopzionaleObbligatorietà (default false).
configobjectopzionaleoptions per select/picklist, target per lookup, prefix/padding/next per autonumber.
defaultValueanyopzionaleValore di backfill per i record esistenti quando required.
groupIdintegeropzionaleSezione in cui collocare il campo.
Richiesta
curl -X POST https://crm.tuodominio.it/api/modules/tickets/fields \
  -H "Authorization: Bearer <accessToken>" \
  -H "Content-Type: application/json" \
  -d '{ "label": "Priorità", "type": "select", "config": { "options": ["bassa","alta"] } }'
const res = await fetch("https://crm.tuodominio.it/api/modules/tickets/fields", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${accessToken}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ label: "Priorità", type: "select", config: { options: ["bassa", "alta"] } }),
});
const { data } = await res.json();
Risposta · 201
json
{ "success": true, "data": { "field": { "field_key": "priorita", "data_type": "select",  }, "definition": {  } } }
Esiti
StatoCodiceQuando
201·Campo aggiunto; nel corpo il campo e la definizione aggiornata.
422VALIDATION_ERROREtichetta mancante, tipo non supportato, chiave duplicata, modulo base (non personalizzato), o campo obbligatorio su record esistenti senza defaultValue.
403FORBIDDENChiamante senza ruolo amministratore.
404NOT_FOUNDModulo inesistente.

08Tipi di campo

Ogni campo ha un type tra i dieci tipi supportati:

TipoUso
text · textareaTesto breve / lungo.
numberValore numerico.
date · datetimeData / data e ora.
checkboxSì / No (booleano).
picklistElenco a scelta gestito (opzioni riusabili, vedi Picklist). Le opzioni iniziali si passano in config.options.
selectElenco a scelta con opzioni statiche in config.options (almeno una, obbligatoria).
lookupRiferimento a un record di un altro modulo. config.target: un modulo core (accounts, contacts, leads) oppure un modulo custom attivo: anche il modulo stesso (auto-riferimento, es. padre/figlio). Il valore è l'id del record collegato, validato all'inserimento.
autonumberProgressivo assegnato dal server alla creazione (mai richiesto in input, anche se il campo è obbligatorio). config: prefix (es. TICKET-), padding (zero-fill, max 12) e next (primo valore, default 1). I valori forniti da import restano invariati.

09Cambiare il tipo di un campo

POST /api/modules/:moduleKey/fields/:fieldId/type admin

Cambia il data_type di un campo esistente, convertendo i dati già presenti. La conversione avviene solo se tutti i valori sono rappresentabili nel nuovo tipo; altrimenti la richiesta è rifiutata e nessun dato viene toccato.

curl
curl -X POST https://crm.tuodominio.it/api/modules/tickets/fields/42/type \
  -H "Authorization: Bearer <accessToken>" \
  -H "Content-Type: application/json" \
  -d '{ "newType": "number" }'
Esiti
StatoCodiceQuando
200·Tipo cambiato; nel corpo la definizione aggiornata.
422VALIDATION_ERRORTipo non supportato, o alcuni record hanno valori non convertibili (nei details: conteggio ed esempi).
403FORBIDDENChiamante senza ruolo amministratore.

10Azzerare il contatore di un autonumber

POST /api/modules/:moduleKey/fields/:fieldId/reset-counter admin

Imposta il prossimo valore che il campo autonumber assegnerà (config.next). Body opzionale { "next": 100 } (default 1). L'operazione è tracciata nell'audit log (module_field_counter_reset).

Attenzione

Riportare il contatore indietro può produrre numeri duplicati rispetto ai record già esistenti: l'unicità del progressivo non è imposta dal database.

11Gruppi di campi

I campi possono essere organizzati in gruppi (le sezioni del form di dettaglio). I gruppi si creano, rinominano, riordinano ed eliminano con gli endpoint /field-groups; lo spostamento di un campo tra gruppi usa PATCH …/fields/:fieldId/placement.

curl · crea una sezione
curl -X POST https://crm.tuodominio.it/api/modules/tickets/field-groups \
  -H "Authorization: Bearer <accessToken>" \
  -H "Content-Type: application/json" \
  -d '{ "label": "Dettagli" }'
Attenzione

Eliminare un campo con ?purge=true, o eliminare un modulo, rimuove i dati associati in modo irreversibile: fai un backup se il modulo contiene record importanti (vedi Backup). L'eliminazione di un modulo richiede di ridigitarne la chiave come conferma.