> ## Documentation Index
> Fetch the complete documentation index at: https://docs.exoid.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Struttura del payload

> Riferimento completo del JSON inviato da Exoid: campi, modello dati TypeScript, tipi di risposta ed esempio.

Riferimento del corpo JSON che Exoid invia al tuo endpoint: campi, modello dati TypeScript e forma di ogni tipo di risposta. Ti serve mentre scrivi il parser.

## Campi di primo livello

<ResponseField name="form_id" type="string">
  Identificativo dell'intervista.
</ResponseField>

<ResponseField name="event_type" type="string">
  Tipo di evento. Per le risposte alle interviste vale sempre `form_response`.
</ResponseField>

<ResponseField name="event_id" type="string">
  Identificativo della risposta.
</ResponseField>

<ResponseField name="form_response" type="object">
  Payload completo: definizione dell'intervista, risposte e metadati.
</ResponseField>

## Modello dati (TypeScript)

<AccordionGroup>
  <Accordion title="WebhookPayload e FormResponse" icon="braces">
    ```ts theme={"dark"}
    interface WebhookPayload {
      event_id: string; // ID univoco dell'evento webhook (ID della risposta)
      event_type: "form_response"; // Sempre "form_response" per le risposte alle survey
      form_response: FormResponse; // I dati principali della risposta
    }

    interface FormResponse {
      form_id: string; // ID della survey
      token: string; // Token/ID della risposta
      submitted_at: string; // Timestamp ISO 8601 UTC quando la risposta è stata inviata
      landed_at: string; // Timestamp ISO 8601 UTC quando l'utente ha iniziato la survey
      calculated?: {
        score?: number; // Punteggio calcolato
        [k: string]: unknown; // Campi calcolati aggiuntivi
      } | null;
      variables?: Variable[]; // Variabili del form provenienti dai parametri URL
      hidden?: Record<string, string>; // Campi nascosti (se presenti)
      definition: FormDefinition; // Definizione della struttura della survey
      answers: Answer[]; // Risposte dell'utente
      ending?: EndingRef; // Schermata finale mostrata all'utente
    }
    ```
  </Accordion>

  <Accordion title="FormDefinition e FieldDefinition" icon="list">
    ```ts theme={"dark"}
    interface FormDefinition {
      id: string; // ID della survey (uguale a form_id)
      title: string; // Titolo della survey
      fields: FieldDefinition[]; // Domande/campi della survey
      endings?: EndingDefinition[]; // Possibili schermate finali
    }

    interface FieldDefinition {
      id: string; // ID univoco del campo
      title: string; // Testo della domanda
      type: FieldType; // Tipo di domanda (vedi sotto)
      ref?: string; // Identificatore di riferimento opzionale
      allow_multiple_selections?: boolean; // Per domande a scelta multipla
      allow_other_choice?: boolean; // Se l'opzione "Altro" è disponibile
      choices?: ChoiceDefinition[]; // Scelte disponibili (per domande a scelta)
      properties?: Record<string, unknown>; // Proprietà aggiuntive del campo
    }
    ```
  </Accordion>

  <Accordion title="FieldType, ChoiceDefinition e Variable" icon="braces">
    ```ts theme={"dark"}
    type FieldType =
      | "short_text"
      | "long_text"
      | "email"
      | "number"
      | "picture_choice"
      | "single_choice"
      | "multiple_choice"
      | "yes_no"
      | "opinion_scale"
      | "rating"
      | "swipe"
      | "single_choice";

    interface ChoiceDefinition {
      id: string; // ID della scelta
      label: string; // Testo/etichetta della scelta
      ref?: string; // Riferimento opzionale
    }

    interface Variable {
      key: string; // Nome della variabile
      type: "text" | "number"; // Tipo della variabile
      text?: string; // Valore testuale (se il tipo è "text")
      number?: number; // Valore numerico (se il tipo è "number")
    }
    ```
  </Accordion>
</AccordionGroup>

## Tipi di risposta supportati

Ogni risposta contiene un oggetto `field` (`id`, `type`, `ref`) che la collega alla definizione dell'intervista.

| Categoria | Tipi di campo                               |
| --------- | ------------------------------------------- |
| Testo     | `short_text`, `long_text`                   |
| Numerico  | `number`, `rating`, `opinion_scale`         |
| Scelta    | `single_choice`, `multiple_choice`, `swipe` |
| Booleano  | `yes_no`                                    |

## Struttura delle risposte

Il campo `type` di ogni elemento di `answers` determina quale proprietà contiene il valore.

