Documentation

Field Types & Validation

The type and format each field expects, what the API accepts, and how validation errors are reported.

Every write endpoint type-checks its request body before anything is saved. A field with the wrong type is rejected with 400 and a message naming the field, what it expected, and what you actually sent - the whole request fails, so you never end up with a half-written record.

{
  "error": "Invalid request body",
  "details": [
    "'track' must be a whole number (received the string \"Main Stage\").",
    "'date' is not a real calendar date (received the string \"2026-02-30\")."
  ]
}

Fields to check before your first write

Most fields are plain text. These few take a number or a particular format, so they are worth confirming when you build your payload.

Field Object Type What it actually is
track session integer The position of the track in your event’s track list, counting from 0. Put the stage or room name in location.
tintColor session integer The session colour. Send a hex string such as "#3366FF", or a 32-bit ARGB integer if you already have one (4294967295 is white).
tier sponsor integer The position of the tier in your event’s sponsor-tier list, counting from 0. Tier names are set under Event Settings.
tags session, speaker string One tag, or several separated by commas. An array is accepted too.
representativeEmails sponsor string One address, or several separated by commas. An array is accepted too.
ticketRedemption session string The ticket tier that can be redeemed at this session. Leave empty for none.
options poll array of strings A real JSON array, at least 2 entries - not comma-separated, because an option may itself contain a comma.
maxChoices poll integer How many options one attendee may pick. Never more than the number of options.
status question enum Exactly one of pending, approved, rejected, answered. Replaces the stored approved/rejected/answered booleans.
points, bonusPoints score object number Decimals allowed; rounded when the leaderboard is calculated.
trackArray, tierArray event array of strings The track and tier names. track and tier above are positions in these lists.

Accepted formats

The API is deliberately forgiving where the intent is unambiguous, so you rarely have to match the internal storage format exactly.

Type Accepted Stored as
integer 150, "150" 150 - decimals and non-numeric strings are rejected
boolean true, "true", "yes", 1 / false, "false", "no", 0 true / false
colour 4281558783, "#3366FF", "#FF3366FF", "0xFF3366FF" ARGB integer - a 6-digit hex gets a fully opaque alpha
tag list "ai, keynote" or ["ai", "keynote"] "ai, keynote" - trimmed, blanks dropped, duplicates removed
email list "[email protected], [email protected]" or ["[email protected]", "[email protected]"] "[email protected],[email protected]" - each address is validated
email " [email protected] " "[email protected]" - trimmed and lowercased
date "2026-09-14" Same. Must be a real calendar date; "" clears it
time "09:00", "9:00" "09:00" - 24-hour; "" clears it
rich text Delta JSON string, or plain text Same - malformed Delta JSON is rejected. See Rich Text Format
number 10, 2.5, "2.5" 2.5 - unlike integer fields, decimals are kept
string array ["Yes", "No"] Same - entries are trimmed; blanks and duplicates are rejected
enum "answered", "Answered" The canonical spelling. An invalid value is rejected with the full list of valid ones

A few more rules worth knowing:

  • Omitted means unchanged. On an edit, only the fields you send are written. To clear a field send "", 0, or false - not null, which is rejected.
  • The body must be a JSON object. Send Content-Type: application/json. A bare string or array is rejected with 400.
  • Required fields are enforced on create. Creating a speaker without a name, or a poll without options, is rejected with 400 before anything is written. On an edit the same fields are optional - but sending one empty is still rejected, since that would wipe it.
  • Writes are POST, reads are GET. The wrong verb returns 405 with an Allow header.
  • Test before you write. Add ?dryRun=1 to any write to validate it - reference checks included - without saving. See Discovery & Dry Runs.

Warnings and ignored fields

Not everything that looks wrong is fatal. When a write succeeds but something is worth a second look, the 200 response carries extra keys:

Key Meaning
warnings The value was saved, but probably isn’t what you meant - a link that isn’t an absolute http(s) URL, or a timeEnd before its timeStart.
ignoredFields Body keys the endpoint does not recognise at all, so they were dropped. Near-misses get a suggestion, e.g. "unlisted (did you mean 'unListed'?)".
{
  "status": "success",
  "sessionId": "aB3xY...",
  "created": true,
  "warnings": ["'handOutLink' does not look like an absolute http(s) URL (\"www.example.com/deck.pdf\"); it may not open as a link in the app or website widgets."],
  "ignoredFields": ["colour", "unlisted (did you mean 'unListed'?)"]
}

Both keys are omitted entirely when there is nothing to report, so a clean request gets the same response shape it always did. ignoredFields is the quickest way to catch a typo, or a payload built against a different system.

Protected fields

A few fields would be a lie to accept. Attendee poll votes, Q&A upvotes and question scores are written by the app; billing limits and tenancy are not yours to set; and a question’s approved/rejected/answered flags have a supported replacement in status. Dropping any of those quietly would be worse than useless - a caller sending votes would get a 200 and reasonably believe it had recorded them.

So they are rejected with a 400 that names the reason and, where there is one, the field to use instead:

{
  "error": "Invalid request body",
  "details": [
    "'votes' cannot be written through the API - attendee ballots are cast in the app and would be overwritten. Read results with /getPollResults.",
    "'approved' cannot be written through the API - moderation state is set with the 'status' field (pending | approved | rejected | answered)."
  ]
}

This is the difference between an unrecognised key, which lands in ignoredFields, and a recognised but forbidden one, which fails the request outright.

Read-modify-write still works

The protected list is deliberately narrow, and no field that a read hands back to you is on it. Server-owned bookkeeping - documentId, clientId, deleted, hidden, apiImported, updated - and derived values like a session’s speakers array are simply reported in ignoredFields. So fetching an object, changing one value, and posting the whole thing back is safe: the fields you didn’t mean to write are listed, not fatal.

Anything genuinely protected is either never returned at all (poll votes, question voters) or has an obvious supported alternative, so a round trip can’t trip over one.

Every object’s protected fields, with their reasons, are listed by GET /apiSchema.

Cloudflare vs. the API

api.event-vault.com sits behind Cloudflare, which rejects unrecognised user agents before the request reaches the API. Always send a normal User-Agent header.

Tell the two apart by the response body: a 403 with a JSON body is a genuine permission or scope failure from the API; a 403 with an HTML body or an error code: 1010 is Cloudflare.