One POST, and the show is on sale.
27 REST endpoints over the whole product: three to get a key, then twenty-four behind it covering schedules, sub-schedules, events, recurrences, ticket types, sales and refunds, feedback and fan content. JSON in, JSON out, one header.
An OpenAPI 3.0 spec, llms.txt and agents.json ship with it, so an agent can discover this API and drive it without a human reading the docs first.
{ "name": "Analog Night", "starts_at": "2026-08-14 20:00:00", "duration": 3, "tickets_enabled": true, "tickets": [{ "type": "Advance", "price": 18, "quantity": 120 }] }
{ "data": { "id": "Kd3Vq7", "url": "https://synth-lab.eventschedule.com/analog-night/Kd3Vq7", "tickets": [{ "id": "9pR3vB", "type": "Advance" }] }, "meta": { "message": "Event created successfully" } }
That one call also writes the event to Google, Outlook or CalDAV if the schedule is connected to one, and fires an event.created webhook.
Four facts, and you can start writing.
No SDK to install, no OAuth dance, no sandbox to request. The whole surface behaves the same way, which is the only property an agent really needs.
One header
Register, generate a key in your settings, or log in when you have none. Keys last a year. Nothing else is required.
Requests a minute
300 reads and 30 writes a minute, per IP. Over the line you get a 429, not a silent drop.
The big lists paginate
100 by default, 500 at most, with a meta block carrying the page, the total and the bounds. Categories and sub-schedules come back whole.
IDs are opaque strings
Never a sequential integer, and an event's is the same string that appears in its public URL, so you can build a link from a response.
{ "data": [ ... ], "meta": { "current_page": 1, "total": 50 } }
{ "error": "Validation failed", "errors": { "starts_at": ["must match Y-m-d H:i:s"] } }
401 for a bad key, 403 when the plan or the permission is missing, 404, 409 when a key is already live or a refund's outcome is not yet confirmed, 422 with the offending fields named, 429 when throttled. A model can branch on that without guessing.
The entire surface, on one page.
27 endpoints. Not a summary of them, all of them. Everything past /api/login needs the key header, and API access is part of the Pro plan.
| Method | Path | Behaviour |
|---|---|---|
| Auth No key required. Each of these has its own throttle. | ||
| POST | /api/register/send-code | Mail a six-digit verification code. Hosted mode only, five per address per hour. |
| POST | /api/register | Create the account and return a key. Three per IP per hour. |
| POST | /api/login | Mint a key for an account that has none. A live key returns 409 instead. |
| Schedules A schedule is the tenant: a venue, a talent or a curator. | ||
| GET | /api/schedules | List the schedules you own or administer. Filter by name and by type. |
| GET | /api/schedules/{subdomain} | One schedule, with its sub-schedules inlined. |
| POST | /api/schedules | Create one. name and type are required; the subdomain is generated from the name. |
| PUT | /api/schedules/{subdomain} | Name, contact, description, timezone, language, address. Partial payloads are fine. |
| DELETE | /api/schedules/{subdomain} | Marks it deleted, so it and its pages go dark. Owner level only, not admin. |
| Sub-schedules Named strands inside one schedule, each with its own colour. | ||
| GET | /api/schedules/{subdomain}/groups | id, name, slug and colour for each sub-schedule. |
| POST | /api/schedules/{subdomain}/groups | name is required, colour optional. The slug is generated. |
| PUT | /api/schedules/{subdomain}/groups/{group_id} | Rename it or recolour it. |
| DELETE | /api/schedules/{subdomain}/groups/{group_id} | Events survive; their sub-schedule reference is cleared. |
| Events The big one. Tickets, agenda parts, members and recurrence all ride along. | ||
| GET | /api/events | Paginated, newest first. Ten filters, including tickets_enabled and rsvp_enabled. |
| GET | /api/events/{id} | One event with its tickets, members and agenda parts. |
| POST | /api/events/{subdomain} | Create an event on a schedule. Carries its own 30-per-minute throttle. |
| PUT | /api/events/{id} | Partial update. Recurrence, tickets and agenda parts survive being omitted. |
| DELETE | /api/events/{id} | Delete it, and withdraw it from any synced calendar. |
| POST | /api/events/flyer/{event_id} | Multipart upload of a flyer_image for an existing event. |
| Categories Read-only lookups so you can send a category_id you know exists. | ||
| GET | /api/categories | Every system category, with its id and name. |
| GET | /api/categories/{subdomain} | The effective list for one schedule, including its own custom categories. |
| Sales A sale is a buyer, a set of ticket quantities and a status. | ||
| GET | /api/sales | Filter by event, subdomain, status, buyer email or occurrence date. |
| GET | /api/sales/{id} | One sale with its ticket lines. |
| POST | /api/sales | Book a sale by hand. Created unpaid; free tickets are marked paid straight away. |
| PUT | /api/sales/{id} | mark_paid, cancel or refund. A refund sends Stripe or PayPal money back, in full or an amount you name; an idempotency_key makes a retry safe. |
| DELETE | /api/sales/{id} | Soft delete. It stops appearing in listings. |
| Feeds Read-only, for pulling audience content onto a site you already run. | ||
| GET | /api/feedback | Post-event star ratings and comments. Filter by minimum rating and date range. |
| GET | /api/fan-content | Approved comments, photos and videos. Submitter email addresses are never included. |
Full documentation for each one, with a cURL example and a response body, is in the API reference.
Four files an agent can read first.
Documentation written for a person is a bad input for a model. These four are written for the model, live at fixed paths, and are served from any installation, hosted or your own.
The short one. Schedule types, the auth header, which plan the API needs, the rate limits, the deployment modes and a four-step getting-started list, so an agent can decide in one fetch whether this API is relevant at all.
The whole reference in one file, so an agent never has to follow a link to finish a task. Every endpoint, every parameter, every error shape.
Named multi-step flows: register_and_setup, create_event_with_tickets, sell_tickets and manage_schedule. Each one lists its calls in order, so a plan is data rather than prompt engineering.
The machine-readable spec. Generate a client, or generate tool definitions, in whatever language your agent is written in.
Three calls you will actually write.
Filtering a calendar, standing up a weekly residency, and settling a sale. Everything else is a variation on these.
?subdomain=synth-lab &starts_after=2026-08-01 &tickets_enabled=1 &per_page=50
"meta": { "current_page": 1, "last_page": 2, "total": 63 }
Ten filters on the events list, including whether tickets or RSVP are switched on, a venue, a sub-schedule and a date window. You narrow server-side rather than pulling a year and filtering in the agent.
"schedule_type": "recurring", "recurring_frequency": "weekly", "days_of_week": "0111110", "recurring_end_type": "after_events", "recurring_end_value": "14"
"schedule_type": "recurring", "days_of_week": "0111110"
A seven-character mask, Sunday first, so Monday to Friday is "0111110". Frequency is one of daily, weekly, every_n_weeks, monthly_date, monthly_weekday or yearly, and a run can end never, on a date, or after a set number of occurrences.
{ "action": "mark_paid" }
"status": "paid", "payment_amount": 36, "total_quantity": 2, "tickets": [{ "type": "Advance" }]
Three actions, and which ones are legal depends on where the sale is: mark_paid from unpaid, refund from paid, cancel from either. On a Stripe or PayPal sale, refund sends the money back before the status moves, and an amount makes it partial, which leaves the sale paid. You can also create a sale outright for a buyer who paid you off-platform.
You can name a venue or a performer instead of looking up an ID: send venue_name with venue_address1, or members as a list of names and emails, and the API resolves them to schedules on your account. To be exact about what that is: it matches an existing schedule you own or follow, and returns a 422 naming the one it could not find. It does not invent a venue for you. Categories work the same way: send category as a name and it is matched against that schedule's category list.
Or stop asking, and get told.
Polling a sales endpoint every minute is a waste of both our time. Register an endpoint and the traffic reverses: we POST to you, signed, the moment something happens.
X-Webhook-Event: sale.paid X-Webhook-Signature: sha256=<hex> X-Webhook-Timestamp: 2026-08-14T20:11:04+00:00 User-Agent: EventSchedule-Webhook/1.0 { "event": "sale.paid", "data": { ... } }
The signature is an HMAC-SHA256 of the raw body, keyed on a secret shown once when you add the hook. Verify it before you trust the payload. Key on data.id plus the event type, because a delivery can repeat and one sale fires several types. There is a delivery log in your settings when something goes wrong.
- sale.created A sale is created, still unpaid.
- sale.paid Confirmed paid, whether by Stripe, PayPal, Payfast, Invoice Ninja, by hand or free.
- sale.refunded A paid sale is refunded in full. A partial refund leaves it paid and fires nothing.
- sale.cancelled A sale is cancelled.
- installment.paid A payment of an installment plan is collected.
- installment.failed A scheduled payment could not be collected. Read outcome for why.
- event.created A new event exists.
- event.updated An event changed.
- event.deleted An event is gone.
- event.cancelled An event is cancelled.
- ticket.scanned A ticket QR code is scanned at the door.
- ticket.booked A pass holder reserves a place on a date.
- ticket.booking_cancelled A pass holder releases a reserved place.
- feedback.submitted An attendee left a rating.
The parts that make it safe to automate.
Details that only matter once your code is running unattended, which is exactly when they matter most.
Your own install, same API
Event Schedule is open source, and the API does not change when you host it yourself: same routes, same OpenAPI spec, same discovery files, served from your own domain. On a selfhosted install the Pro gate returns true unconditionally, so no endpoint is held back and no key talks to anyone else's server.
Flyers, as a second call
Artwork is multipart, so it gets its own request. Create the event, then POST a flyer_image to the flyer endpoint with the returned ID.
curl -X POST .../api/events/flyer/Kd3Vq7 \ -H "X-API-Key: $KEY" \ -F "[email protected]"
Languages, made explicit
Set language_code on a schedule and its pages are served in that language; twelve are supported. A schedule can also nominate one translation target, and its own copy is machine-translated into it on a scheduled pass.
Money, without a middleman
Ticket types created through the API sell through your own Stripe or PayPal account, or through Invoice Ninja, Payfast for rand prices, a payment URL, or by hand. Event Schedule takes zero platform fees on ticket sales: the only deduction is your processor's. Sales come back through the sales endpoints and through sale.paid webhooks, with the ticket lines attached, and a Stripe or PayPal refund goes back through the provider.
Read-only feeds
Two endpoints exist purely so you can pull audience content somewhere else: post-event ratings and comments, and approved fan photos, videos and comments. Fan submissions carry a display name only; the ratings feed names the attendee, so treat it as owner-facing.
Each kind of fan submission has its own ID sequence, so key on type and id together when you store a row.
Partial writes that keep their nerve
PUT takes the same body as create and applies only what you send. Recurrence configuration, ticket types and agenda parts are preserved when they are absent, so an agent that only knows the new start time cannot quietly erase a run's ticket tiers. Every write is scoped to the schedules the key's owner owns or administers, and anything outside that returns 403 rather than silently doing nothing.
Key missing, wrong or expired.
Not your schedule, or the plan does not cover it.
Throttled. Back off and retry.
What people point at this API.
An HTTP API has no opinion about what is calling it, which is the point.
AI Assistants
Turn a conversation into a published event. Register, create the schedule and create the event in three calls, then hand back the URL from the response.
Learn moreDeveloper Tools & Scripts
A cron job, a CLI, a one-off migration. Generate a client from the OpenAPI spec and the whole surface is typed for you.
Learn moreCommunity Bots
A Discord, Slack or Telegram bot that creates the event when someone announces it in the channel, and posts the ticket link back.
Learn moreBooking Platforms
Keep your own front end and let Event Schedule hold the events, the ticket types and the sales. Webhooks push each paid sale straight back to you.
Learn moreCalendar Aggregators
Pull a date window with the events filters, or take the iCal feed and skip the API entirely. Both come off the same schedule.
Custom Integrations
Anything that speaks HTTP and JSON. If you would rather not write the client, the OpenAPI spec will write it for you.
Learn moreThree requests from nothing to a live page.
Get a key
One unauthenticated POST to /api/register, or to /api/register/send-code first in hosted mode. The response body carries the key and its expiry.
Create a schedule
POST /api/schedules with a name and a type. The subdomain is generated from the name and the public page exists immediately.
Create events
POST /api/events/{subdomain}. Ticket types, agenda parts and recurrence go in the same body, so there is no second round trip. On eventschedule.com this one needs the schedule on Pro.
Free forever. Upgrade when you're ready.
Free registration for as many people as you like. When you start charging, zero platform fees on every plan - the only deduction is your payment processor's own.
Everything you need to publish a schedule and fill the room, for as long as you like.
- Unlimited events, sub-schedules and recurring dates
- Two-way Google, Outlook and CalDAV sync
- Unlimited free registration and RSVPs, scanned at the door
No expiry, and no card asked for.
Start charging, and the rest of the selling kit arrives with it.
- Sell paid tickets, with the live check-in dashboard
- Promo codes, add-ons, passes and gift cards
- The REST API, webhooks, and no Event Schedule branding
7-day free trial, cancel any time.
For a room with a seating chart, a team, and a domain of its own.
- Reserved seating, drawn once and reused every date
- Your own domain, and up to five team members
- Internal and unlisted events, and 1,000 newsletter recipients
Included free on every selfhosted install.
Frequently asked questions
What developers ask before they write the first request.
Is the API free to use?
The REST API is part of the Pro plan at $5 a month, with a seven-day trial when you subscribe. Selfhosted installations are Pro by definition, so running your own copy unlocks every endpoint at no cost. Ticket sales carry zero platform fees on every plan and in both modes: you keep everything except your payment processor's cut.
Which endpoints need the Pro plan, and what happens without it?
On eventschedule.com the list endpoints for schedules, events, sales and feedback return only rows from schedules on Pro, so a free schedule's data is missing rather than refused: check the plan before you read an empty list as nothing there. Reading one schedule, event or sale, updating a schedule, and writing to its events, sub-schedules or sales return 403 with "API usage is limited to Pro accounts". The exception worth planning around is POST /api/sales, which has no plan check of its own: a free schedule can record a sale against a zero-price ticket, while any row with a price on it needs the schedule to be Pro and answers 422 otherwise. On a selfhosted install every one of these checks passes.
How does authentication work?
One header, X-API-Key. Get a key from POST /api/register or POST /api/login, or generate one in your account settings. Keys are valid for a year. Login only mints a key when the account has none, and returns 409 while one is still live, so store the key rather than calling login on every run. Accounts with two-factor authentication have to generate keys from the web UI. Every endpoint except register, send-code and login requires the header.
What can I actually do with it?
27 endpoints across registration, schedules, sub-schedules, events, categories and sales, plus two read-only feeds for post-event feedback and fan-submitted content. Schedules, sub-schedules, events and sales have full create, read, update and delete; categories are read-only lookups. A single create call can carry ticket types, agenda parts, performing members, a venue and a recurrence pattern, so publishing a run of shows is one request rather than six.
Can the API refund a sale?
Yes: PUT /api/sales/{id} with the action refund. On a Stripe or PayPal sale the money goes back through the provider before the status changes. Send an amount to return part of it, and the sale stays paid with its tickets valid; leave it out and the whole remaining balance goes back, the sale becomes refunded, its places return to stock and sale.refunded fires. Send an idempotency_key of your own so a retry returns the first attempt's outcome instead of refunding twice. A refund whose outcome could not be confirmed returns 409 and is never retried for you. Invoice Ninja, Payfast, payment-link and cash sales are only recorded as refunded, so return that money yourself, and a payment plan is refunded in full only.
What is llms.txt, and why are there two of them?
llms.txt is an emerging convention for telling a language model what a site is and where its documentation lives. Event Schedule publishes both: llms.txt is a short routing summary an agent can read to decide whether this API is relevant, and llms-full.txt is the entire reference in one file, so an agent that has decided to proceed never needs to follow a link.
What are the rate limits?
300 GET requests a minute and 30 POST, PUT or DELETE requests a minute, counted per IP address. Creating an event carries its own 30-per-minute throttle on top of that, and the auth endpoints have their own tighter limits. Going over returns 429 with an error body.
Are there webhooks, or do I have to poll?
There are webhooks, on the Pro plan. Fourteen event types cover sales, event changes, door scans, pass bookings and feedback. Each delivery is signed with HMAC-SHA256 in an X-Webhook-Signature header so you can verify it came from us, payloads match the shapes the API returns, and there is a delivery log in your settings for debugging.
Which IDs does the API use?
Encoded strings, never sequential integers. An event, a ticket, a sale and a sub-schedule all identify themselves with a short opaque string, and an event's is the same string that appears in its public URL, so you can build a link straight from a response. Category IDs are the exception: they are small integers you read from the categories endpoint.
Can I run this against my own installation?
Yes. Event Schedule is open source and the API is the same in both modes: same routes, same spec, same discovery files served from your own domain. On a selfhosted install the Pro gate returns true unconditionally, so nothing is held back.
The last call is the first one.
Pick a name and start, or register straight from your code. Publishing a schedule and its dates is free forever, and so is free registration; the API and any ticket with a price on it are $5 a month, and Event Schedule takes nothing from the door.
No card to start. Or go straight to the API reference and the OpenAPI spec.
{ "name": "Your Agent", "email": "[email protected]", "password": "..." }
{ "data": { "api_key": "your_new_api_key", "api_key_expires_at": "2027-07-30T00:00:00Z" } }
In hosted mode, POST /api/register/send-code mails a six-digit code first, and you pass it as verification_code.
Related
Keep exploring
Integrations
Google Calendar, Outlook, CalDAV, Stripe, webhooks and the REST API.
Read moreOpen Source
The licence, the repositories and how to contribute.
Read moreUse Cases
Event scheduling for musicians, venues, restaurants and theaters.
Read morePricing
See what is included on Free, Pro, and Enterprise plans.
Read more