Home Features Pricing Blog Docs
Log in Start for Free
English | Deutsch

The public events feed exposes the same 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, upcoming events for the shop. Past and unpublished events are never included.

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",
      "ends_at": "2026-05-01T23:00:00Z",
      "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 event with its tickets, performers, and FAQ. 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.
ends_at string ISO 8601 UTC.
sales_starts_at string | null ISO 8601 UTC. null if sales are open immediately.
sales_ends_at string ISO 8601 UTC.
time_zone string IANA / 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 ISO 3166-1 alpha-2.
latitude number | null Decimal degrees.
longitude number | null Decimal degrees.
time_zone string IANA / 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 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
  • 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.
  • ETagGET /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.