Every field
What each field means, with an example for each kind of record
Stability and versioning
What we promise not to break, and how you hear about changes
How to import and export
Check a file, import it, export a workspace, map a CSV
AI file ingestion, a CheckAI Private Preview feature for existing
beta testers only, drafts import files too. When CheckAI extracts a contract or call sheet, it
proposes the same gig shape described below.
What a file looks like
schema_version:2.0. Any later2.xis accepted. A1.0document is rejected: move it to the 2.0 shape.source: where the document came from.source.typeis free text, for exampleSPREADSHEET,PASTE,INGESTION,EXPORTor your own partner identifier.
$.events[0].days[1].date: is outside the gig's dates. Nothing is committed. Counts, seats, quantities, capacities, call orders, ratings, set orders, minutes and song durations and tempos are whole numbers no larger than 2147483647, and none is negative, so 2.5, -1 or 2147483648 rejects the document. They follow the limits the API sets for the same values: seats, gear quantities and days_later start at 1, a position rating runs from 1 to 5, days_later is at most 365, duration_max_minutes at most 1440, a speaker’s minutes at most 600, and piece_count and vocal_count at most 99.
Documents carry data, not commands. There is no op instruction, and an explicit null does not clear a field: an omitted field keeps whatever Soundcheck already has.
Gigs, venues, clients, leads, cues, crew and ledger lines can each carry a provenance object saying where the record came from, for example { "source_system": "contract.pdf", "source_file_ids": ["…"] }. It travels with the document so a reviewer can trace a value back to its source; Soundcheck doesn’t write it onto the record.
Refs: one record, named once
Clients, venues, acts, guests, hotels, vehicles, projects and gigs can each carry aref: a short name you make up (such as main-stage) that only means something inside this file. Other records use it to point at that record, so you write a venue once and every gig there names it:
A ref must be unique within its collection, and every pointer must name a ref that exists. Twenty gigs at the same venue name the venue once.
A gig can instead carry its venue or client inline, as a
venue or client object. Use one form or the other on a gig, not both.
Gigs (events[])
Days and run of show
Each entry indays[] describes one calendar day of the gig.
Each cue has a
name (required), start and end as 24-hour HH:MM local times in the gig’s timezone, notes, an optional act_ref, and an optional days_later. An end earlier than its own start runs past midnight. A cue that happens after midnight but belongs to the listed day carries days_later: 1 (a whole number of calendar days after the listed day); a workspace export writes it for you. Cues must be in time order, counting days_later. A backward clock change between cues with no days_later is ambiguous (out-of-order presentation or overnight timing), so that day’s import reports an error and leaves its cues, phases and notes unchanged. Soundcheck never infers a date from a cue’s position. Re-importing a day updates the cues an earlier UEF import wrote, matched by name (ignoring case; a repeated name matches in order), so inserting or reordering cues doesn’t rewrite the others. A renamed cue comes in as a new one. A cue with no earlier-imported match that shares its name with a cue someone added to that day in Soundcheck counts as that cue (in order, for repeated names) and leaves it exactly as it is, so a workspace export imported back into its own workspace leaves one copy of every cue. An import never edits or removes a cue added in Soundcheck. A cue an earlier UEF import wrote that the day no longer lists is removed, unless someone attached songs or documents to it in Soundcheck. Send run_of_show: [] to clear a day’s imported cues, phases: [] to clear its phases and notes: "" to clear its notes; leaving a key out keeps what Soundcheck has.
A cue can also carry timing_mode (CLOCK, SEGUE or ON_CUE; ON_CUE needs a timing_label), timing_label, duration_minutes and duration_max_minutes (the maximum must not be below the minimum), tentative, playback_source (LIVE, TRACK, DS_IPAD or OTHER), note_roles (any of SOUND, BAND_LEADER, PLANNER or MUSICIANS), instructions (up to 4000 characters), location, ensemble, and speakers, a list of objects with a name and optional relationship and minutes. An imported speaker is not linked to a gig contact. A re-import updates a cue nobody has edited since the import, including these fields. A cue whose speakers someone edited in Soundcheck keeps them through a re-import that omits the cue.
A day can also list its segments[], the run-of-show sections such as Cocktails or Reception. Each segment has a name (required), start and end as local HH:MM times, an optional days_later, segment_kind (CEREMONY, COCKTAILS, RECEPTION, DINNER, DANCING, AFTER_PARTY, OTHER or SOUND_CHECK), location, ensemble, and piece_count and vocal_count (each a whole number from 0 to 99). booking_state and gear_notes are still accepted but ignored: segments are no longer marked booked or not booked, and gear lives in the gig’s Gear tab. A cue whose start falls inside a segment’s window is filed under that segment; other cues stay in the day’s section. A day without a run_of_show[] list does not write its segments.
Shifts and crew
A shift describes a role on the gig:seats is how many people it needs in all, and the people named in crew[] are invited to the gig in that shift’s position.
A crew member needs an
email or a phone_number to be invited. Seats nobody in crew[] fills become an open shift on the staffing board: a shift with no crew opens all its seats, one with two of three seats filled opens one, and a fully crewed shift (or crew with no seats) opens none. Each person is invited once per gig, in the position of the first shift that names them (matched by email or phone). They fill a seat on every shift for that position that names them, and none on a shift for another position, since their invitation does not cover it. An entry with neither email nor phone fills no seat. A crew member whose position comes only from the shift’s title, and matches none of the organization’s positions, is invited with no position and no note. A position that matches none is kept in the invitation’s fee notes as Position: ….
Gear list
pack_items[] lands on the gig’s Gear tab, unpacked. Each line needs a name or an external_id, with an optional quantity (defaults to 1) and notes. The external_id is matched first; a name is matched case-insensitively, and an unknown name is added to inventory. A line whose item is already on the gig is skipped, so a re-import never doubles the list. A line that needs more units than are available fails only that line.
Ledger lines
ledger_items[] are the gig’s money lines: deposits, balances, fees and expenses. They land on the gig’s Finances tab.
A line with an
external_id matches by it. When one document repeats an external_id (two payments against one invoice, say), the first line keeps it and each repeat takes its own key under the reserved uef:occurrence: prefix, numbered in document order, so every line is kept. A line whose external_id starts with uef:occurrence: is refused. A line whose external_id is already on the gig with the same values is a duplicate. The same external_id with a different amount, date, currency, type, description or counterparty is refused and reported with both values; the gig is not changed. A line without an external_id matches by type, description, amount, its own date, currency, counterparty and account hint, with an occurrence number for identical lines. These fields are encoded separately, so punctuation inside a name cannot make two different lines match. Reordering distinct lines or moving the gig to another day preserves their keys. Syncing a line to QuickBooks doesn’t change how a later import matches it.
Earlier development versions used a different derived key. Unchanged legacy rows are matched once per import by their stored type, description, amount, date, currency, counterparty and resolved account, and counted as existing. Their stored keys and financial details remain unchanged: an old-looking key may also be a supplied external ID. Supplied external IDs keep their identity regardless of prefix, except the reserved uef:occurrence: prefix, which is refused. If unmatched legacy rows remain and the import would add a derived-key line, the ledger write rolls back and reports a reconciliation error. Review those rows before retrying; ambiguous matches never create a second charge.
Projects (projects[])
A project is a tour, festival, residency or any other body of work that owns gigs.
Acts (acts[])
Performing acts that run-of-show cues can name: name (required), ref, external_id, is_external (booked from outside the organization) and notes. Acts match by name only, ignoring case: an act renamed in the source system comes in as a new act.
Guests (guests[])
People on the organization’s guest list: name (required), ref, external_id, email, phone, dietary, tags (a list, such as ["VIP"]) and notes. A guest with an email or phone matches an existing guest by it; a guest with neither matches a guest of the same name who has no contact details either. A matched guest keeps its own details and only fills the ones it is missing.
A gig’s guest_list[] puts guests on that gig. Each entry names a guest with guest_ref, or just a name for someone with no record yet, and can set plus_count (0 to 99), pass_type (COMP when absent), role (HONOREE for someone the show honors), rsvp_status (ATTENDING when absent), meal_choice and notes. A guest the gig already lists is skipped, so re-importing a file adds nothing. events[].honorees still works and lists each name as an honoree.
A gig’s guest_sources[] lists where its guest list comes from, for reference only: provider (LUMA, PARTIFUL, THE_KNOT, ZOLA, EVENTBRITE, SPREADSHEET or OTHER), label, external_event_id, external_url and last_synced_at. Workspace export writes them and never includes credentials, tokens or webhook secrets. Import reads them and ignores them: it creates no guest source and starts no sync, because importing a Luma source would start syncing that Luma event into the importing workspace. The preview notes how many it skipped (“2 guest sources listed for reference, not imported”). Reconnect a source on the gig after importing. Check-ins are not part of the file.
Travel (hotels[], vehicles[])
hotels[] are the hotels the organization has saved: name (required), ref, external_id, place_id, street, unit, city, state, postal_code, country, phone, website, brand, check_in_time, check_out_time, notes (the organization’s own notes), room_block_code, negotiated_rate, rate_currency and billing_method. A workspace export writes each saved hotel’s ID as its ref, so importing that export back into the same workspace matches each hotel to its own record first. Otherwise a hotel with a place_id joins the shared directory record for that place, and one without matches a saved hotel of the same name (ignoring case) whose street and city agree wherever both give one. A hotel that matches more than one saved hotel that way is left out, with a note, rather than guessed, and the stays that name it are refused. A matched hotel is not changed. Corporate and loyalty account numbers are never part of the file.
vehicles[] are the organization’s own and rented vehicles: name and ownership (OWNED or RENTED) are required, then make, model, year, color, license_plate, seats, the rental fields (rental_company, rental_confirmation, rental_start_date, rental_end_date, rented vehicles only), cost, cost_currency and notes. A workspace export writes each vehicle’s ID as its ref, so importing it back into the same workspace matches each vehicle to its own record first. Otherwise a vehicle matches a saved vehicle with the same name (ignoring case) and ownership whose make, model, plate and rental confirmation agree wherever both give one. A vehicle that matches more than one is left out with a note rather than guessed. A matched vehicle is not changed. A rental that ends before it starts is refused in the preview.
A gig carries its travel in three lists. People on them are named by email, and must be active members of the organization: an entry naming anyone else is refused and the rest of the gig imports. The preview names each traveller it cannot place.
hotel_stays[]:hotel_ref(required),check_in_date,check_out_date,confirmation_number,room_count,notes, andguests[](email,room_number,confirmation_number,notes). The same gig, hotel and check-in date update one stay rather than adding another. A stay that checks out before it checks in is refused in the preview.flights[]:airline,flight_number,depart_airport,arrive_airport,depart_at,depart_timezone,arrive_at,arrive_timezone,booking_reference,cost,cost_currency,notes, andpassengers[](email,confirmation_code,seat,ticket_number,baggage_count,notes). A workspace export writes each flight’s ID as itsref, so importing that export back into the same workspace matches the flight it came from; otherwise a flight with the same number and departure on the gig is not added again, and one that matches more than one flight on the gig is refused rather than guessed. A flight that lands before it departs is refused in the preview. The live status (status,estimated_depart_at,estimated_arrive_at, gates and terminals) comes from the status provider: workspace export lists it for reference and import ignores it.transports[]:kind(CAR_RENTAL, RIDESHARE, SHUTTLE, VAN, BUS, TRAIN, DRIVER or OTHER, required),provider, pickup and drop-off place, time and time zone,vehicle_refor a free-textvehicle,driver_name,driver_phone,confirmation_code,cost,cost_currency,payer,pickup_instructions,notes, andriders[](email,notes). Rides carry arefthe same way. Otherwise a ride with the same type, pickup time and place on the gig is not added again, and one that matches more than one ride on the gig is refused rather than guessed. A ride that drops off before its pickup is refused in the preview.
Clients (clients[])
name (required), ref, external_id, email, phone, website, status, notes, address, city, state, postal_code, country, and contacts[] (name, email, phone, title, is_primary).
Venues (venues[])
name (required), ref, external_id, address fields, phone_number, website, latitude, longitude, place_id, notes, and the venue’s production details: dock, elevator, parking, load_in, load_out, access_code, capacity, venue_type, stage_size, wifi, dressing_rooms, green_room, house_tech, restrictions, amenities, contact_name, contact_role, contact_email, photo_url.
photo_url is a public http or https image URL for the venue’s baseline photo. It only fills a venue that has no photo yet: import never replaces a photo the venue already has, whether it is a URL or an uploaded copy, and never brings back a photo your organization removed. The photo is saved on your organization’s copy of the venue, so other organizations that use the same venue don’t see it. A value that is not an absolute http(s) URL (a relative path, another scheme, or a URL with a user name or password) is dropped with a warning in the preview, and the rest of the venue still imports. A gig’s inline venue object accepts photo_url with the same rule. A workspace export writes a venue’s photo when it is a public http(s) URL. A Google Places photo only loads through Soundcheck, so the export leaves it out.
A venue’s stages[] are its rooms and stages: name (required, unique within the venue, ignoring case), ref, capacity, stage_size, house_tech and notes. A workspace export writes each active stage’s ID as its ref, so importing it back into the same workspace matches each stage to its own record first; otherwise a stage matches the venue’s stage of the same name, ignoring case. A matched stage is not changed, and a new one is not listed on your storefront. When a venue lists its stages, its own stage_size and house_tech are not applied, because they describe its first stage. Archived stages, spots and holds are not part of the file.
Stages and key times on a gig (events[].stages[], events[].key_times[])
A gig’s stages[] books stages at its venue. Each entry names one with stage_ref (a stage’s ref, or its name when it has no ref) and can set notes. The gig needs a venue_ref, and every stage_ref must be a stage of that venue. Import adds the stages to the ones the gig already books and never removes one; a stage the gig already books keeps its own note.
A gig’s key_times[] are its call, doors, show and curfew times: kind (crew_call, load_in, rehearsal, soundcheck, doors, ceremony, show, set, curfew or load_out, in any case), date (a day of the gig), time (24-hour HH:MM), past_midnight (true for a time after midnight that belongs to date’s night, before 12:00) and note. One kind appears once per day. Import writes them the way the gig page does, so run-of-show items anchored to a key time move with it. A key time someone set by hand on the gig is never changed by an import. A workspace export writes every key time on the gig’s days.
Labels, offerings, sponsors and task templates
These collections sit at the top of the file next tohotels[] and vehicles[]. Each record can carry a ref. A workspace export writes the record’s ID as its ref, so importing that export back into the same workspace matches each record to its own row first; otherwise a record matches by name, ignoring case. A matched record is not changed, a name that matches more than one saved record is left out with a note, and import never deletes a record the file leaves out.
label_groups[]:name,description,selection(SINGLE or MULTIPLE) andapplies_to(EVENT, TASK, ASSET, SCHEDULE_ITEM or CONTACT). Built-in groups, such as gig type, are not exported or imported; a gig’s type travels asevents[].type.labels[]:name,group_ref,color,descriptionandapplies_to. A label matches a saved label of the same name in the same group.offerings[]:name,category(AUDIO, LIGHTING, VIDEO, LABOR, PACKAGE, VENUE_SERVICES or OTHER),unit(EACH, HOUR, DAY or FLAT),sell_rate,cogs,invoice_label,activeandpublic.offering_packages[]:name,description,deposit_pct,publicandlines[](offering_ref,quantity,rate_override,note). Offerings import only when the org has offerings turned on and the importer can manage the business. Pricing history (PricingExtractionRun,PricingObservation) is worked out from the org’s own quotes, so it is not exported or imported.sponsors[]:name,email,phone,website,status,tier,notesandcommitments[]for deals not tied to a gig (ref,title,amount,currency,status,due_date,paid_at,notes). A sponsor matches a saved sponsor of the same name when their emails agree or either has none. Sponsors stay their own records and never become clients.checklist_templates[]:name,defaultandphases[](title,kind,tasks[]withtitle,notesanddue_offset_days). Import never moves the default away from another template.run_of_show_templates[]:name,description,default,time_anchor_minutes,sections[]andcues[]for cues outside a section. Times are relative, never a date: a clock time as minutes after midnight (start_clock_minutes,end_clock_minutes) or minutes from the anchor (start_offset_minutes,end_offset_minutes), and a section’sday_offsetplaces it on a later gig day. A cue names its audience by position name and its songs bytitleandartist; a position or song the org does not have is left out, with a note. File attachments are not carried.
staffing_plans[]) and run of show templates can carry provenance.catalog_key and provenance.catalog_version, the Soundcheck starter catalog entry they came from. A template with a catalog key matches the org’s template with the same key before it looks at names, and a new template stores the key and version.
Money follows finance access. Sell rates, costs, package line rates and sponsor deal amounts are exported only for a caller who can view finances, and import sets them only when the importer can edit finances. Without it, a new offering or a new sponsor deal is left out with a note, because each needs its money, and package line rates are left off. A new sponsor deal posts a receivable to the org’s income account, as it does in the app.
Labels, checklist and sponsor deals on a gig (events[].labels, events[].checklist[], events[].sponsor_commitments[])
A gig’s labels names labels by ref. A gig’s checklist[] lists its phases (title, kind) and each phase’s tasks[]: ref, title, status (NOT_STARTED, IN_PROGRESS or COMPLETE), notes, due_date (a calendar day), assignee_email and labels. A phase matches the gig’s phase of the same title. A task matches by ref first, then by title within its phase. Matched tasks are not changed; new tasks are added after the gig’s own, and import never removes a task. An assignee must be an active member of the org; anyone else leaves the task unassigned, with a note.
A gig’s sponsor_commitments[] are its sponsor deals: sponsor_ref (required), ref, title, amount, currency, status, due_date, paid_at and notes. A deal matches by ref, then by sponsor, title and due date on the same gig.
Labels are added, never taken off. In a SINGLE group an item holds at most one label, so a label that would replace the one already there is left off, with a note. Labels on gear, run of show items and contacts are not imported yet.
Team, inventory, songs, setlists and leads
These collections use the same fields as the matching spreadsheet import:members[]: the organization’s team.email(required),role, names,phone_number,notes, andpositions[]with ratings and day rates. Crew for a particular gig go on its shifts instead.roleis Member when blank, otherwise Admin, Finance or Gig Coordinator. Case, spacing, hyphens, underscores and dots do not matter, sogig-coordinatoris Gig Coordinator, and a Clerk name such asorg:adminis Admin. An Owner is invited as Admin when the email is new and the importer is an Owner. Only an Owner can invite an Admin, so any other importer skips that Owner row with a warning. An existing member keeps their current role. A misspelt role (Adnim) is read as the role it means: a JSON document is written with that role, and a spreadsheet row also gets a warning. Text that matches no role (Manager) refuses the document, or the row in a spreadsheet, and is never written as Member.
inventory[]:name(required),external_id,category,quantity,status,condition,location,replacement_cost,daily_rate,serial_number,manufacturer,model,case_type,case_dimensions,weight,notes.songs[]:title(required),artist,duration,key,tempo,notes.setlists[]:title,is_template, andsets[]with theirsongs[].leads[]:name,emailandevent_date(required), plusphone,event_type,location,deal_stage,budget,message,status,external_idandprovenance.event_reflinks the inquiry to a gig in the same document; a linked lead without its ownevent_typetakes the gig’s, and a lead with neither is saved asOther.
Example
A three-day festival with its client, venue, headline act, project, days and one staffed shift:Datetime conventions
- Calendar days (
event_date,end_date,days[].date, project dates):YYYY-MM-DD, no time. - Gig
start_time/end_time: RFC3339 with an offset, e.g.2026-06-15T19:00:00-04:00. - Run-of-show
start/end:HH:MMon the cue’s day, in the gig’stimezone.
Identity and safe re-imports
External IDs keep re-imports safe. The writer matches a record in this order:- By
external_id, when present. - By natural key:
(title, event_date)for gigs; the name, ignoring case, for clients, venues and projects. Acts match by name only. Guests match as described under Guests, and hotels, vehicles, stays, flights and rides as described under Travel.
external_id that matches nothing takes over a same-named project only when that project has no ID from an import yet. Two “Summer Tour” projects with different IDs stay two projects.
When both are present, external_id wins, so renaming a gig in the source system keeps it linked instead of creating a duplicate.
An external_id is compared exactly after trimming spaces at either end: G1 and g1 are different records, and G1 and G1 are the same one. Within one collection, an external ID names one record; a repeat is rejected. A gig whose external_id matches nothing falls back to (title, event_date) only for a gig that has no ID from the same source, so it never takes over a gig another ID already owns.
Invitations are deduped per gig by email and by phone number, so re-running the same import is always safe.
Field catalog
The reader’s field list and JSON Schema are generated fromontology/registry.json, so the importer, the MCP tools and the catalog can’t drift apart. The field list lists every field from the same source. Fetch the live catalog from the API: