← All engineering notes

Public API and MCP reference

Integration reference for event discovery, ticket checkout and MCP access, with request formats, response fields and error handling.

Gotobeat provides public event data over HTTP, signed ticket checkout through the Agentic Commerce Protocol (ACP), and public and authenticated Model Context Protocol (MCP) tools.

Discovery files

File What it is
/llms.txt Entry points for agents.
/llms-full.txt Endpoint summaries, ticket identifiers and checkout flow.
/openapi/agents.json OpenAPI 3.1 schemas for the public HTTP API.
/docs/agents/ Integration guide for checkout and MCP authentication.

/sitemap.xml indexes five sections: events-upcoming, events-archive, artists, venues and content. Each section has a six-hour edge cache lifetime. /.well-known/security.txt lists the security contact. Page URLs use a trailing slash; requests without it receive a 301 redirect.

Public HTTP routes

The documented API uses the following prefixes, which robots.txt allows under /api/. Crawler rules describe indexing policy; each endpoint enforces its own access checks. Use the endpoints listed in this reference for integrations.

Prefix Purpose
/api/events Event listing and detail
/api/search/ Event keyword search
/api/artists/search Artist search
/api/venues/search Venue search
/api/checkout_sessions Signed ACP checkout

Event response fields

The three HTTP event endpoints use the same field projection. Optional values are omitted when absent. hideDateTime omits dates and times; hideVenue omits the venue object.

Field Type Notes
eventId, slug, url string url is the canonical gig page
title, description string description contains visible text with HTML removed
status string PUBLISHED in these HTTP responses
date, untilDate YYYY-MM-DD untilDate only on a multi-day event
startTime, endTime, doorTime HH:MM venue local time
hideDateTime, hideVenue boolean when true, the hidden fields are omitted
genres string[]
image string the poster URL
ageLimit string
artists[] object name, slug, image, genres[], spotifyUrl
venue object name, address, city, postcode, country, googleMapsUrl
tickets[] object see the tier table below
externalTickets[] object name, url, when another ticketer sells the show

Ticket tier fields:

Field Type Notes
sku string <eventId>:<ticketTypeId>, the id a checkout session takes
ticketTypeId string
name string
price decimal string for example, "22.50"
currency ISO 4217 GBP, EUR, or the venue's currency
availability enum InStock, SoldOut or PreSale
releaseDate ISO 8601 optional scheduled release time
minQuantity, maxQuantity integer optional limits per order

Read endpoints

These five GET endpoints accept anonymous requests. HTTP event results are restricted to upcoming PUBLISHED events that carry no password. The detail endpoint returns 404 for an unknown slug and for an event outside that filter, with the same body in both cases, so a response discloses no existence signal.

A password-gated event is refused by the read itself. One helper, isUpcomingPublishedEvent, answers status, date and password together, and every anonymous read applies it: /api/events and both of its search fallbacks, /api/events/:slug, /api/search/event/:keyword, the /api/events/list.csv product feed, and the two listing MCP tools. public_get_event reads the same status and password rules directly rather than through the helper, so it can still answer a finished show — see the MCP section below. The promoter shares the link and the password by hand, and /gig/<slug> answers an ungated visitor with an empty ticket list and no venue. An anonymous JSON read that answered with tiers, prices and skus would disclose what that page withholds.

List and search events

GET https://gotobeat.com/api/events?search=<text>&cursor=<opaque>&limit=<n>

Returns { events, cursor, hasMore }, with search included for a search request. The default page size is 12. Pass the returned cursor to fetch the next page.

Without search, results are ordered by event date. With search, direct keyword matches are paginated. When there are no direct matches, fallbackType identifies the result:

fallbackType Response
artist_events events contains upcoming shows for matched artists.
artist_no_events events is empty; matchedArtists contains name, slug, image and genres[]; genreEvents contains up to 12 related shows.
top_events events contains shows ranked by remaining tickets on sale.

Fallback responses set cursor: null and hasMore: false.

One event

GET https://gotobeat.com/api/events/<slug>

Returns { event, how_to_buy }. event uses the fields above. Each tier with a ticket type id includes a sku. how_to_buy describes the checkout endpoint and required item identifiers.

Keyword search

GET https://gotobeat.com/api/search/event/<keyword>

Returns a bare array of public event objects. An empty keyword or a failed lookup returns [] with status 200.

Artist and venue pickers

GET https://gotobeat.com/api/artists/search?keyword=<text>
GET https://gotobeat.com/api/venues/search?keyword=<text>

Successful requests return { success: true, data }. Artist rows contain { id, label }; keywords shorter than two characters return an empty array. Venue rows contain { id, label, venueId, venueName, city?, country?, hiringOptionsCount }; an empty keyword returns an empty array. Search failures return HTTP 500 with { success: false, error }.

Structured data on a gig page

