The public events feed exposes the same listed events your customers see on your shop, as JSON, on the same URL, just request application/json. It’s designed for embedding your event lineup on your own website, in a partner site, or in a third-party tool.

No authentication, CORS-enabled, cacheable.

If you’re looking for the authenticated, account-wide API instead, drafts, orders, customers, write access, see the admin API.

Quick example

curl -H "Accept: application/json" \
  https://your-subdomain.usetix.io/events

From a browser:

fetch("https://your-subdomain.usetix.io/events.json")
  .then(r => r.json())
  .then(data => console.log(data.events))

Endpoints

GET /events

Returns published, listed, upcoming events for the shop. Past, unpublished, and unlisted events are never included in this collection.

curl -H "Accept: application/json" \
  https://your-subdomain.usetix.io/events

Response:

{
  "events": [
    {
      "slug": "spring-showcase",
      "title": "Spring Showcase",
      "description": "<p>Our annual seasonal event.</p>",
      "url": "https://your-subdomain.usetix.io/events/spring-showcase",
      "starts_at": "2026-05-01T19:00:00Z",
      "doors_open_at": "2026-05-01T18:00:00Z",
      "ends_at": "2026-05-01T23:00:00Z",
      "show_end_time": true,
      "sales_starts_at": null,
      "sales_ends_at": "2026-05-01T19:00:00Z",
      "time_zone": "Berlin",
      "minimum_age": 18,
      "video_url": null,
      "sold_out": false,
      "image_url": "https://your-subdomain.usetix.io/rails/active_storage/blobs/...",
      "background_image_url": null,
      "gallery_image_urls": [],
      "venue": {
        "name": "The Venue",
        "address": "Hauptstraße 1",
        "postal_code": "10115",
        "city": "Berlin",
        "country": "DE",
        "latitude": null,
        "longitude": null,
        "time_zone": "Berlin"
      },
      "cheapest_available_price": {
        "amount": "15.00",
        "currency": "EUR"
      }
    }
  ]
}

GET /events/:slug

Returns a single published event with its tickets, performers, and FAQ. Both listed and unlisted published events remain available here by their direct slug. Returns 404 Not Found if the slug doesn’t exist or the event isn’t published.

curl -H "Accept: application/json" \
  https://your-subdomain.usetix.io/events/spring-showcase

Query parameters:

Parameter Description
code Access code for hidden tickets. Repeat for multiple: ?code=AAA&code=BBB. Without a matching code, hidden tickets are excluded from the response.

Response: all the event fields, plus:

{
  "slug": "spring-showcase",
  "title": "Spring Showcase",
  "...": "...",
  "tickets": [
    {
      "title": "Early Bird",
      "kind": "StandardTicket",
      "color": "#10b981",
      "features": ["Free coat check"],
      "price": { "amount": "15.00", "currency": "EUR" },
      "available": true,
      "sold_out": false,
      "low_stock": false,
      "max_per_order": 4
    }
  ],
  "performers": [
    {
      "name": "DJ Example",
      "performer_type": "person",
      "role": "headliner",
      "genre": "Techno",
      "starts_at": "2026-05-01T22:00:00Z",
      "ends_at": "2026-05-02T01:00:00Z",
      "bio": "<p>Berlin-based...</p>",
      "image_url": "https://your-subdomain.usetix.io/rails/active_storage/blobs/...",
      "links": {
        "website": "https://example.com",
        "instagram": "https://instagram.com/example",
        "spotify": null,
        "soundcloud": null,
        "tiktok": null,
        "youtube": null
      }
    }
  ],
  "faq_items": [
    { "question": "Is there an age limit?", "answer": "18 and over." }
  ]
}

Event fields

