Eventship

Eventship API

The Eventship API lets you manage events, attendees, tickets, and more programmatically. Authenticate with your host API key.

Every error response carries its body under detail, in one of three shapes. Most give an object with a machine-readable code and a human-readable message, plus occasional extra fields. Some give a plain string. A request that fails schema validation gives an array of validation objects. Check the type of detail before reading code.

This page lists every public endpoint. The interactive reference needs JavaScript. The same reference in plain text: llms.txt.

Base URL

https://api.eventship.com

Authentication

Your host API key. Create one from your host dashboard settings.

X-API-Key: es_live_your_key_here

Endpoints

Events

GET /v1/events

List events for your host.

Returns summary data for each event (title, dates, location, capacity). Use GET /v1/events/{event_slug} for full details including sessions, speakers, and ticket types — and, for hub events that accept community submissions, pass includeCommunityEvents=true there to also get the approved community-submitted schedule (communityEvents).

NameInTypeRequiredDescription
statusquerystringoptionalFilter by event status (draft, live, cancelled)
afterquerystring (date)optionalOnly events starting on or after this date (YYYY-MM-DD)
beforequerystring (date)optionalOnly events starting on or before this date (YYYY-MM-DD)
pagequeryinteger (min 1, default 1)optional
pageSizequeryinteger (1 to 100, default 20)optional

POST /v1/events

Create a new event.

The host is automatically resolved from your API key. Provide an address to auto-geocode the location.

By default the event is created as a draft. Pass publish=true to create and publish it as live in one step — ticket sales open immediately, default reminders are created, and the host receives a notification email.

Request body: required JSON object. Unknown fields are rejected.

NameInTypeRequiredDescription
titlebodystring (1 to 500 chars)required
startDatebodystring (date-time)required
descriptionbodystringoptional
endDatebodystring (date-time)optionalWhen the event ends, in the event's timezone. Optional: omit it and the event is created lasting four hours from its start, which you can change at any time with a PATCH.
timezonebodystring (default America/Los_Angeles)optional
locationTypebodyin_person | virtual | hybrid | global (default in_person)optional
venuebodystringoptional
addressbodystringoptional
virtualLinkbodystringoptional
externalRegistrationUrlbodystringoptional
privateLocationbodyboolean (default false)optional
isPublicbodyboolean (default true)optional
showGuestListbodyboolean (default true)optional
imagebodystringoptional
bannerTemplatebodystringoptional
introductionsEnabledbodyboolean (default false)optional
sendSaveTheDatebodyboolean (default false)optional
feedbackEnabledbodybooleanoptional
enableAdsbodyboolean (default false)optional
publishbodyboolean (default false)optionalIf true, the event is published immediately as live instead of remaining a draft.

POST /v1/events/import

Import an event from an external URL.

Accepts a URL to an event page (Eventbrite, Luma, Meetup, etc.), extracts the event data, and creates a draft event on Eventship. Ticket types, sessions, and location data are imported automatically.

The event is priced in the currency the source stated, or in your host's own currency when it stated none. If the source used a currency Eventship cannot sell in, the imported prices keep their numbers and the event is created in your currency instead: message then says which currency was substituted. Check it before publishing a priced event.

A source page that states no end time produces an event ending four hours after its start, which you can change at any time with a PATCH. The page's agenda does not extend it.

The import refuses a page whose START date it cannot read. It also refuses several other things, so do not treat that as the only failure: a missing title, tickets it could parse but not price, tickets in mixed currencies, and structurally invalid tickets each return their own error code.

Request body: required JSON object. Unknown fields are rejected.

NameInTypeRequiredDescription
urlbodystringrequiredURL of the external event page to import

GET /v1/events/{event_slug}

Get event details by slug.

Hub events (events that accept community submissions) can also embed their approved community-submitted schedule: pass includeCommunityEvents=true and the response includes a communityEvents array ordered by start time. The field is null unless requested and the event is a hub. Only approved, live, public, listed events appear — the same privacy rules as the hub's public schedule page.

Each community event carries its own description and, when its host takes registrations elsewhere, externalRegistrationUrl — enough to mirror the approved schedule onto your own site without a second call per event. Those events belong to other hosts, so their descriptions are user-authored content from outside your account: sanitize before rendering as HTML.

NameInTypeRequiredDescription
event_slugpathstringrequired
includeCommunityEventsqueryboolean (default false)optionalSet true to also return the hub's approved community-submitted events as communityEvents (hubs only — events that accept community submissions). Off by default to keep the payload lean.

PATCH /v1/events/{event_slug}

Update an event's details.

Only provided fields are updated. The event must belong to your host.