Gig pages at https://gotobeat.com/gig/<slug>/ embed schema.org MusicEvent JSON-LD. Fields depend on the event data and visibility settings: name, startDate, endDate, doorTime, eventStatus, location (a Place with a PostalAddress), performer (a PerformingGroup with url and sameAs), image, typicalAgeRange, isAccessibleForFree, and one Offer per ticket tier with url, sku, name, price, priceCurrency, availability and validFrom.

Offer fields follow these rules:

  • Offer.sku is the same <eventId>:<ticketTypeId> string the API returns. Split on the first colon to preserve ticket type ids containing colons.
  • availability uses the https://schema.org/ prefix. The JSON-LD emits InStock or SoldOut only, and it reads a tier awaiting its release date as SoldOut. The HTTP API reports that tier as PreSale, because a JSON reader can act on the distinction and a crawler cannot.
  • One rule decides the answer for every surface. It reads the manual sold-out flag, the release window and a bundle-aware capacity: a tier that shares an exhausted pool with a bundle reads sold out even while its own counters say otherwise. The JSON-LD, the HTTP API, the product feed and the MCP tools therefore agree about what is buyable. Checkout validates current inventory again at reservation time.
  • A cancelled event reads eventStatus: EventCancelled and every offer SoldOut.
  • A past event keeps EventScheduled (schema.org has no past state), every offer reads SoldOut, and no offer carries a sku. It stays online as a historical record.
  • An event that sells through another ticketer carries one Offer whose url is that seller's page and no sku.

Ticket checkout

ACP checkout lets an approved partner create and pay for ticket orders. Obtain a Bearer credential and a signing secret from Gotobeat before integrating.

Endpoints

Request Behaviour
POST /api/checkout_sessions Create. items[] is the only required field; buyer and fulfillment_address are optional. items[].id is a sku, quantity a positive integer. The schema is strict, so any other field — currency included — is a 400. Returns 201.
GET /api/checkout_sessions/:id Read the session.
POST /api/checkout_sessions/:id Update items, buyer, fulfillment_address or fulfillment_option_id. An empty body is a 400.
POST /api/checkout_sessions/:id/complete Pay. payment_data carries provider: "stripe", a delegated token, and an optional billing_address. The schema is strict, so any other field is a 400. Produces the order.
POST /api/checkout_sessions/:id/cancel Cancel the session and release any reserved tickets.

Session lifecycle

A new ticket session starts in ready_for_payment with digital delivery selected. The status schema also includes not_ready_for_payment, completed and canceled. Supply the buyer's email before completing payment; a missing email returns buyer_email_required.

line_items contains the priced tiers and totals contains amounts in minor currency units. A completed session includes order.permalink_url, pointing to /orders/<checkoutId>. An info entry in messages[] says the tickets are still being issued. Do not branch on a code there: an info message is projected as { type, content_type, content } and carries none.

The server calculates prices from the current ticket tiers, and a line item carries id and quantity only — a submitted unit_amount is refused by the strict schema, not repriced. Checkout accepts paid tickets for one upcoming, published event per cart. Password-gated events require the browser checkout. Inventory is reserved during complete.

Idempotency

Use a unique Idempotency-Key of up to 255 characters for each create, update, complete or cancel operation. Reuse that key when retrying the same operation. Cached successful responses are replayed for one hour by default; a changed operation needs a new key.

Signing

Production requires signed checkout requests. AGENTIC_CHECKOUT_VERIFY_SIGNATURE turns the guard on, and staging leaves it off so an integration can be tested unsigned. Send every one of these headers on a checkout request:

Header Content
Authorization Bearer <your credential>. A missing or wrong credential is a 401.
Signature HMAC-SHA256 of the raw request body with your signing secret, base64, in the sig1=:<base64>: form. A bare base64 value is accepted.
Timestamp An RFC 3339 date-time. It is required, not optional.
Request-Id Any id you choose. It comes back on the response Request-Id header, so you can pair the two.
API-Version 2025-09-12. Another value is a 400.
Accept-Language, User-Agent Required on every call.
Content-Type application/json on every write. Another type is a 415.
Idempotency-Key Required on a write. See Idempotency above.

Sign the exact body bytes sent to the server; a GET request signs the empty string. A digest that is not canonical base64 is a 400, and it never reaches the comparison. A Timestamp more than five minutes from the server clock is a 401.

The credential and the signing secret are separate values, and a request needs both. Leaking the outbound webhook secret therefore cannot authenticate a checkout request.

One credential signs the surface today. There is no keyid, and no per-partner registry: a second partner would add a key-id-to-secret map behind the same headers, and no caller would change.

Checkout applies a best-effort limit of 30 requests per minute per resolved client IP on each warm instance. Back off after HTTP 429.

Checkout errors

Every checkout failure answers with ONE shape, whatever raised it:

