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
- Open Provision → Event feeds → Add event feed.
- Enter a label, stable key, canonical URL, description, classifications, and tags.
- Choose
Localfor a private feed. Choose a broader access value only for the intended sharing policy:Publicmakes 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. - Select the provenance entities and a source binding with Mode = Stored.
- Declare the allowed event types. For attendable events publish
status,attendanceMode,venue, andlocation; addvirtualLocationUrlfor hybrid events. - Save, clear every Ready to publish? blocker, and use Preview.
- Publish and wait for delivery before sending events. Over the API, poll
GET /v1/provision/publicationsand matchobjectGid(your feed's gid) andrevision(the revision the publish returned) untilstateisdelivered— 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
- Find it with
GET /v1/catalog/services?type=event. - Follow
detailUrland check the published fields and example. - Send the nearby example to
queryUrland confirmdistanceMetersis returned. - Search every visible located feed with
POST /v1/events/search. - 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.