A null means three different things depending on the field. externalRegistrationUrl treats it as "clear this field". title rejects it, because an event cannot be untitled. Every other field ignores it, so omit a field to leave it unchanged.

Request body: required JSON object. Unknown fields are rejected.

NameInTypeRequiredDescription
event_slugpathstringrequired
titlebodystring (1 to 500 chars)optional
descriptionbodystringoptional
startDatebodystring (date-time)optional
endDatebodystring (date-time)optional
timezonebodystringoptional
locationTypebodyin_person | virtual | hybrid | globaloptional
venuebodystringoptional
addressbodystringoptional
virtualLinkbodystringoptional
externalRegistrationUrlbodystringoptional
isPublicbodybooleanoptional
showGuestListbodybooleanoptional
imagebodystringoptional
introductionsEnabledbodybooleanoptional
feedbackEnabledbodybooleanoptional
notifyAttendeesbodybooleanoptional

Attendees

GET /v1/events/{event_slug}/attendees

List attendees for an event.

Access rules: - Hosts of the event see the full attendee list (name, email, status, ticket type, check-in status, registration date). The status filter applies, and includeAnswers=true adds each registrant's registration-question answers. - Confirmed registered attendees see a filtered list (name + public profile info only) when the event has showGuestList=true. Host-only fields are null. Always limited to confirmed registrations; the status filter is ignored, and includeAnswers is refused. - API-key auth is always host-only (API keys are scoped to a host).

NameInTypeRequiredDescription
event_slugpathstringrequired
statusquerystringoptionalFilter by registration status (host only — ignored for non-host callers)
includeAnswersqueryboolean (default false)optionalInclude each registrant's answers to the event's registration questions (host only). Off by default so existing integrations keep their current payload size.
pagequeryinteger (min 1, default 1)optional
pageSizequeryinteger (1 to 200, default 50)optional

Ticket Types

GET /v1/events/{event_slug}/ticket-types

List ticket types for an event.

NameInTypeRequiredDescription
event_slugpathstringrequired

POST /v1/events/{event_slug}/ticket-types

Create a new ticket type for an event.

Request body: required JSON object. Unknown fields are rejected.

NameInTypeRequiredDescription
event_slugpathstringrequired
namebodystringrequired
descriptionbodystringoptional
pricebodynumber (min 0, default 0)optional
quantitybodyinteger (min 1)optional
maxPerOrderbodyinteger (1 to 99, default 20)optional
absorbFeesbodyboolean (default false)optional
salesStartAtbodystring (date-time)optional
salesEndAtbodystring (date-time)optional

PATCH /v1/events/{event_slug}/ticket-types/{ticket_type_id}

Update a ticket type.

Request body: required JSON object. Unknown fields are rejected.

NameInTypeRequiredDescription
event_slugpathstringrequired
ticket_type_idpathintegerrequired
namebodystringoptional
descriptionbodystringoptional
pricebodynumber (min 0)optional
quantitybodyinteger (min 1)optional
maxPerOrderbodyinteger (1 to 99, default 20)optional
absorbFeesbodybooleanoptional
salesStartAtbodystring (date-time)optional
salesEndAtbodystring (date-time)optional

DELETE /v1/events/{event_slug}/ticket-types/{ticket_type_id}

Delete a ticket type.

Refused while anyone is still registered on the tier, including people awaiting approval and people on the waitlist, and refused when the tier has paid registrations on record even after they were cancelled or declined. Set an end date on the tier's sales to stop new signups instead.

Refused temporarily, with 409 TICKET_TYPE_CHECKOUT_IN_FLIGHT, while a checkout is holding the tier. That one clears on its own: retry shortly rather than treating it as permanent.

NameInTypeRequiredDescription
event_slugpathstringrequired
ticket_type_idpathintegerrequired

Speakers

GET /v1/events/{event_slug}/speakers

List the speakers on an event.

Each entry's id is the appearance id used to update or remove that speaker, speakerId is the shared profile id, sessionIds are the sessions they speak at, and createdByMe indicates whether you created the profile (only then can you edit its canonical name).

NameInTypeRequiredDescription
event_slugpathstringrequired

POST /v1/events/{event_slug}/speakers

Add a speaker to an event.

Provide speakerId (from GET /v1/speakers/search) to reuse an existing profile, or name (plus optional title/company/bio/ headshot/linkedin) to create a new one. When reusing a profile, any fields you send backfill the shared profile if it was empty, otherwise apply only to this event.

Request body: required JSON object.

