Overview
This page describes the protected group API: artists, events, contacts, and venues. List
GET responses use JSON with
data and meta. Create and update write endpoints return
data.id and data.slug; delete endpoints return
data.success.
Request and response shapes differ. Field tables are split into
input schemas (POST bodies) and
output schemas (GET list/detail). GET payloads
include many server-derived or read-only fields (ids, slugs, flags, denormalized names,
nested venues) that you cannot set on POST. Do not copy a GET response
and send it back as an update body. GET itinerary list rows always include
_id. Itinerary lists (tickets, schedules, marketing materials, and
similar) are replaced in full when sent — see
Updating itinerary lists.
Changelog from v1.4.8 to v1.6.0
Breaking
-
GET itinerary always present. Deployed docs omitted
bookings[].itinerarywithoutextend. It is now always present: unrequested lists are[], scalarsnull,has*flagsfalse. Every resource field is always included (empty string kept; missing scalars are JSONnull). -
Tickets replace in full. Sending
itinerary.ticketsstores that array as-is. v1.4.8 merged tickets by_idwhen any incoming row had an id; omitted ticket categories are now removed. -
Venue GET omits
addressLine1. Use combinedstreet(plusstreetName/streetNumber) for the address line. This key is not present on venue list/detail or nested eventvenue.
Added
-
extend=marketing—itinerary.marketing.materials(_id, description,typetext|count|choice,value) anditinerary.marketing.receiverContacts(delivery contacts). -
Event
bookingCapacity(show capacity, separate fromvenue.capacity). -
List query
includeDeleted(defaultfalse). GET by id still returns soft-deleted events (isDeleted: true). POST update of a soft-deleted event returns404. -
Nested event venue may set
isVerified. -
Venue
venueType— optional string array of free-form venue type labels on create/update; always present on GET (empty list is[]).
Changed
-
Itinerary list
_idis always present on GET for every row (flights, guest list, hotels, lineup, schedules, specials, tickets, transports, travels, marketing materials). POST accepts optional_idto keep the stored id. Resource ids remain on events, bookings, contacts, and venues. Contact refs still use{ "contactId": "…" }. -
Ticket sales stay on
bookings[].itinerary.tickets(extend=tickets). Event-rootticketsremains deprecated. -
Writing ticket sales, marketing materials, or
bookingCapacityalso updates eventupdatedAt(the field itself already existed). -
sequenceNris still GET-only and assigned from array order on write. -
Venue GET still includes
attachments(samecategory,public_id,urlshape as event attachments).logoremains the primary venue image.
Clarification
-
Itinerary lists are full-replace. Sending
tickets,schedules,flights, marketing materials, and similar arrays stores that list as-is (no per-row patch). Optional_idkeeps the stored row id; omit_idto create a new id. See Updating itinerary lists.
Changelog v1.7.0
Added
-
Contact billing address is writable.
POST /v1/group/contactsandPOST /v1/group/contacts/:idacceptbillingAddress(name, company, address lines, postal code, city, state, country). Omit it to leave the stored address unchanged.nullon a field clears that field;nullfor the object, or clearing the last field, removes it. GET list and detail return the same fields (nullwhen there is no billing address). Rights are unchanged:read:contacts/write:contacts, plus the existing contact visibility and edit rights. -
Booking deal on GET events.
GET /v1/group/eventsandGET /v1/group/events/:idincludebookings[].deal, the mapped Optune deal for that booking (guaranteed fee, additional fee, expenses, agency / manager / other commissions with percentage and amount, currencies, storeddealType, and calculateddeal.total).dealTypeis the stored booking value, ornullwhen unset. Fee lines omitfeeType,label,hint,percentage,inclusive,isFixAmount, andisSubtotalCommission.feeDescriptionis only onotherCommission.afterCommissionsis only onartistFeeExpenses. Linevatis only on commissions (guaranteed, additional, and expenses fees do not store VAT; commission VAT is calculated intodeal.total). Commissionamountis the stored amount whenisFixAmountis true, andnullwhen it is false. Commission lines keeppercentage(andinclusive,isFixAmount,isSubtotalCommission) and omitfeeType,label, andhint. Calculated totals omitlabelandhint. Each total amount includespercentage(nullwhen there is none) andpercentageCommissionType(single commission, orvarious commissionswhen commission VAT rates are mixed). Mixed rates ontotal.commissionVATandtotal.commissionOnSubtotalVATare returned aspercentage: nullandpercentageCommissionType: "various commissions". It is read from the stored deal on each request.feeandfeeCurrencyare unchanged.dealis not writable.
Permissions
-
dealuses the same visibility asfeeandfeeCurrency. The API key must includeread:deal. Artist members and agency managers only receive it when their deal right is visible, including per-artist deal visibility for an agency. When any of those checks hide the deal,bookings[].dealisnull(andfee/feeCurrencystaynull).extenddoes not grant deal access.
Authentication headers
Use a Bearer API key for all protected group endpoints:
Authorization: Bearer optune_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Optional legacy fallback for selected routes (only if documented by endpoint):
Content-Type: application/json { "apiKey": "optune_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}
Scopes
Read scopes:
read:artists read:contacts read:deal read:events read:internalComment read:venues
Write scopes (POST create/update, DELETE):
write:contacts write:events write:internalComment write:venues
read:deal is required to read bookings[].deal,
fee, feeCurrency, managerFee, and
managerFeeCurrency. It does not reveal the internal agency note.
read:internalComment is required to read
bookings[].internalAgencyComment.
write:internalComment is required, together with
write:events, to set, change, or clear that note.
write:internalComment does not grant read access.
Sync and pagination contract
List endpoints follow a consistent contract: deterministic sorting, stable IDs, optional
updatedSince filtering, and limit/offset
pagination with a meta object.
For artists, contacts, and venues, updatedSince includes entries where
createdAt or updatedAt is greater than or equal to the given
date.
For events, startDate and updatedSince are optional;
endDate is only valid when startDate is provided.
{ "data": [{ "_id": "..." }], "meta": { "hasMore": false, "limit": 50, "offset": 0,
"total": 1 } }
limit defaults to 50 and is capped at 200.
offset must be a non-negative integer (no upper cap).
Invalid date values return 400 with a structured error body.
Event extend query (list & detail)
On GET /v1/group/events and GET /v1/group/events/:id, use
extend to load extra booking itinerary slices into each
bookings[].itinerary object. Pass one or more categories (comma-separated
in a single parameter, or repeated query params). Values are case-insensitive; an
itinerary. prefix is accepted and stripped (for example
itinerary.lineup → lineup).
Categories that populate bookings[].itinerary:
contacts custom flights guestList hotels lineup marketing schedules specials tickets
transports travels
Example:
/v1/group/events?extend=contacts,lineup,tickets&startDate=2026-01-01
When extend includes contacts, booking-level
bookings[].contacts lists all contacts; the same rows are also grouped
under bookings[].itinerary in artistCareContacts,
promoterContacts, technicalContacts, and
otherContacts (see
Output: Itinerary). Other categories only add
data under bookings[].itinerary.
bookings[].itinerary is always present. extend controls which
slices are populated. Unrequested lists are [], unrequested scalars are
null, and has* flags are false. Core booking
fields (fee, play times, operational period, status) are always present when the API key
has access to the booking. bookings[].deal is included on the same
responses when deal rights allow it; otherwise it is null. It is not an
extend category.
GET serialization: stored values (including empty string '') are returned
as-is; empty lists stay []; null or missing scalars are JSON
null. Keys are not omitted.
Write operations
All write requests use Content-Type: application/json and the same Bearer
API key as GET. Updates use POST on the resource path (not PATCH).
Deletes use DELETE and soft-delete records (events, contacts, venues
remain in the database with a deleted status).
Create — POST /v1/group/{resource} → 201:
{ "data": { "id": "…", "slug": "…" } }
Update — POST /v1/group/{resource}/:id →
200 (same response shape).
Delete — DELETE /v1/group/{resource}/:id →
200:
{ "data": { "success": true } }
Event writes
Create requires title, startDate (YYYY-MM-DD),
and bookings with exactly one object containing artistId. The
API maps description to the stored public description. Optional event
fields include bookingCapacity, doors (HH:mm),
endDate, eventType,
internalComment, venueId, and website (ApiEventInput
also lists optional nested venue in TypeScript types; the HTTP API accepts
venueId only). Ticket sales belong under
bookings[0].itinerary.tickets. Event-root tickets on GET is
deprecated (see Output: Event).
bookingCapacity is the show capacity and is separate from
venue.capacity. Uncaptured ticket sales and capacities are
null (unknown), never 0.
endDate must be on or after startDate (returns
400 otherwise). Calendar dates must be real YYYY-MM-DD days.
2026-02-30 returns 400 with
startDate 2026-02-30 is not a valid calendar date (the same shape is used
for endDate, the operational period, and itinerary dates). Create does not
insert a booking. An update that includes an invalid date does not change the existing
booking, even when the same request also sends valid fields. Soft-deleted events cannot
be updated (returns 404).
eventType is the stored Optune event type label (for example
Festival or Club Show). It is a free-form string, separate
from GET type (the event document type, such as
Simple Booking or Manager Booking). Omit
eventType to leave it unset on create and unchanged on update.
null clears it. GET always includes it; null means unset.
bookings[0].internalAgencyComment is the internal agency note. GET list
and detail return it only when the key has read:internalComment; otherwise
the field is null. read:deal does not grant that read, and
write:internalComment does not grant it either. Setting, changing, or
clearing the note requires write:internalComment as well as
write:events. A request that includes the field without that scope returns
400 and leaves the event unchanged. Omit the field to leave the stored
note unchanged. null or "" clears it when the key may write
it. Event internalComment and booking internalComment are
separate notes and are not gated by these scopes.
venueId may reference a non-deleted venue the API key's group belongs to,
including a private venue. A public venue owned by another group
(visibility public, GET isPublic: true) can be
used only when it is active and Optune-verified (verifiedAt is set). A
private venue owned by another group is rejected (400). A public venue
that is not verified and is owned by another group is rejected the same way. Creating
a venue always stores visibility: private. This API does not create public
or verified venues. GET /v1/group/venues returns venues where the group is
owner, manager, or viewer, and does not export the verified directory. Updating a venue
requires the group to be owner or manager on that venue. GET isVerified is
true only when both verifiedAt and verifiedBy are set.
Update is partial: only fields present in the JSON are changed;
null clears optional values; omitted fields are unchanged. The body must
include bookings as an array of exactly one object (use
bookings: [{}] when only updating top-level event fields). Do not send
null for required booleans such as isPublished. Itinerary
lists are replaced in full when present (see
Updating itinerary lists).
Send bookings[0].itinerary.tickets: [] or
tickets: null to clear all ticket categories.
Changes to ticket sales, marketing materials, or bookingCapacity update
the event updatedAt timestamp. Itinerary
contact lists accept inline contact objects or
{ "contactId": "…" } references.
sequenceNr on itinerary lists (read-only on write): On
GET, list rows under bookings[].itinerary (for example
schedules, lineup, guestList,
flights, hotels, travels,
transports, specials, marketing.materials,
tickets) include sequenceNr for display order. You
cannot set or update sequenceNr via POST — it is ignored
if sent. On create and update, the server assigns sequenceNr automatically
from the array order (first item = 1, second = 2, and so on). To reorder rows, send the
full list in the desired order. See Updating itinerary lists.
Contact & venue writes
Contact create requires name or company (at
least one — not both). Venue create requires name, city, and
country; capacity must be an integer ≥ 0 when set (same on GET
and POST). Optional venueType is a string array of free-form labels (same on
GET and POST). Contact and venue updates accept any subset of writable fields. Soft-deleted
contacts and venues cannot be updated (returns 404).
Updating itinerary lists
Event updates are partial at the field level: itinerary keys you omit are left unchanged.
Every itinerary list row includes _id on GET (flights,
guest list, hotels, lineup, schedules, specials, tickets, transports, travels,
marketing materials). On POST, optional _id keeps that stored id.
Sending a list field stores that array as-is. Tickets, marketing
materials, schedules, flights, and the other itinerary lists all replace in full.
Optional _id keeps the stored row id; omit _id to create a
new id. GET the current list, then POST the complete array. Rows you omit are removed.
Lists that follow the full-replace rule:
flights guestList hotels lineup marketing.materials marketing.receiverContacts
schedules specials tickets transports travels
[] or null on a list field clears it. Scalar itinerary fields
(notes, guestListSpotCount, custom) still update
independently. Contact category lists
(artistCareContacts, promoterContacts,
technicalContacts, otherContacts) replace the categories you
send; include every category you want to keep when replacing contacts.
Replace the full ticket list (include _id to keep a
stored ticket id; omitted rows are removed):
{ "bookings": [{ "itinerary": { "tickets": [{ "_id": "ticketId", "description": "GA",
"price": 35, "priceCurrency": "CHF", "sales": 40, "status": "tickets" }, {
"description": "VIP", "price": 80, "priceCurrency": "CHF", "sales": 2, "status":
"tickets" }] } }] }
Replace schedules (any schedule not in this array is deleted):
{ "bookings": [{ "itinerary": { "schedules": [{ "text": "Soundcheck", "date":
"2026-09-01", "time": "16:00" }, { "text": "Doors", "date": "2026-09-01", "time":
"19:00" }] } }] }
Input vs output schemas
The protected API uses different JSON shapes for requests (POST
create/update) and responses (GET list/detail). OpenAPI lists them separately:
ApiEventWriteInput / ApiEventItem,
ApiContactWriteInput / ApiContactItem, and so on.
| Resource | Input (POST body) | Output (GET data[] / data) |
|---|---|---|
| Artists | — | Output only (no write endpoints) |
| Events | Input: Event + Itinerary |
Output: Event +
Itinerary (extend)
|
| Contacts | Input: Contact | Output: Contact |
| Venues | Input: Venue | Output: Venue |
Typical output-only fields (present on GET, not accepted on POST):
document ids (_id), slug, version,
updatedAt, status flags (eventStatus, isDeleted,
…), aggregated fees, denormalized artist names, nested venue objects (use
venueId on write), itinerary has* flags and
sequenceNr, event artwork / attachments, and
venue logo / attachments.
Input: Event (POST create / update)
Request body for POST /v1/group/events and
POST /v1/group/events/:id. Validated by ApiEventSchema /
ApiEventUpdateSchema, ApiBookingSchema, and
ApiItinerarySchema. This is not the same object returned
by GET — see Output: Event.
Event-level fields
| Field | Create | Update | Type | Description |
|---|---|---|---|---|
title |
required | optional | string | Event title. |
startDate |
required | optional | YYYY-MM-DD |
First event day. Must be a real calendar date.
2026-02-30 returns 400 and does not create or change a
booking.
|
bookings |
required | required | array (1 item) |
Exactly one booking object; use [{}] for top-level-only updates.
|
description |
optional | optional | string | null | Public description (null clears on update). |
doors |
optional | optional | string (HH:mm) |
Doors-open time; stored on the event item. |
endDate |
optional | optional | YYYY-MM-DD | null |
Must be a real calendar date and ≥ startDate. An impossible day such
as 2026-02-30 returns 400.
|
eventType |
optional | optional | string | null |
Stored Optune event type label, such as Festival. Not the GET
type enum. Omit to leave it unset on create or unchanged on update.
null clears it.
|
bookingCapacity |
optional | optional | string | null |
Show capacity for this booking, separate from venue.capacity. Empty /
unknown is null, not 0.
|
internalComment |
optional | optional | string | null |
Internal event note. Not gated by read:internalComment /
write:internalComment.
|
venueId |
optional | optional | string | null | Existing venue id for this API key; null clears on update. |
website |
optional | optional | string | null | Public website URL. |
Booking fields (bookings[0])
| Field | Create | Update | Type | Description |
|---|---|---|---|---|
artistId |
required | — | string | Artist id for the lineup slot. |
internalAgencyComment |
optional | optional | string | null |
Internal agency note. Write requires write:internalComment in
addition to write:events. Without it the request returns
400 and the event stays unchanged. Read requires
read:internalComment.
|
internalComment |
optional | optional | string | null |
Booking internal comment. Not gated by read:internalComment /
write:internalComment.
|
isPublished |
optional | optional | boolean | Cannot be null. |
itinerary |
optional | optional | ApiItineraryInput |
See Input: Itinerary.
null clears on update.
|
operationalPeriod |
optional | optional | ApiBookingOperationalPeriodInput | null |
startDate, startTime, endDate,
endTime (YYYY-MM-DD / HH:mm).
|
playDuration |
optional | optional | string | null | Play duration label. |
playEndTime |
optional | optional | string (HH:mm) | null |
Play end time. |
playStartTime |
optional | optional | string (HH:mm) | null |
Play start time. |
status |
optional | optional | string |
One of idea, pending, confirmed,
declined, or canceled.
|
statusCommentCanceled |
optional | optional | string | null | Cancellation reason when status is canceled. |
Itinerary (bookings[0].itinerary)
Optional object typed as ApiItineraryInput on POST. Field-level reference:
Input: Itinerary. GET response uses
ApiItineraryItem — see
Output: Itinerary.
Not in POST body (GET only on events/bookings): _id,
slug, version, updatedAt, type,
eventStatus, artwork, attachments,
fee, feeCurrency, managerFee,
managerFeeCurrency, isCanceled,
isClosed, isDeleted, isOk, nested
venue (use venueId), booking _id,
artistName, artistSlug, deal, fee,
feeCurrency, playStartDate, playEndDate,
contacts[], itinerary has* flags and row
sequenceNr.
Input: Itinerary (ApiItineraryInput, POST)
Nested under bookings[0].itinerary on event create/update. Validated by
ApiItinerarySchema. List rows use the typed inputs below; contact lists
accept ApiContactInput (inline) or ApiContactRefInput ({ "contactId": "…" }). On update, each list you send replaces the stored list in full — see
Updating itinerary lists.
Not writable: has* flags,
sequenceNr (assigned from array order on save). Every itinerary list
row accepts optional _id on POST (always returned on GET). Dates:
YYYY-MM-DD;
times: HH:mm where validated.
Top-level (ApiItineraryInput)
| Field | Type | Description |
|---|---|---|
artistCareContacts |
ApiContactInput | ApiContactRefInput[] |
Artist care contacts. |
artistCareContactsNotes |
string | null | Notes for artist care. |
custom |
object | null | teamConstellation (string | null). |
flights |
ApiItineraryFlightInput[] |
Flight rows. |
guestList |
ApiItineraryGuestListInput[] |
Requires name per row. |
guestListSpotCount |
number | null | Total guest list spots. |
hotels |
ApiItineraryHotelInput[] |
Hotel rows. |
lineup |
ApiItineraryLineupInput[] |
Requires name per row. |
marketing |
ApiItineraryMarketingWrite |
Nested marketing object. materials: freely defined rows with
optional _id, description (required),
type (text |
count | choice), value.
receiverContacts: marketing delivery contacts (Lieferkontakt) as a
list of inline ApiContactInput or
{ "contactId": "…" }. Both arrays are full-replace on update.
sequenceNr on materials is assigned from array order.
|
otherContacts |
ApiContactInput | ApiContactRefInput[] |
Other contacts. |
otherContactsNotes |
string | null | Notes for other contacts. |
promoterContacts |
ApiContactInput | ApiContactRefInput[] |
Promoter / client contacts. |
promoterContactsNotes |
string | null | Notes for promoter contacts. |
schedules |
ApiItineraryScheduleInput[] |
Requires text per row. |
specials |
ApiItinerarySpecialInput[] |
Special rows. |
technicalContacts |
ApiContactInput | ApiContactRefInput[] |
Technical contacts. |
technicalContactsNotes |
string | null | Notes for technical contacts. |
tickets |
ApiItineraryTicketsInput[] |
Ticket sales rows. Optional _id on update (see
Updating itinerary lists).
|
transports |
ApiItineraryTransportInput[] |
Ground transport rows. |
travels |
ApiItineraryTravelInput[] |
Requires travelType per row. |
ApiItineraryTicketsInput
Optional _id, currency, description,
isSoldOut, link,
notes, price, priceCurrency, sales,
soldOut,
status. Uncaptured sales and
price are null, never 0.
sequenceNr is assigned from array order. Optional _id keeps
the stored row id; omitted rows are removed.
ApiItineraryMarketingInput /
ApiItineraryMarketingWrite
Material row: optional _id, description (required), type
(text, count, choice), value
(number for count, boolean for choice, string for
text). sequenceNr is assigned from array order. Nested under
itinerary.marketing.materials. Delivery contacts are a list at
itinerary.marketing.receiverContacts (inline contact or
{ "contactId": "…" }). Both materials and
receiverContacts replace the stored list when sent. GET returns the same
list as itinerary.marketing.receiverContacts (empty list
[]).
List row types (optional fields unless noted)
ApiItineraryFlightInput: optional _id,
arrivalAirport,
arrivalTime, departureAirport, departureTime,
flightDate, flightNr, notes,
passengerName, reservationCode.
ApiItineraryGuestListInput: name (required),
optional _id, comment, spotCount.
ApiItineraryHotelInput: optional _id,
hotelName,
hotelAddress, hotelBookingNr, check-in/out dates and times,
hotelCheckoutLate, hotelEmail, hotelNotes,
hotelPhoneNr, hotelWebsite, singleRoom,
doubleRoom.
ApiItineraryLineupInput: name (required),
optional _id, playStartDate, playStartTime,
playEndDate,
playEndTime.
ApiItineraryScheduleInput: text (required),
optional _id, date, time, endDate,
endTime.
ApiItinerarySpecialInput: optional _id,
title,
description.
ApiItineraryTransportInput: optional _id,
transportCompany,
transportDriverName, transportDriverPhoneNr,
transportDropOffLocation, transportNotes,
transportPickUpDate, transportPickUpLocation,
transportPickUpTime, transportTaxiNr.
ApiItineraryTravelInput:
travelType (required), optional _id, departure/arrival locations, dates, times,
travelBookingNr, travelNr, travelPassengerName,
travelNotes, travelWebsite.
Input: Contact (POST create / update)
Request body for POST /v1/group/contacts and
POST /v1/group/contacts/:id (ApiContactInput /
ApiContactSchema). Not the same as
Output: Contact. Phones:
phoneNr (primary/mobile), phoneNrOther (secondary/landline).
otherPhoneNr was renamed to phoneNrOther.
| Field | Create | Update | Type | Description |
|---|---|---|---|---|
name |
required* | optional | string | *Required unless company is set. |
company |
required* | optional | string | null | *Required unless name is set. |
addressLine1 |
optional | optional | string | null | Address line 1. |
addressLine2 |
optional | optional | string | null | Address line 2. |
billingAddress |
optional | optional | object | null |
Separate billing address (Rechnungsadresse). Omit on update to leave it
unchanged. null removes it. Fields below.
|
city |
optional | optional | string | null | City. |
contactNr |
optional | optional | string | null | Contact or reference number. |
country |
optional | optional | string | null | Country. |
email |
optional | optional | string | null | Email. |
language |
optional | optional | string | null | Preferred language. |
notes |
optional | optional | string | null | Notes. |
otherLink |
optional | optional | string | null | Additional URL. Omit on update to leave stored additional links unchanged. |
phoneNr |
optional | optional | string | null | Primary / mobile phone (stored as mobilePhoneNr). |
phoneNrOther |
optional | optional | string | null |
Secondary / landline phone (stored as phoneNr). Replaces
otherPhoneNr.
|
position |
optional | optional | string | null | Role or job title. |
postalCode |
optional | optional | string | null | Postal code. |
state |
optional | optional | string | null | State or region. |
contactType |
optional | optional | string | null | Contact category (stored as contactType; same name on GET). |
vatNr |
optional | optional | string | null | VAT number. |
website |
optional | optional | string | null |
Website URL. Omit on update to leave the stored website unchanged. Additional
links and other stored links stay when website and
otherLink are omitted.
|
Billing address (billingAddress)
Separate billing address on create and update. Same fields are returned by
GET /v1/group/contacts and GET /v1/group/contacts/:id.
On update, only billing fields present in the object change. null clears
that field and leaves the others. null for billingAddress
itself removes the address (GET then returns null). Clearing the last
stored field does the same. An empty string is ignored, the same as omitting the
field. This uses the existing write:contacts scope and the same contact
edit rights as other contact fields.
| Field | Create | Update | Type | Description |
|---|---|---|---|---|
addressLine1 |
optional | optional | string | null | Billing address line 1. |
addressLine2 |
optional | optional | string | null | Billing address line 2. |
city |
optional | optional | string | null | Billing city. |
company |
optional | optional | string | null | Billing company. |
country |
optional | optional | string | null | Billing country. |
name |
optional | optional | string | null | Billing name. |
postalCode |
optional | optional | string | null | Billing postal code. |
state |
optional | optional | string | null | Canton, state, or region. |
Not in POST body (GET only): _id, slug,
version, updatedAt, createdAt,
agencyId, artistId,
additionalInfo, additionalNotes, isDeleted,
mobilePhoneNr (deprecated on GET).
Input: Venue (POST create / update)
Request body for POST /v1/group/venues and
POST /v1/group/venues/:id (ApiVenueInput /
ApiVenueSchema). Not the same as
Output: Venue. Create requires
name, city, and country (strings). Update treats
those as optional. capacity is an integer ≥ 0. The created venue is always
private (visibility: private, isPublic: false). Public and
verified flags are not writable.
| Field | Create | Update | Type | Description |
|---|---|---|---|---|
name |
required | optional | string | Venue name. |
city |
required | optional | string | City. |
country |
required | optional | string | Country. |
capacity |
optional | optional | integer | null | Capacity as integer ≥ 0 (same type on GET). |
description |
optional | optional | string | null | Description. |
email |
optional | optional | string | null | Email. |
phoneNr |
optional | optional | string | null | Phone number. |
postalCode |
optional | optional | string | null | Postal code. |
streetName |
optional | optional | string | null | Street name (stored in location components). |
streetNumber |
optional | optional | string | null | Street number. |
venueType |
optional | optional | string[] | null |
Free-form venue type labels (e.g. ClubHall,
OpenAirStage). Same type on GET; omitted or empty clears on update
when sent as [].
|
website |
optional | optional | string | null | Website URL. |
Not in POST body (GET only): _id, slug,
version, updatedAt,
street, locality,
localityFull, logo, attachments,
map, placeId,
status, type, visibility, isPlace,
isPublic, isVerified, isDeleted.
List Artists
Scope: read:artists
Query: limit, offset, name,
updatedSince
Sync filter: createdAt OR updatedAt >= updatedSince
Get Artist by ID
Scope: read:artists
Path params: id
List Events
Scope: read:events
Query: limit, offset, artist,
startDate, endDate, eventId,
includeCanceled, includeDeleted, updatedSince,
extend
Filters: artist is optional — pass the artist
slug (e.g. my-artist), not the MongoDB _id;
scoped to the API key. updatedSince is optional; endDate is
only valid when startDate is provided. extend selects
itinerary slices on each booking (see Event extend query).
By default, canceled bookings and events with eventStatus
canceled are included; pass includeCanceled=false,
0, or no to exclude them. Soft-deleted events are excluded
from the list by default; pass includeDeleted=true, 1, or
yes to include them (isDeleted: true).
updatedSince without startDate includes past
events changed since that timestamp.
Date behavior: If no startDate is set, the response
includes all future events starting today. Example: /v1/group/events
To include past events, provide a startDate. Example:
/v1/group/events?startDate=2025-01-01
If both startDate and endDate are set, the response is limited
to events within that date range. Example:
/v1/group/events?endDate=2025-12-31&startDate=2025-01-01
Get Event by ID
Scope: read:events
Query: extend (same as list events)
Path params: id
Returns one event object (Output: Event); same shape
as list items. Canceled and soft-deleted events are always included on the
single-event endpoint (isCanceled / isDeleted).
Create Event
Scope: write:events
Body: Request schema Input: Event (not the GET event shape). Summary: Write operations.
Response: 201 with data.id and
data.slug.
Update Event
Scope: write:events
Path params: id (event id)
Body: Input: Event (partial update). Do not send GET-only fields from Output: Event.
Response: 200 with data.id and
data.slug.
Examples
GET tickets, marketing, and capacities
(extend=tickets,marketing):
{ "data": { "_id": "eventId", "bookingCapacity": "Seated 120", "isCanceled": false,
"isDeleted": false, "updatedAt": "2026-08-13T10:00:00.000Z", "venue": { "_id":
"venueId", "name": "Hall", "capacity": 1500, "isVerified": true }, "bookings": [{
"itinerary": { "marketing": { "materials": [{ "_id": "fieldId", "description": "A3 posters",
"type": "count", "sequenceNr": 1, "value": 50 }], "receiverContacts": [{ "name":
"Delivery Contact", "company": "Promo GmbH", "addressLine1": "Lagerstrasse 1", "postalCode":
"8005", "city": "Zurich", "country": "CH", "email": "delivery@promo.ch", "phoneNr":
"+41000000001" }] },
"tickets": [{ "_id": "ticketId", "description": "GA", "sales": 25, "price": 35,
"priceCurrency": "CHF", "status": "tickets", "isSoldOut": false, "sequenceNr": 1 }] } }]
} }
POST create with ticket category and show capacity:
{ "title": "Openair", "startDate": "2026-09-01", "bookingCapacity": "Seated 120",
"bookings": [{ "artistId": "artistId", "itinerary": { "tickets": [{ "description": "GA",
"price": 35, "priceCurrency": "CHF", "status": "tickets" }] } }] }
POST /:id replace the full ticket list (include _id to
keep a stored ticket id; omitted rows are removed):
{ "bookings": [{ "itinerary": { "tickets": [{ "_id": "ticketId", "description": "GA",
"sales": 40, "price": 35, "priceCurrency": "CHF" }, { "description": "VIP", "price":
80, "priceCurrency": "CHF", "sales": 2 }] } }] }
POST /:id replace marketing materials and delivery contacts:
{ "bookingCapacity": "Standing 400", "bookings": [{ "itinerary": {
"marketing": { "materials": [{ "_id": "fieldId", "description": "A3 posters", "type":
"count", "value": 80 }, { "description": "Instagram ads", "type": "choice", "value":
true }], "receiverContacts": [{ "contactId": "contactId" }] } } }] }
Delete Event
Scope: write:events
Path params: id
Soft-deletes the event. Response: 200 with
data.success: true.
List Contacts
Scope: read:contacts
Query: limit, offset, name,
updatedSince
Sync filter: createdAt OR updatedAt >= updatedSince
Get Contact by ID
Scope: read:contacts
Path params: id
Create Contact
Scope: write:contacts
Body: Input: Contact —
name or company required. Optional
billingAddress sets the separate billing address.
Response: 201 with data.id and
data.slug.
Update Contact
Scope: write:contacts
Path params: id
Body: Input: Contact (partial; not
the GET contact object). billingAddress: null removes the billing
address. null on a billing field clears that field only.
Response: 200 with data.id and
data.slug.
Delete Contact
Scope: write:contacts
Path params: id
Soft-deletes the contact. Response: 200 with
data.success: true.
List Venues
Scope: read:venues
Query: limit, offset, name,
updatedSince
Sync filter: createdAt OR updatedAt >= updatedSince
Get Venue by ID
Scope: read:venues
Path params: id
Create Venue
Scope: write:venues
Body: Input: Venue —
name, city, country required.
Response: 201 with data.id and
data.slug.
Update Venue
Scope: write:venues
Path params: id
Body: Input: Venue (partial; not the GET venue object).
Response: 200 with data.id and
data.slug.
Delete Venue
Scope: write:venues
Path params: id
Soft-deletes the venue. Response: 200 with
data.success: true.
Output: Artist (GET)
Response shape for GET /v1/group/artists and
GET /v1/group/artists/:id (ApiArtistItem).
Read-only — there are no artist write endpoints. See
Input vs output schemas.
| Field | Type | Description |
|---|---|---|
_id |
string | Artist id. |
appleMusic |
string | undefined | Apple Music URL when set. |
attachments |
object[] | Attachments except profile picture. See artist attachment object. |
backgroundColor |
string | undefined | Agency-specific listing color when configured. |
biography |
string | undefined | Long biography text. |
description |
string | undefined | Short description or intro. |
facebook |
string | undefined | Facebook URL. |
genres |
string[] | Genre names. |
instagram |
string | undefined | Instagram URL. |
musicLabel |
string | undefined | Label name when set. |
name |
string | Display name. |
onescreener |
string | undefined | Onescreener URL when set. |
otherLink |
string | undefined | Additional link. |
profilePicture |
string | undefined | Profile image URL when set. |
settings |
object | undefined | Agency commission settings when configured. |
slug |
string | URL slug. |
soundcloud |
string | undefined | SoundCloud URL. |
soundLink |
string | undefined | Generic audio link when set. |
spotify |
string | undefined | Spotify URL. |
tikTok |
string | undefined | TikTok URL when set. |
types |
string[] | Artist types (extended types when present). |
updatedAt |
string | Last change time (ISO 8601). |
version |
number | Document version. |
website |
string | undefined | Website URL. |
x |
string | undefined | X/Twitter URL. |
youTube |
string | undefined | YouTube URL. |
Artist attachment object (attachments[])
| Field | Type | Description |
|---|---|---|
category |
string | Attachment category. |
fileUrl |
string | undefined | URL of the file. |
Output: Contact (GET)
Response shape for contact list/detail (ApiContactItem). Differs from
Input: Contact — many fields below are
server-managed or mapped only on read. Writable fields on POST are listed in the input
section.
GET-only (not in POST body): _id, slug,
version, updatedAt, createdAt,
agencyId, artistId,
additionalInfo, additionalNotes, isDeleted.
Writable on POST: same fields as
Input: Contact (including
contactType and position). Phones:
phoneNr (primary/mobile), phoneNrOther (secondary/landline).
mobilePhoneNr is deprecated on GET (duplicate of
phoneNr).
| Field | Type | Description |
|---|---|---|
_id |
string | Contact id. |
company |
string | null | Company name when set. |
additionalInfo |
string | null | Extra info text when set. |
additionalNotes |
string | null | Additional notes when set. |
addressLine1 |
string | null | Address line 1. |
addressLine2 |
string | null | Address line 2. |
agencyId |
string | null | Owning agency id when set. |
artistId |
string | null | Related artist id when set. |
billingAddress |
object | null |
Separate billing address when set; null when none. When present,
every field is included: addressLine1, addressLine2,
city, company, country, name,
postalCode, state (each string | null).
Writable on POST — see Input: Contact.
|
city |
string | null | City. |
contactNr |
string | null | Contact or reference number. |
contactType |
string | null | Category label. |
country |
string | null | Country. |
createdAt |
string | null | Creation time (ISO 8601) when set. |
email |
string | null | Email address. |
isDeleted |
boolean | Soft-delete flag. Always present. |
language |
string | null | Preferred language when set. |
name |
string | null | Display name. |
notes |
string | null | Notes. |
otherLink |
string | null | Additional URL when set. |
mobilePhoneNr |
string | null |
Deprecated. Same value as phoneNr; use
phoneNr instead.
|
phoneNr |
string | null | Primary / mobile phone (from stored mobilePhoneNr). |
phoneNrOther |
string | null | Secondary / landline phone (from stored phoneNr). |
position |
string | null | Role or job title. |
postalCode |
string | null | Postal code. |
slug |
string | null | URL slug. |
state |
string | null | State or region. |
updatedAt |
string | null | Last change time (ISO 8601). |
vatNr |
string | null | VAT number. |
version |
number | null | Document version. |
website |
string | null |
Website URL from the stored website link. A contact update that omits
website and otherLink leaves this and any additional
links unchanged.
|
Output: Venue (GET)
Response shape for venue list/detail (ApiVenueItem). Differs from
Input: Venue — includes map, logo, status, and
integer capacity. Street is stored as separate
streetName and streetNumber; GET also includes combined
street (this is the address line — v1.4.8 addressLine1 is
not returned). Venue files appear as logo plus
attachments (same shape as event attachments; empty list is
[]).
On events, the nested venue object uses this
shape (including Optune-verified locations used on that booking).
GET /v1/group/venues returns only the group's own venues, not the full
verified directory. On POST use venueId instead.
GET-only (not in POST body): _id, slug,
version, updatedAt,
street, locality,
localityFull, logo, attachments,
map, placeId,
status, type, visibility, isPlace,
isPublic, isVerified.
| Field | Type | Description |
|---|---|---|
_id |
string | Venue id. |
attachments |
object[] |
Venue files. Same shape as event attachments
(category, public_id, url); empty list is
[].
|
capacity |
integer | null | Capacity (integer ≥ 0). |
city |
string | null | City. |
country |
string | null | Country. |
description |
string | null | Description. |
email |
string | null | Email. |
isPlace |
boolean | Whether the venue is modeled as a place. Always present. |
isPublic |
boolean |
True when visibility is public. Private venues,
including every venue created by this API, are false.
|
isVerified |
boolean |
True only when both verifiedAt and verifiedBy are set.
A public venue can be used on another group's event only when it is verified.
|
locality |
string | null | Short locality label. |
localityFull |
string | null | Full locality string. |
logo |
object | null |
Logo file; null if none (category,
public_id, url).
|
map |
object | null | Map marker and optional viewport geometry. |
name |
string | Display name. |
phoneNr |
string | null | Phone number. |
placeId |
string | null | External place id when available. |
postalCode |
string | null | Postal code. |
slug |
string | URL slug. |
status |
string | Venue status (enum). |
street |
string | null | Street as one combined line. |
streetName |
string | null | Street name as stored in the location components. |
streetNumber |
string | null | Street number as stored in the location components. |
type |
string | Venue type (enum). |
updatedAt |
string | Last change time (ISO 8601). |
venueType |
string[] |
Free-form venue type labels. Always present; empty list is [].
|
visibility |
string |
private or public. Venues created by this API are
private. isPublic mirrors this value.
|
version |
number | Document version. |
website |
string | null | Website URL. |
Attachment object (logo)
category (string), public_id (string),
url (string).
Output: Event (GET)
Response shape for event list/detail (ApiEventItem). Differs from
Input: Event — do not round-trip a GET body into
POST. startDate and endDate are calendar dates
(YYYY-MM-DD). The lineup is bookings. Ticket sales live on
bookings[].itinerary.tickets when extend=tickets. Event-root
tickets is deprecated (legacy mirror); prefer the
itinerary path.
GET serialization: every field of the resource shape is always present. Stored values
(including empty string '') are returned as-is. Empty lists stay
[]. Missing, null, or undefined scalars are JSON
null. Keys are never omitted.
Shared with POST (same names, read back after write):
title, startDate, endDate,
bookingCapacity, description, doors,
eventType, internalComment, website, and much of
bookings[] except fields listed below.
GET-only on the event: _id, slug,
version, updatedAt, type,
eventStatus, artwork, attachments,
fee, feeCurrency, managerFee,
managerFeeCurrency, isCanceled,
isClosed, isDeleted, isOk, nested
venue (write venueId). Booking deal is also
GET-only.
| Field | Type | Description |
|---|---|---|
_id |
string | Event id. |
artwork |
object | null | Primary flyer or cover; null if none. See attachment object. |
attachments |
object[] | Further files. See attachment object. |
bookingCapacity |
string | null |
Show capacity for this booking. Separate from nested
venue.capacity. Unknown is null, not 0.
|
bookings |
object[] | Lineup. See booking object. |
description |
string | null | Public description. |
doors |
string | null | Doors or opening time label. |
endDate |
string | null | Last event day (YYYY-MM-DD) or null. |
eventStatus |
string | Event status (string enum). |
eventType |
string | null |
Stored Optune event type label, such as Festival. Writable. Always
present; null when unset. Distinct from type.
|
fee |
number | null |
Read-only sum of billable booking artist fees
(calculateTotalFee artistFee.amount). Declined and
canceled bookings are excluded. null when none are visible.
|
feeCurrency |
string | null |
Shared artistFee.currency of the bookings in fee.
null when none are visible or the currencies differ.
|
internalComment |
string | null |
Internal event note. Not gated by read:internalComment.
|
isCanceled |
boolean | Canceled flag. |
isClosed |
boolean | Closed flag. |
isDeleted |
boolean | Deleted flag. |
isOk |
boolean | OK or confirmed-style flag. |
managerFee |
number | null |
Read-only sum of billable booking total commissions
(calculateTotalFee totalCommission.amount).
null when none are visible.
|
managerFeeCurrency |
string | null |
Shared totalCommission.currency of the bookings in
managerFee. null when none are visible or the currencies
differ.
|
slug |
string | URL slug. |
startDate |
string | First event day (YYYY-MM-DD). |
tickets |
ApiTicketsItem[] |
Deprecated. Use
bookings[].itinerary.tickets (ApiTicketsItem) instead.
Not writable on POST.
|
title |
string | null | Title. |
type |
string |
Event document type, such as Simple Booking or
Manager Booking. Not the writable eventType label.
|
updatedAt |
string | Last change time (ISO 8601). |
venue |
object | null |
GET only. Nested venue when present; null otherwise.
Same shape as Output: Venue, including full
address, coordinates (map), capacity, type,
and isVerified for Optune-verified locations used on the booking.
isVerified is true only when both verifiedAt and
verifiedBy are set. isPublic is true when
visibility is public. A private venue
(visibility private) appears here only when the group
belongs to that venue. A public venue from another group appears here only when
the booking uses an active Optune-verified venue. Verified directory venues are
not listed on GET /v1/group/venues — that list is venues where the
group is owner, manager, or viewer. On POST use venueId. Venue
create always stores a private venue.
|
version |
number | Document version. |
website |
string | null | Public website URL. |
Attachment object (artwork, attachments[], venue
logo / attachments[])
| Field | Type | Description |
|---|---|---|
category |
string | Attachment category. |
public_id |
string | Stable file id. |
url |
string | File URL. |
Booking object (bookings[])
GET-only on bookings: _id, artistName,
artistSlug, deal, fee, feeCurrency,
playStartDate, playEndDate, contacts[] (always
present; populated with extend=contacts, otherwise []).
deal is the mapped Optune deal, or null when deal data is
hidden.
Writable booking fields: see
Input: Event.
| Field | Type | Description |
|---|---|---|
_id |
string | Booking id. |
artistId |
string | Artist id. |
artistName |
string | Artist name. |
artistSlug |
string | Artist slug. |
contacts |
object[] | See booking contact object. |
deal |
ApiDealItem | null |
Mapped Optune deal for this booking: currency,
artistFeeGuaranteed, artistFeeAdditional,
artistFeeExpenses, agencyCommission,
managerCommission, otherCommission, stored
dealType (or null), and calculated
total. Guaranteed and additional fees include amount, currency,
note, and payment fields. They omit feeDescription,
afterCommissions, and vat, plus
feeType, label, hint,
percentage, inclusive, isFixAmount, and
isSubtotalCommission. Expenses add afterCommissions and
still omit feeDescription and vat. Commissions include
percentage and vat, plus inclusive,
isFixAmount, and isSubtotalCommission. Commission
amount is the stored amount when isFixAmount is true,
and null for a percentage commission. feeDescription is
only on
otherCommission. Commission lines omit feeType,
label, hint, and afterCommissions.
Calculated commission amounts stay on total.commissions
(agency commission, manager commission,
other commission) and total.totalCommission. Commission
VAT is calculated into total (for example totalFee.vat
and commissionVAT). Every total amount has percentage
(a number, or null) and percentageCommissionType
(single commission, or various commissions when
commission VAT rates are mixed). Mixed rates on
total.commissionVAT and total.commissionOnSubtotalVAT
use percentage: null and
percentageCommissionType: "various commissions".
total.totalFee, total.artistFee, and
total.expenses carry amount and currency and omit
label and hint. Same visibility as
fee: API key read:deal, plus member or manager deal
rights (including per-artist visibility). Hidden deal data is null.
Not controlled by extend.
|
fee |
number | null |
Read-only artist fee, deal.total.artistFee.amount from
calculateTotalFee. Not the stored booking fee.
null when the deal is hidden or not loaded. Requires
read:deal and the same deal rights as deal.
|
feeCurrency |
string | null |
Currency of fee, deal.total.artistFee.currency.
null when the deal is hidden or not loaded.
|
internalAgencyComment |
string | null |
Internal agency note. null unless the key has
read:internalComment. read:deal does not reveal it.
|
internalComment |
string | null |
Booking internal comment. Not gated by read:internalComment.
|
isPublished |
boolean | Published flag. |
itinerary |
ApiItineraryItem |
Always present. extend fills category data; other slices are
[] / null. See
Output: Itinerary.
|
managerFee |
number | null |
Read-only total commission, deal.total.totalCommission.amount from
calculateTotalFee. Not the stored booking managerFee.
null when the deal is hidden or not loaded.
|
managerFeeCurrency |
string | null |
Currency of managerFee,
deal.total.totalCommission.currency. null when the deal
is hidden or not loaded.
|
operationalPeriod |
object | null | Operational window when any part is set. See operational period object. |
playDuration |
string | null | Play duration label. |
playEndDate |
string | null | Play end date in UTC (YYYY-MM-DD) or null. |
playEndTime |
string | null | End time label. |
playStartDate |
string | null | Play date in UTC (YYYY-MM-DD) or null. |
playStartTime |
string | null | Start time label. |
status |
string |
idea, pending, confirmed,
declined, or canceled.
|
statusCommentCanceled |
string | null | Cancellation reason or comment when the booking is canceled. |
Operational period (ApiBookingOperationalPeriodInput on POST; same fields
on GET)
| Field | Type | Description |
|---|---|---|
endDate |
string | null | End date (YYYY-MM-DD, UTC). |
endTime |
string | null | End time (HH:mm, UTC). |
startDate |
string | null | Start date (YYYY-MM-DD, UTC). |
startTime |
string | null | Start time (HH:mm, UTC). |
Booking contact object (ApiBookingContactItem)
On bookings[].contacts[] when extend=contacts, and on
bookings[].itinerary.{artistCareContacts,promoterContacts,technicalContacts,otherContacts}. Same fields as
Output: Contact
(ApiContactItem), plus itinerary category.
phoneNr = mobile; phoneNrOther = landline.
otherPhoneNr is not used on this shape.
| Field | Type | Description |
|---|---|---|
category |
string | Extra vs Output: Contact. Itinerary contact category (artist care, promoter, technical, other). |
Output: Itinerary (ApiItineraryItem, GET)
On bookings[].itinerary. Typed as ApiItineraryItem in
types/api.data.types.ts. POST uses
Input: Itinerary (ApiItineraryInput)
— not this shape.
Every itinerary field is always present. extend populates matching slices;
unrequested lists are [], scalars are null,
has* flags are false. Empty string '' is kept.
Nested list rows include every property; unused values are null.
GET-only: all has* flags; list row
sequenceNr (assigned from array order). Every itinerary list row always
includes _id (flights, guest list, hotels, lineup, marketing materials,
schedules, specials, transports, travels, and tickets).
Top-level (ApiItineraryItem)
| Field | Type | Description |
|---|---|---|
hasContacts |
boolean | Always boolean. true with extend=contacts when contacts exist; otherwise false. |
hasCustom |
boolean | Always boolean. true with extend=custom when custom data exists; otherwise false. |
hasFlights |
boolean | Always boolean. true with extend=flights when flights exist; otherwise false. |
hasGuestList |
boolean | Always boolean. true with extend=guestList when guest list exists; otherwise false. |
hasHotel |
boolean | Always boolean. true with extend=hotels when hotels exist; otherwise false. |
hasItinerary |
boolean | Always boolean. true when any extended slice is loaded; otherwise false. |
hasLineup |
boolean | Always boolean. true with extend=lineup when lineup exists; otherwise false. |
hasMarketingMaterials |
boolean | Always boolean. true with extend=marketing when marketing exists; otherwise false. |
hasSchedules |
boolean | Always boolean. true with extend=schedules when schedules exist; otherwise false. |
hasSpecials |
boolean | Always boolean. true with extend=specials when specials exist; otherwise false. |
hasTickets |
boolean | Always boolean. true with extend=tickets when tickets exist; otherwise false. |
hasTransport |
boolean | Always boolean. true with extend=transports when transports exist; otherwise false. |
hasTravels |
boolean | Always boolean. true with extend=travels when travels exist; otherwise false. |
artistCareContacts |
ApiBookingContactItem[] |
Always present. Populated with extend=contacts; otherwise
[]. Same fields as
Output: Contact plus
category.
|
artistCareContactsNotes |
string | null | Artist care notes. |
custom |
object |
Always present: { teamConstellation: string | null }.
|
flights |
FlightItem[] |
Same fields as ApiItineraryFlightInput +
_id (always present), sequenceNr. Always present as
[] when empty or not
extended. Each row includes every property; unused values are null.
|
guestList |
GuestListItem[] |
Same as input + _id (always present), sequenceNr,
addedAt, addedBy. Always [] when empty or
not extended. Each row includes every property; unused values are
null.
|
guestListSpotCount |
number | null | Total spots. |
hotels |
HotelItem[] |
Same as ApiItineraryHotelInput +
_id (always present), sequenceNr. Always
[] when empty or not extended. Each
row includes every property; unused values are null.
|
lineup |
LineupItem[] |
Same as input + _id (always present), sequenceNr. Always
[] when empty or not extended. Each row includes every property;
unused values are null.
|
marketing |
ApiItineraryMarketing |
Always present. Empty state: materials: [],
receiverContacts: []. materials rows include every
property (_id, description, type
(text | count | choice),
sequenceNr, value); unused values are
null. GET returns marketing delivery contacts as
receiverContacts (full ApiContactItem list). POST writes
the same list as
receiverContacts (see
Input: Itinerary).
|
otherContacts |
ApiBookingContactItem[] |
Always present. Populated with extend=contacts; otherwise
[]. Same fields as
Output: Contact plus
category.
|
otherContactsNotes |
string | null | Other contacts notes. |
promoterContacts |
ApiBookingContactItem[] |
Always present. Populated with extend=contacts; otherwise
[]. Same fields as
Output: Contact plus
category.
|
promoterContactsNotes |
string | null | Promoter notes. |
schedules |
ScheduleItem[] |
Same as input + _id (always present), sequenceNr. Always
[] when empty or not extended. Each row includes every property;
unused values are null.
|
specials |
SpecialItem[] |
Same as input + _id (always present), sequenceNr. Always
[] when empty or not extended. Each row includes every property;
unused values are null.
|
technicalContacts |
ApiBookingContactItem[] |
Always present. Populated with extend=contacts; otherwise
[]. Same fields as
Output: Contact plus
category.
|
technicalContactsNotes |
string | null | Technical notes. |
tickets |
ApiTicketsItem[] |
Always present as [] when empty or not extended. Each row includes
every property (_id, description, sales
(sold count; null if uncaptured), price,
priceCurrency, status, link,
notes, isSoldOut, sequenceNr); unused
values are null.
|
transports |
TransportItem[] |
Same as input + _id (always present), sequenceNr. Always
[] when empty or not extended. Each row includes every property;
unused values are null.
|
travels |
TravelItem[] |
Same as input + _id (always present), sequenceNr. Always
[] when empty or not extended. Each row includes every property;
unused values are null.
|
Edge cases & validation notes
-
Event dates:
endDatemust be on or afterstartDateon create and update (returns400; no silent clamp). -
Uncaptured numbers: missing ticket
salesand missing show/venue capacity arenull(unknown), never0. -
Venue
capacity: integer ≥ 0 on POST and GET (e.g.250, not"250"). Unknown venue capacity isnull. -
Venue
venueType: optional string array of free-form labels on POST. On GET the field is always present (empty list is[]). -
Venue
nameon update:name: ""is ignored (no change);name: nullreturns400. -
Slug reuse: after DELETE, the slug stays reserved; creating a venue
with the same name may get a
-1suffix. -
Malformed JSON: invalid request bodies return
400withreason: "Invalid JSON in request body". -
Itinerary row
_id: every itinerary list row always includes_idon GET. POST accepts optional_idto keep the stored id. Resource and contact ids are unchanged. -
List
includeDeleted: default is to omit soft-deleted events. PassincludeDeleted=true,1, oryesto include them. GET by id always returns a soft-deleted event (isDeleted: true). POST update of a soft-deleted event returns404. -
Booking cancel vs event status: a canceled booking does not
automatically set
eventStatus/isCanceledon the event — check both when syncing. -
Itinerary lists: sending a list
(
tickets,schedules,marketing.materials, and similar) replaces that list as-is. Optional_idkeeps the stored row id. See Updating itinerary lists. -
Event
tickets(deprecated): root-levelticketsonApiEventItemis legacy. Read and write ticket sales viabookings[].itinerary.tickets(extend=ticketson GET;bookings[0].itinerary.ticketson POST). -
Contact phones: use
phoneNr(mobile) andphoneNrOther(landline) on POST/GET.otherPhoneNrwas renamed tophoneNrOther.mobilePhoneNron GET is deprecated (same asphoneNr).
OpenAPI
The embedded reference below points to the updated machine-readable spec: /openapi/v1.json