# Tysnes Kalender — developer documentation > Tysnes Kalender is a public events calendar for a local community in Norway. Its events are > available through a public, read-only GraphQL API at https://hvaskjer-staging.web.app/graphQL. No key is required > to read; a free key identifies your application so you are told before a change affects it. ## Pages (markdown) - https://hvaskjer-staging.web.app/utviklere/overview.md — what the API is, the three rules, a first call, why a key - https://hvaskjer-staging.web.app/utviklere/api.md — endpoint, headers, the events query and its filter, pagination, dates, identifiers, price and capacity, errors - https://hvaskjer-staging.web.app/utviklere/reference.md — every type and field, generated from the schema - https://hvaskjer-staging.web.app/utviklere/widget.md — embedding the calendar on another site (JavaScript widget, iframe) - https://hvaskjer-staging.web.app/utviklere/changelog.md — every change to the API or to the data, per licence - https://hvaskjer-staging.web.app/utviklere/schema.graphql — the schema (SDL) Every page is also served as HTML at the same path without `.md`, and as markdown when the request sends `Accept: text/markdown`. ## The three rules 1. IDs are the contract. Filter and match on ids; names and slugs are presentation. Read category labels from the `categories` query on every run. Category ids differ per licence and a retired id is never reused. 2. `startDate` / `endDate` carry the UTC offset in force on the event's date (`+01:00` in winter, `+02:00` in summer), separated from the date by a space. Render in `Europe/Oslo` or use `startTime` (Norwegian wall clock). `startDate` is the next upcoming occurrence; `repetitions` lists only future ones. 3. Nothing that comes from a form is guaranteed numeric. `Price.price` may be `null`; treat every numeric field defensively. ## Keys - Get one: https://hvaskjer-staging.web.app/utviklere/keys (an account on Tysnes Kalender with a verified e-mail address) - Send it: `X-Api-Key: hsk_…` on every request, or `?key=hsk_…` where headers are impossible - Programmatic creation for a signed-in account: POST https://europe-west1-hvaskjer-staging.cloudfunctions.net/createApiKey with `Authorization: Bearer ` and body `{"data":{"name":"my app"}}` ## About - Site: https://hvaskjer-staging.web.app - Site-wide index: https://hvaskjer-staging.web.app/llms.txt - Contact: post@hvaskjerkalender.no