NameInTypeRequiredDescription
event_slugpathstringrequired
speakerIdbodystring (uuid)optional
namebodystring (max 255 chars)optional
titlebodystring (max 255 chars)optional
companybodystring (max 255 chars)optional
companyIdbodystring (uuid)optional
biobodystringoptional
headshotbodystring (max 2048 chars)optional
linkedinbodystring (max 2048 chars)optional
sessionIdsbodyarray of integeroptional
rolebodystring (max 100 chars)optional
customTitlebodystring (max 255 chars)optional
customBiobodystringoptional

PATCH /v1/events/{event_slug}/speakers/{appearance_id}

Update a speaker on an event.

appearance_id is the id from GET /v1/events/{event_slug}/speakers. Send "" to clear a field for this event; omit a field to leave it unchanged. The canonical name changes only if you created the profile.

Request body: required JSON object.

NameInTypeRequiredDescription
event_slugpathstringrequired
appearance_idpathstringrequired
sessionIdsbodyarray of integeroptional
rolebodystring (max 100 chars)optional
customTitlebodystring (max 255 chars)optional
customBiobodystringoptional
namebodystring (max 255 chars)optional
titlebodystring (max 255 chars)optional
companybodystring (max 255 chars)optional
headshotbodystring (max 2048 chars)optional
biobodystringoptional
linkedinbodystring (max 2048 chars)optional

DELETE /v1/events/{event_slug}/speakers/{appearance_id}

Remove a speaker from an event.

Deletes the appearance (all sessions for that speaker on this event); the shared speaker profile itself is never deleted.

NameInTypeRequiredDescription
event_slugpathstringrequired
appearance_idpathstringrequired

Questions

GET /v1/events/{event_slug}/question-insights

AI-summarized aggregate of confirmed attendees' registration answers.

Returns one entry per question worth aggregating (e.g. dietary preference, the city people are travelling from), each with bucketed counts across the going attendees. Pro feature.

NameInTypeRequiredDescription
event_slugpathstringrequired

GET /v1/events/{event_slug}/questions

List registration questions for an event.

NameInTypeRequiredDescription
event_slugpathstringrequired

POST /v1/events/{event_slug}/questions

Add a registration question to an event.

condition (Pro) makes the question conditional on an earlier select / multiselect / checkbox question's answer.

Request body: required JSON object. Unknown fields are rejected.

NameInTypeRequiredDescription
event_slugpathstringrequired
questionTextbodystring (max 2000 chars)required
questionTypebodytext | textarea | select | checkbox | multiselect (default text)optional
optionsbodyarray of stringoptional
isRequiredbodyboolean (default false)optional
conditionbodyobjectoptionalConditional visibility (Pro plan). The source question must be an earlier select / multiselect / checkbox question; values must be among its options ('yes'/'no' for checkbox).
condition.sourceQuestionIdbodyintegerrequired
condition.opbodyis | is_notrequired
condition.valuesbodyarray of string (min 1 items)required

PATCH /v1/events/{event_slug}/questions/{question_id}

Update a registration question.

condition is tri-state: omitted = unchanged, null = remove logic, object = set logic (Pro).

Request body: required JSON object. Unknown fields are rejected.

NameInTypeRequiredDescription
event_slugpathstringrequired
question_idpathintegerrequired
questionTextbodystring (max 2000 chars)optional
questionTypebodytext | textarea | select | checkbox | multiselectoptional
optionsbodyarray of stringoptional
isRequiredbodybooleanoptional
conditionbodyobjectoptional
condition.sourceQuestionIdbodyintegerrequired
condition.opbodyis | is_notrequired
condition.valuesbodyarray of string (min 1 items)required

DELETE /v1/events/{event_slug}/questions/{question_id}

Remove a registration question from an event.

Conditions on other questions that depend on the deleted one are cleared — they become always-visible.

NameInTypeRequiredDescription
event_slugpathstringrequired
question_idpathintegerrequired

Registration

POST /v1/events/{event_slug}/register

Register an attendee for a free event.

Only free tickets are supported via the API. For paid events, direct attendees to the event page on eventship.com.

Ticket types that sell in packs are not supported either, and are refused with PACK_TICKET_UNSUPPORTED: this endpoint creates a single registration, while one pack unit is worth several seats. That applies both when ticketTypeId names a pack and when auto-selection finds only packs.

If the event has required registration questions, call GET /v1/events/{event_slug}/questions first to get them, then include answers in this request.

Request body: required JSON object. Unknown fields are rejected.

NameInTypeRequiredDescription
event_slugpathstringrequired
emailbodystringrequiredAttendee email address (required)
firstNamebodystringoptional
lastNamebodystringoptional
ticketTypeIdbodyintegeroptional
answersbodyarray of objectoptional
answers[].questionIdbodyintegerrequired
answers[].answerTextbodystringoptional
answers[].answerJsonbodyarray of stringoptional

