Docs / Event Data API / Endpoints / List events
List events
Returns events by start time, soonest first. Every timestamp is an RFC 3339 instant in UTC — render it in the venue's own timezone, which for every source live today is Asia/Baku (UTC+4).
Query parameters
| Parameter | Type | Description |
|---|---|---|
q |
string | Full-text match on name, venue and description. |
category |
string | Exact match on the source's own category slug, which is not a closed set — see the field description. `GET /v1/events` with no filter is the only reliable way to learn which values exist today. |
updated_after |
timestamp | Only rows whose `ingested_at` is later than this instant — everything that CHANGED since your last poll, new and re-seen alike. Pass the newest `ingested_at` you have stored. This is what a mirror of the collection should page on; `starts_after` filters on when the EVENT happens, which is a different question. |
starts_after |
timestamp | Events starting at or after this instant. |
starts_before |
timestamp | Events starting at or before this instant. |
limit |
integer | Items per page, 1–100. Defaults to 25. |
cursor |
string | Opaque cursor from a previous response's meta.next. Do not construct one. |
order |
string | Sort field: `ingested_at`, `starts_at`, each optionally prefixed with `-` to reverse. Default is `starts_at`. Rows with no value for the sort column always sort LAST in either direction, so paging never leads with undated rows. |
source |
string | Restrict to ONE scraper source, by its stem — `abb`, not `ABB` or `abb-bank.az`. Not a list: `?source=a,b` and a repeated `?source=` do not select two sources. On `/v1/jobs` an unknown stem is a `400` naming it, and `source_type` is the way to select several sources at once. `GET /v1/sources` lists every stem. |
Request
curl -G https://api.softon.dev/v1/events \
-H "Authorization: Bearer $SOFTON_KEY" \
-d q=gimnastika -d category=cinema -d updated_after=2026-08-16T09:00:00Z
req, _ := http.NewRequestWithContext(ctx, "GET", "https://api.softon.dev/v1/events", nil) req.Header.Set("Authorization", "Bearer "+os.Getenv("SOFTON_KEY")) q := req.URL.Query() q.Set("q", "gimnastika") q.Set("category", "cinema") q.Set("updated_after", "2026-08-16T09:00:00Z") req.URL.RawQuery = q.Encode() res, err := http.DefaultClient.Do(req) if err != nil { log.Fatal(err) } defer res.Body.Close() var page struct { Data []Event `json:"data"` Meta struct{ Next *string `json:"next"` } `json:"meta"` } if err := json.NewDecoder(res.Body).Decode(&page); err != nil { log.Fatal(err) } // page.Meta.Next → send it back as ?cursor= for the following page
import json, os, urllib.parse, urllib.request url = "https://api.softon.dev/v1/events" + "?" + urllib.parse.urlencode({ "q": "gimnastika", "category": "cinema", "updated_after": "2026-08-16T09:00:00Z", }) req = urllib.request.Request(url, headers={ "Authorization": "Bearer " + os.environ["SOFTON_KEY"], }) page = json.load(urllib.request.urlopen(req)) # page["meta"]["next"] → send it back as ?cursor= for the following page
const url = new URL("https://api.softon.dev/v1/events"); url.searchParams.set("q", "gimnastika"); url.searchParams.set("category", "cinema"); url.searchParams.set("updated_after", "2026-08-16T09:00:00Z"); const res = await fetch(url, { headers: { Authorization: `Bearer ${process.env.SOFTON_KEY}` }, }); if (!res.ok) throw new Error(`${res.status} ${await res.text()}`); const { data, meta } = await res.json(); // meta.next → send it back as ?cursor= for the following page
Response
The envelope is identical on every softon.dev API: data, meta, error. Only the shape inside data changes per dataset — see the response envelope.
{
"data": [
{
"id": "iticket:12299",
"source": "iticket",
"name": "The Golden Collection: Pearls of Azerbaijani Fine Art",
"category": "exhibitions",
"venue": {
"id": "museum-center", "name": "Museum Center",
"address": null, "lat": 40.3698087, "lng": 49.8425258
},
"starts_at": "2026-08-05T06:00:00Z",
"ends_at": "2026-09-15T13:00:00Z",
"price": { "min": 7, "max": 10, "currency": "AZN" },
"age_limit": "16+",
"tickets_available": 7199,
"url": "https://iticket.az/az/events/exhibitions/the-golden-collection-pearls-of-azerbaijani-fine-art8749",
"external_url": null,
"ingested_at": "2026-08-04T23:55:46.834186Z"
}
],
"meta": { "count": 1, "next": "eyJvIjoyfQ", "request_id": "req_9Fv3" },
"error": null
}
Fields of each item in data[]
| Field | Type | Description |
|---|---|---|
id |
string | Stable identifier, "<source>:<source id>". |
source |
string | Which scraper produced this event. |
slug |
string · nullable | The source's own readable identifier for the event — what to build a stable, human-readable URL from, rather than the opaque `id`. NOT unique and not an identifier: one source derives it from a film title and a cinema name, so the same film at two cinemas shares a slug. Null where the source publishes none, and a value that stops arriving is kept rather than nulled, because a stale slug is a working link and an empty one is a 404. |
name |
string | Event name as published. |
category |
string · nullable | The source's own category slug, not normalised and not a closed set — it follows the upstream, so it also contains venue and festival names (`hayal-kahvesi`, `gabalafest`). `cinema`, `concerts` and `theatre` are three quarters of the corpus between them; `kids`, `sport`, `seminar`, `master-class`, `circus`, `other` and `exhibitions` make up most of the rest. Do not build a fixed facet from this list — read the values you actually receive. |
venue |
object · nullable | id, name, address, lat, lng. Coordinates where the source geocodes. |
starts_at |
timestamp · nullable | Start time as an RFC 3339 instant in UTC. Convert with the venue's timezone for display — all current venues are Asia/Baku (UTC+4). |
ends_at |
timestamp · nullable | End time in UTC, when the source publishes one. |
price |
object · nullable | min, max and currency across ticket tiers. |
age_limit |
string · nullable | Age restriction as published, e.g. "16+". |
tickets_available |
integer · nullable | Live inventory. null where the source does not expose it — never 0 as a stand-in. |
description |
string · nullable | Editorial copy for the event. |
url |
string · nullable | Canonical page on the source site. |
external_url |
string · nullable | Information or ticketing page. NOT guaranteed to be a purchase link — cinema sources have no dereferenceable buy href. |
poster_url |
string · nullable | Artwork, highest resolution the source offers. |
ingested_at |
timestamp | When this version was stored. |
Try it
Send the request to see a response.