Field Type Notes
slug string URL slug. Use it as the path parameter on GET /events/:slug.
title string Event title.
description string HTML. May contain rich-text formatting. Empty string if no description.
url string Canonical shop URL for the event.
starts_at string ISO 8601 UTC.
doors_open_at string | null ISO 8601 UTC. When guests may enter. null when no separate doors time is set.
ends_at string ISO 8601 UTC. Operational end time, including the internal five-hour default when no public end was supplied.
show_end_time boolean Display ends_at publicly only when this is true.
sales_starts_at string | null ISO 8601 UTC. null if sales are open immediately.
sales_ends_at string ISO 8601 UTC.
time_zone string Rails time zone name (e.g. "Berlin"), useful for displaying local times.
minimum_age integer | null  
video_url string | null YouTube URL if set.
sold_out boolean true when no tickets remain.
image_url string | null Absolute URL to the event image.
background_image_url string | null Absolute URL to the background image.
gallery_image_urls string[] Absolute URLs to gallery images, in order.
venue object See below.
cheapest_available_price object | null The lowest-priced ticket still available. null when sold out or no tickets configured.

venue

Field Type Notes
name string  
address string Street address.
postal_code string | null  
city string  
country string Country code or name as stored on the venue.
latitude number | null Decimal degrees.
longitude number | null Decimal degrees.
time_zone string Rails time zone name.

tickets[] (show only)

Field Type Notes
title string  
kind string "StandardTicket" or "GroupTicket".
color string Hex color (e.g. "#10b981") used in the shop.
features string[] Bullet-point list of perks.
price object { amount, currency }. See Money fields.
available boolean true when stock and event capacity allow purchase.
sold_out boolean Inverse of available.
low_stock boolean true when ≤ 15 left in stock. Stays false for unlimited-stock tickets.
max_per_order integer | null Per-order purchase cap. null when unlimited.

performers[] (show only)

Field Type Notes
name string  
performer_type string "person" or "performing_group".
role string "headliner", "support", or "guest".
genre string | null  
starts_at string | null Set time, ISO 8601 UTC.
ends_at string | null  
bio string | null HTML.
image_url string | null  
links object Social links, website, instagram, spotify, soundcloud, tiktok, youtube. Each is a string or null.

faq_items[] (show only)

Field Type Notes
question string  
answer string Plain text.

What’s not in the feed

Deliberately omitted, because it’s either internal or for the authenticated admin API:

  • Database IDs (use slug as the stable identifier)
  • Drafts and unpublished events
  • Unlisted events on the index; a published unlisted event remains available from GET /events/:slug
  • Hidden tickets without a matching access code
  • Past events (on the index)
  • Capacity, sales totals, ticket stock counts (use low_stock and sold_out instead)
  • Ticket access codes
  • Customer or order data

Authentication

None. The feed only exposes data your shop is already publishing. No tokens, no headers required beyond Accept: application/json.

CORS

All responses include:

Access-Control-Allow-Origin: *

You can fetch the feed from any origin in the browser without a proxy.

Caching

The feed is built to be cached by browsers, CDNs, and your own infrastructure.

  • Cache-Control: public, max-age=60: both endpoints. Shared caches (CDN, reverse proxy) can serve the response for up to a minute.
  • ETag: GET /events/:slug returns an ETag based on the event’s last-modified timestamp. Send it back as If-None-Match on subsequent requests; if nothing has changed, you get a 304 Not Modified with no body.

A typical embed setup polls every minute or two, well within the cache window, and gets near-instant responses.

Custom domains

If your shop runs on a custom domain (e.g. tickets.yourbrand.com), the feed is available at the same path on that domain:

https://tickets.yourbrand.com/events.json
https://tickets.yourbrand.com/events/spring-showcase.json

Embedding example

A minimal “next event” widget for any HTML page:

<div id="next-event"></div>

<script>
  fetch("https://your-subdomain.usetix.io/events.json")
    .then(r => r.json())
    .then(data => {
      const next = data.events[0];
      if (!next) return;
      document.getElementById("next-event").innerHTML = `
        <a href="${next.url}">
          <img src="${next.image_url}" alt="">
          <h3>${next.title}</h3>
          <time datetime="${next.starts_at}">${new Date(next.starts_at).toLocaleString()}</time>
          <p>${next.venue.name}, ${next.venue.city}</p>
          ${next.sold_out ? "<span>Sold out</span>" : `<span>From ${next.cheapest_available_price.currency} ${next.cheapest_available_price.amount}</span>`}
        </a>
      `;
    });
</script>

Changes and stability

The feed is intentionally narrow, additive changes (new fields) may ship without notice. We won’t remove fields without a deprecation window. If something breaks for you, let us know.