Skip to content

Publish an event feed

An event feed is a published event collection. Each row is an event occurrence. With a stored binding, occurrences are written to QuickLookup ClickHouse and can be private or shared under the feed's access policy.

Use attendanceMode to distinguish in_person, online, hybrid, and non-attendable (none) occurrences. A validated physical location makes an occurrence eligible for nearby searches; add an explicit attendanceMode filter when attendance semantics matter. A live stream belongs in virtualLocationUrl; it is not a physical location.

Before you start

You need an editor grant to create the draft and a publisher grant to publish. Reuse or create the provenance entities, stored source binding, event types, metrics, and dimensions before creating the collection.

Create the collection in the admin

  1. Open Provision → Event feeds → Add event feed.
  2. Enter a label, stable key, canonical URL, description, classifications, and tags.
  3. Choose Local for a private feed. Choose a broader access value only for the intended sharing policy: Public makes the feed visible to every reader of your own account and to accounts you grant; making a feed part of the shared open catalogue is an operator action, not an access value.
  4. Select the provenance entities and a source binding with Mode = Stored.
  5. Declare the allowed event types. For attendable events publish status, attendanceMode, venue, and location; add virtualLocationUrl for hybrid events.
  6. Save, clear every Ready to publish? blocker, and use Preview.
  7. Publish and wait for delivery before sending events. Over the API, poll GET /v1/provision/publications and match objectGid (your feed's gid) and revision (the revision the publish returned) until state is delivered — a publication has no slug, so a slug filter matches nothing.

The signed-in account is authoritative; the form and request body do not accept account routing.

Create the feed through the API

Creating definitions through the API needs the catalogue editor role, so these operations are not in the public reference; the admin does the same work. For a key that holds the role, GET https://quicklookup.com/api/v1/authoring returns the step-by-step guide.

Execute GET /v1/authoring with a publisher token. Its quickStart provides matching identities and request bodies for a stored event feed. Change the example's definitions and access policy, then execute the requests in order.

Add event occurrences

POST https://quicklookup.com/api/v1/event-collections/{collectionGid}/events
Authorization: Bearer <your API key>
Content-Type: application/json
{
  "items": [
    {
      "gidUrl": "https://customer.example/events/annual-meeting-2030",
      "name": "Annual meeting",
      "type": "CustomerEvent",
      "dateFrom": "2030-01-01T09:00:00Z",
      "dateTo": "2030-01-01T10:00:00Z",
      "timezone": "Atlantic/Reykjavik",
      "status": "scheduled",
      "attendanceMode": "hybrid",
      "venue": "Harpa",
      "location": {"longitude": -21.9325, "latitude": 64.1500},
      "virtualLocationUrl": "https://customer.example/live/annual-meeting-2030",
      "ticketUrl": "https://customer.example/tickets/annual-meeting-2030"
    }
  ]
}

Supply a stable gid or gidUrl. A correction with the same identity replaces the logical occurrence; it does not create a second occurrence. QuickLookup derives the accepted revision, provenance, access policy, feed identity, and account routing.

Intervals are half-open: dateFrom is included and dateTo is excluded. Both timestamps must carry an offset. For a recurring series, send concrete occurrences with the same eventSeriesGid and a different recurrenceId; recurrenceRule is preserved as metadata and is never expanded without a bound on the query path.

A happening at several places

A promotion in seven stores, a festival on three stages, a race with a start and a finish is one occurrence with several sites, not one occurrence per place. Send sites instead of the single venue / location pair; the first site is the epicenter and is what venue, location and distanceMeters report, and a nearby query matches when any site is within the radius and names the one it matched in matchedSite (1-based).

{
  "gidUrl": "https://customer.example/events/danish-days-2027",
  "name": "Danish Days", "type": "SaleEvent",
  "dateFrom": "2027-03-01T09:00:00Z", "dateTo": "2027-03-08T09:00:00Z",
  "attendanceMode": "in_person", "countryCode": "ISL",
  "sites": [
    {"role": "Store", "label": "Hagkaup Skeifan", "idType": "osm", "id": "way/108335182",
     "locality": "Reykjavík", "postalCode": "108", "location": {"longitude": -21.87, "latitude": 64.13}},
    {"role": "Store", "label": "Hagkaup Kringlan", "location": {"longitude": -21.893, "latitude": 64.129}}
  ],
  "participants": [{"role": "ORGANIZER", "entityType": "Organization", "label": "Hagkaup"}],
  "media": [{"mediaType": "Image", "type": "Poster", "of": "Event", "url": "https://customer.example/poster.jpg"}],
  "names": {"IS": "Danskir dagar", "EN": "Danish Days"},
  "classification": [{"type": "Category", "value": "Promotion"}]
}

Site roles are Venue, Store, Stage, Start, Finish and Broadcast; a site needs a name, an identifier (id with idType, for example an OpenStreetMap way) or a point. The same happening on several dates stays several occurrences sharing eventSeriesGid; a series is about time, never about places. sites, participants, media, names and classification are part of every event and need no field declaration. countryCode is ISO 3166-1 alpha-3; alpha-2 is accepted and converted. An irregular extent (a festival across a whole town) can be sent as a GeoJSON boundary when the feed declares a boundary field of type polygon.

The endpoint rejects an undeclared event type or field, a reversed interval, wrong metric or dimension types, missing required dimensions, an oversized batch, an unpublished collection, or a non-stored binding before writing to ClickHouse.

GET …/events/{eventGid} reads one occurrence back, DELETE …/events/{eventGid} removes one, and GET …/events/values?field=venue lists the values the feed already uses. To call an event off, write it back with "status": "cancelled" — the occurrence stays in the feed and consumers see the cancellation; deleting takes it out for everyone.

Events can also be entered by hand in the admin, against the same contract and through the same writer.

Verify the feed and nearby discovery

  1. Find it with GET /v1/catalog/services?type=event.
  2. Follow detailUrl and check the published fields and example.
  3. Send the nearby example to queryUrl and confirm distanceMeters is returned.
  4. Search every visible located feed with POST /v1/events/search.
  5. If it is shared, verify visibility with an entitled consumer token and non-disclosure with a token that has no grant.

Use the integrated query workbench for these checks.