CSV schema
The formal specification of the upload format, for writing an export or checking a file.
If you are preparing data for the first time, start with Prepare your data, which explains what to put in these columns and why it matters. This page assumes you already know that and need the exact rules.
File format
| Property | Requirement |
|---|---|
| Format | CSV |
| Encoding | UTF-8 |
| Byte order mark | Tolerated |
| Delimiter | Comma |
| Line endings | LF or CRLF |
| Header row | Required |
| Column order | Any |
Quoting and escaping
- A field containing a comma must be wrapped in double quotes.
- A double quote inside a quoted field is escaped by doubling it.
- A line break inside a field is allowed, provided the field is quoted.
session_id,timestamp,side,utterance,channel
a1,2024-06-01T09:00:00.000,USER,"I said ""cancel it"", not ""change it""",TEXT
a1,2024-06-01T09:00:05.120,BOT,"Understood.
Which card should I cancel?",TEXT
Columns
Five columns are required. Names are matched exactly as written here.
| Column | Type | Required | Constraints |
|---|---|---|---|
| session_id | string | Yes | dentifies the conversation. Must be unique across every file you ever upload, not only within one file. Format is yours to choose. |
| utterance | string | Yes | The full text of one message, including any markup for buttons or components. No practical length limit. A row with an empty value is dropped — see Rows that are dropped. |
| timestamp | string | Yes | ISO 8601, millisecond precision. See Timestamps. |
| channel | enum | Yes | VOICE, TEXT or BUTTON. Case-insensitive. |
| side | enum | Yes | USER or BOT. Case-insensitive. |
Enumerated values
| Column | Accepted values |
|---|---|
| channel | VOICE — spokenTEXT — typedBUTTON — clicked |
| side | USER — the personBOT — the assistant |
Case does not matter: TEXT, Text and text are all accepted. The documentation uses upper case throughout for legibility.
Timestamps
Pattern: YYYY-MM-DDTHH:MM:SS.sss followed by an optional time zone.
| Form | Example | Interpreted as |
|---|---|---|
| No zone | 2024-06-01T09:00:00.123 | UTC |
| Z | 2024-06-01T09:00:00.123Z | UTC |
| Offset | 2024-06-01T09:00:00.123+02:00 | That offset |
Use millisecond precision. Inquio orders utterances within a conversation by timestamp, so at second-level precision a user message and an assistant message that share a second may be ordered wrongly — which changes what the conversation appears to say.
Row order in the file does not matter. Inquio sorts by timestamp itself, so an export that emits conversations out of order is fine.
Optional columns
| Column | Type | Description | Example |
|---|---|---|---|
| custom_meta | string | Any parameter or flag belonging to that utterance — a thumbs up or down, a client ID, an outcome marker. Read and displayed alongside the conversation. | success |
Any other column you include is ignored. Extra columns never cause a failure, so there is no need to strip your export down.
Note that custom_meta is per row, not per conversation. Each utterance carries its own value, so you can mark the single answer a user rated badly rather than labelling the whole exchange.
What makes a file fail
There are two different outcomes, and the difference matters: one stops the upload, the other is silent.
Errors that reject the file
Nothing is analyzed and the upload reports Validation failed, listing what was wrong. See When processing fails.
- The header is missing one or more required columns.
- The file is not valid CSV — for example an unterminated quoted field.
- The file is not readable as UTF-8.
- Every session_id in the file is already present in Inquio.
Rows that are dropped
These do not stop the upload. The row is discarded, the rest of the file is processed, and nothing tells you it happened.
- An empty utterance.
That last point is worth designing around. If your export produces empty utterances — for a button click with no label, a system event, an attachment with no text — those messages disappear from the conversation without a trace, and the analysis reads a conversation with holes in it. Filter them out deliberately, or give them text, rather than letting them be dropped silently.
What Inquio does with the file
- Validate. Format and header are checked. A failure here stops everything.
- Drop invalid rows. Rows that cannot be used are discarded.
- Remove duplicates. Any session_id already in Inquio is skipped, and not charged.
- Truncate. If what remains exceeds your plan's limits, the oldest data that fits is kept and the rest discarded, with a note on the report card.
- Analyze.
Limits per plan are in Plans and limits.
Complete example
One conversation, all five columns:
session_id,timestamp,side,utterance,channel
cc145dc461eefd1ff1,2024-06-01T08:12:03.000,BOT,"Hello, I am your virtual banking assistant. How can I help you?<buttons><button title=""Account statements""></button><button title=""Card problems""></button></buttons>",TEXT
cc145dc461eefd1ff1,2024-06-01T08:12:19.447,USER,Account statements,BUTTON
cc145dc461eefd1ff1,2024-06-01T08:12:20.101,BOT,"Statements for the last 12 months are in the Documents section of your online banking. Which account do you need?",TEXT
cc145dc461eefd1ff1,2024-06-01T08:12:41.882,USER,"The savings one, ending 4471",TEXT
cc145dc461eefd1ff1,2024-06-01T08:12:42.503,BOT,"Your savings account statements are ready to download. Anything else?",TEXT
cc145dc461eefd1ff1,2024-06-01T08:12:58.219,USER,"No, thanks.",TEXT
Note the assistant's first row: the button markup is included, the channel is TEXT even though buttons are offered, and the user's reply carries the button's visible label with channel set to BUTTON.
A ready-made file is also available from Template on the upload screen.
Related
- Prepare your data — what to put in these columns, and why
- When processing fails
- Plans and limits