{ "type": "invalid_request", "code": "invalid_line_item", "message": "…", "param": "$.items[0].id" }

type classes the STATUS, not the fix: every 4xx reads invalid_request apart from request_not_idempotent, a 503 reads service_unavailable, and any other 5xx reads processing_error. Retriability therefore lives in code, not in type — the three codes marked Retriable below arrive as invalid_request like every other 4xx, and every 5xx is worth another attempt.

code is the stable string to branch on. message carries the prose — there is no error key and no details key. param is a JSON path into your request body, and it appears only when a field caused the refusal. A 500 answers internal_error with a deliberately opaque message.

Code Status Cause
invalid_request 400, 401 or 415 The body, a header or a field failed validation, and param names the field when one did. It is the default code for an uncoded refusal, so a bad Bearer, a bad Timestamp and a wrong Content-Type all carry it.
invalid_line_item 400 The item id is malformed or the ticket tier is missing.
mixed_events 400 The cart includes multiple events.
event_not_found 404 The event id was not found.
not_found 404 No checkout session has that id. The most common 404.
checkout_error 503 Checkout initialisation failed on our side. Retriable.
internal_error 500 The opaque fallback. Retriable.
event_not_available 400 The event is not published, already happened, or needs a password.
free_event_not_supported 400 The cart total is zero.
checkout_unavailable 409 Checkout initialisation failed, for example because a tier sold out.
invalid_state 400, 405 or 409 The session is in the wrong status for the call. Cancelling an already-cancelled session answers 405.
session_not_payable 400 The session has no payable order.
buyer_email_required 400 The buyer email is missing at completion.
payment_declined 402 Payment failed and the reservation was released.
payment_pending 409 Payment or fulfilment is unresolved. Poll the session.
order_not_amendable 409 The order moved past checkout.
order_already_placed 405 or 409 The order is paid. Use the support flow for refunds.
checkout_in_progress 409 A concurrent complete moved the order on under a cancel. Re-read the session. Retriable.
request_in_progress 409 Another request holds the same Idempotency-Key and is still running. Retriable.
request_not_idempotent 409 The same Idempotency-Key arrived with a different body. Use a new key.
session_not_amendable 409 The session refuses every amendment.
invalid_fulfillment_option 400 The fulfillment_option_id names no option on the session.
rate_limit_exceeded 429 Back off, then retry.
payload_too_large 413 The body exceeds the accepted size.
idempotency_unavailable 503 The idempotency store could not answer. Retriable.
order_update_failed 500 The order update failed. Retry with the same idempotency key.
order_unavailable 503 The order could not be read. Retry the call.
payment_setup_failed 500 The payment could not be set up.

MCP

The MCP server is available at https://mcp.gotobeat.com.

Discovery

The server publishes RFC 9728 protected-resource metadata at https://mcp.gotobeat.com/.well-known/oauth-protected-resource. A compliant client reads it to find the authorisation server, the supported bearer method (header) and the scopes (mcp:tools:read, mcp:tools). The server supports RFC 7591 dynamic client registration at /oauth/register and S256 PKCE, allowing compatible MCP clients to register during connection setup.

Anonymous tools

POST https://mcp.gotobeat.com/public accepts JSON-RPC with no token. It exposes three read-only tools.

Tool Argument Returns
public_search_events keyword { events[] }: upcoming published gigs whose title, artist, venue or city matches
public_get_event idOrSlug a gig card plus description, tiers[] (sku, name, price, currency, availability) and how_to_buy instructions
public_list_upcoming_events limit (default 12, max 50), cursor { events[], cursor }, soonest first

A gig card is { title, date, venue: { name, city }, slug, url, priceFrom, priceTo, currency }. MCP results contain JSON encoded in content[].text. Card prices and tier prices are numbers. Every tool refuses a password-gated event, and each gate reads the stored row before the public projection strips the password. public_search_events and public_list_upcoming_events also hide a finished show. public_get_event does not: asked for one by id or slug, it answers with the record and reads every tier SoldOut, which is the honest answer to a question about a gig that already happened. MCP uses its own projection, narrower than the HTTP API's, and it returns the event description unprocessed where the HTTP API strips markup from it.

An unknown event or a status rejected by the detail tool returns an MCP error with Event not found. Only a published event is public.

The anonymous route allows 60 requests per 60 seconds per resolved source IP on each warm instance. Requests routed through the same CloudFront edge can share a budget. A 429 includes Retry-After; wait for that interval before retrying.

Authenticated tools

Add https://mcp.gotobeat.com to a compatible MCP client and sign in with your Gotobeat account. OAuth registration and consent use the discovery endpoints above. The authenticated tool set is selected by the account's role: promoters receive tools scoped to their own data, while staff accounts receive an operational tool set. Query tools/list after authentication to inspect the available tools and argument schemas.

All engineering notes
region eu-west-2read 14m