<AccordionGroup>
  <Accordion title="Testo, booleano e numero" icon="file-text">
    ```ts theme={"dark"}
    // Risposta Testuale
    interface TextAnswer {
      type: "text";
      text: string;
      field: { id: string; type: FieldType; ref?: string };
    }

    // Risposta Booleana
    interface BooleanAnswer {
      type: "boolean";
      boolean: boolean;
      field: FieldReference;
    }

    // Risposta Numerica
    interface NumberAnswer {
      type: "number";
      number: number;
      field: FieldReference;
    }
    ```
  </Accordion>

  <Accordion title="Scelta singola e scelte multiple" icon="list">
    ```ts theme={"dark"}
    // Risposta a Scelta Singola
    interface SingleChoiceAnswer {
      type: "choice";
      choice: {
        id?: string;
        label?: string;
        ref?: string;
        other?: string; // Testo personalizzato se è stato scelto "Altro"
      };
      field: FieldReference;
    }

    // Risposta a Scelte Multiple
    interface MultipleChoicesAnswer {
      type: "choices";
      choices: {
        ids?: string[];
        labels?: string[];
        refs?: string[];
        other?: string;
      };
      field: FieldReference;
    }
    ```
  </Accordion>
</AccordionGroup>

## Variabili nascoste

Exoid cattura i parametri passati nell'URL dell'intervista (es. `?user_id=123`) e li riporta nel payload sotto `variables`.

```json theme={"dark"}
"variables": [
  {
    "key": "user_id",
    "type": "text",
    "text": "1qd12-4e34e"
  }
]
```

Ti servono per correlare le risposte a utenti, sessioni o campagne interne.

## Esempio di payload completo

L'intervista di questo esempio include swipe, testo breve, scala di opinione, sì/no, scelta multipla e una variabile nascosta.

```json theme={"dark"}
{
  "event_id": "f851e006-15a0-42dd-8408-d96ca7425a7e",
  "event_type": "form_response",
  "form_response": {
    "form_id": "97b7c9c3-0d04-47db-afac-0459761b3e90",
    "token": "f851e006-15a0-42dd-8408-d96ca7425a7e",
    "submitted_at": "2025-10-01T17:28:52.136Z",
    "landed_at": "2025-10-01T17:28:19.893Z",
    "calculated": { "score": 0 },
    "definition": {
      "id": "97b7c9c3-0d04-47db-afac-0459761b3e90",
      "title": "as",
      "fields": [
        { "id": "node-1759153917681", "title": "Pick a your favorite social media app!", "type": "swipe", "ref": "node-1759153917681" },
        { "id": "node-1759337349635", "title": "What is your name?", "type": "short_text", "ref": "node-1759337349635" },
        { "id": "node-1759337403533", "title": "Rate us", "type": "opinion_scale", "ref": "node-1759337403533" },
        { "id": "node-1759337554850", "title": "Did you enjoy your day today? 🌅", "type": "yes_no", "ref": "node-1759337554850" },
        { "id": "node-1759337400490", "title": "What activities did you do today? 🌞", "type": "multiple_choice", "ref": "node-1759337400490" }
      ]
    },
    "answers": [
      { "field": { "id": "node-1759337349635", "type": "short_text", "ref": "node-1759337349635" }, "type": "text", "text": "Mario rossi" },
      { "field": { "id": "node-1759153917681", "type": "swipe", "ref": "node-1759153917681" }, "type": "choices", "choices": { "labels": ["facebook"], "ids": ["facebook"] } },
      { "field": { "id": "node-1759337403533", "type": "opinion_scale", "ref": "node-1759337403533" }, "type": "number", "number": 3 },
      { "field": { "id": "node-1759337400490", "type": "multiple_choice", "ref": "node-1759337400490" }, "type": "choices", "choices": { "labels": ["🏃 Exercise or sports", "🎮 Gaming or hobbies", "💤 Resting or napping"], "ids": ["🏃 Exercise or sports", "🎮 Gaming or hobbies", "💤 Resting or napping"] } },
      { "field": { "id": "node-1759337554850", "type": "yes_no", "ref": "node-1759337554850" }, "type": "boolean", "boolean": true }
    ],
    "variables": [
      { "key": "user_id", "type": "text", "text": "1qd12-4e34e" }
    ]
  }
}
```

## Punti chiave

* Tutte le risposte sono contenute in `answers[]`, collegate al rispettivo `field`.
* **Swipe** restituisce `type: "choices"` con `labels` e `ids`.
* **Scelte multiple** restituiscono array in `choices.labels` e `choices.ids`.
* **Booleano** restituisce una proprietà `boolean`.
* **Opinion scale** e le altre domande numeriche usano `type: "number"`.
* **Testo** restituisce una proprietà `text`.
* **Variabili** catturano i parametri passati via URL (es. `user_id`).

## Prossimi passi

<CardGroup cols={2}>
  <Card title="Firma e sicurezza" icon="shield" href="/it/webhooks/sicurezza">
    Verifica l'header `X-Signature` prima di elaborare il payload.
  </Card>

  <Card title="Come funzionano" icon="webhook" href="/it/webhooks/introduzione">
    Flusso di consegna, ritentativi e codici di errore permanenti.
  </Card>
</CardGroup>


## Related topics

- [Firma e sicurezza](/it/webhooks/sicurezza.md)
- [Come funzionano](/it/webhooks/introduzione.md)
- [Configurazione](/it/webhooks/configurazione.md)