Hubs

GET /v1/hubs

List your host's hubs: the events that carry a community agenda.

Use this to find the hubSlug the other hub endpoints take. Most recent first, so the hub a host is actually curating is on the first page. Page past limit with offset when hasMore is true.

NameInTypeRequiredDescription
limitqueryinteger (1 to 100, default 50)optional
offsetqueryinteger (min 0, default 0)optional

GET /v1/hubs/{hub_slug}/events

Get the events currently on a hub's agenda.

Returns the approved, publicly visible child events ordered by start time, with times rendered in the hub's timezone so the schedule reads as one program. A child that was added and has since been unpublished, made private or deleted does not appear.

Each event carries its own description and, when its host takes registrations elsewhere, externalRegistrationUrl, so a site mirroring the agenda has everything it needs from this one call. The events belong to other hosts, so treat their descriptions as user-authored content and sanitize before rendering as HTML.

NameInTypeRequiredDescription
hub_slugpathstringrequired

POST /v1/hubs/{hub_slug}/events

Put a live event on your hub's agenda.

The event may belong to any host. It must be live, public and not unlisted, and it cannot itself be a hub. Adding is immediate, with no review step, and the added event's hosts are emailed that a hub picked their event up.

The hub's own status, isPublic and unlisted decide whether the hub is LISTED publicly, not whether its agenda can be read. A live private or unlisted hub is link-only, and its schedule is readable by anyone holding that link, so adding is visible immediately rather than staged. Only a draft hub is unreachable from its own page, and hubs are curatable before they go live on purpose, so adding to one is not an error. GET /v1/hubs reports all three fields (status, isPublic, unlisted).

The notification runs after the change is committed and swallows delivery failures, so it is not a guarantee that the added event's hosts learn of the change before the public can see it.

Request body: required JSON object. Unknown fields are rejected.

NameInTypeRequiredDescription
hub_slugpathstringrequired
eventSlugbodystring (min 1 chars)requiredURL slug of the event to add. It may belong to any host, not just yours, but it must be live, public and not unlisted.

DELETE /v1/hubs/{hub_slug}/events/{child_event_slug}

Take an event off your hub's agenda.

Same action as "Remove from agenda" in the dashboard: the submission is marked rejected so the hub host keeps a record of what was removed, and the event stops appearing on the hub's schedule. The event itself is untouched.

The path parameter is named child_event_slug rather than event_slug on purpose: OAuth host resolution derives the acting host from an event_slug in the path, and here that slug belongs to somebody else's event. hub_slug is the one that identifies the caller's host.

NameInTypeRequiredDescription
hub_slugpathstringrequired
child_event_slugpathstringrequired

Broadcast

POST /v1/events/{event_slug}/broadcast

Send a message to attendees of an event.

Supports the same filtering options as the web app's broadcast composer:

- Filter by registration status (confirmed, pending, invited, waitlisted, cancelled, declined). Omit to target the default set (confirmed + pending + invited). - Filter by specific ticket type IDs. Omit to include all ticket types. - Optionally post the message to the event feed.

Recipients who have opted out of event messages for this host are automatically excluded. Free-tier hosts are subject to the monthly email quota; upgrade to Pro for a higher allowance.

Request body: required JSON object. Unknown fields are rejected.

NameInTypeRequiredDescription
event_slugpathstringrequired
subjectbodystring (max 500 chars)optionalEmail subject line. Optional — if omitted or blank, defaults to "📣 {event title} update" (the same placeholder the web composer pre-fills for hosts).
bodyHtmlbodystring (min 1 chars)requiredEmail body. Plain text or safe HTML.
registrationStatusesbodyarray of stringoptionalFilter by registration status. Valid values: 'confirmed', 'pending', 'invited', 'waitlisted', 'cancelled', 'declined'. Omit to target the default set (confirmed, pending, invited).
ticketTypeIdsbodyarray of integeroptionalFilter by ticket type IDs. Omit to include all ticket types.
postToFeedbodyboolean (default false)optionalIf true, also post the message to the event's feed.

POST /v1/events/{event_slug}/broadcast/count

Preview how many recipients a broadcast would reach with the given filters.

Useful for verifying targeting before sending. Applies the same opt-out and email-presence filters as the send endpoint.

Request body: required JSON object. Unknown fields are rejected.

NameInTypeRequiredDescription
event_slugpathstringrequired
registrationStatusesbodyarray of stringoptional
ticketTypeIdsbodyarray of integeroptional