HTTP API: calendars
The 5 operations tagged calendars, each with its parameters, its body and what it answers.
List your calendar feeds
GET /v1/calendars
Your own feeds, newest first. Never the secret, which cannot be recovered.
Yours and nobody else's, including an instance administrator's — which is where this
differs from GET /v1/tokens. A list of somebody's feeds says which projects they watch
and from how many devices, and §20.6 already accepts that a feed URL is a bearer credential
nobody can audit; an inventory of them is the map that makes one worth stealing.
Not paginated, for the reason GET /v1/users gives: how many exist is bounded by how
many somebody made.
Parameters
include_revoked(boolean, in query)format(stringornull, in query): 'full' (default), 'compact' for one aligned line per item, or 'ids' for the addresses alone. Compact is roughly a twentieth the size of full.fields(stringornull, in query): Comma-separated field names to return instead of the whole item, e.g. 'ref,title,due_at'. GET /v1/meta lists what each entity has. Cannot be combined with 'format'.
Responses
200:Collection_Calendar_. Successful Response422:HTTPValidationError. Validation Error
Create a calendar feed
POST /v1/calendars
Mint a feed and return its URL once.
The URL is the credential and it is in this response and in nothing else, ever. Only a hash of the secret is stored, so nothing recovers it afterwards — including this instance. Give it to a calendar application when you receive it, and reset the feed if it leaks.
url is null when this instance has not been told its own public_url. That is not a
failure to build one: the whole URL is the secret, so a host guessed from a request header
would send it wherever that header pointed, every fifteen minutes, for as long as the
subscription lives.
A bounded credential cannot mint one. A feed reads with its owner's own sight rather than with the narrowing on whatever asked for it, so issuing one from a restricted token would hand back more than was presented.
Request body: Create as application/json, required.
Responses
201:IssuedCalendar. Successful Response422:HTTPValidationError. Validation Error
Revoke a calendar feed
DELETE /v1/calendars/{id_or_prefix}
Stop a feed for good, now.
Immediate: revoked_at is read on every poll rather than cached, so there is no window
to wait out. Whoever holds the URL gets the same 404 as somebody who guessed one.
Idempotent, and it keeps the first revocation time — when a credential stopped being trusted is worth not overwriting. The revoked feed is returned rather than an empty 204, so a repeat call is distinguishable from a first one.
Parameters
id_or_prefix(string, in path, required)
Responses
200:Calendar. Successful Response422:HTTPValidationError. Validation Error
Give a feed a new URL
POST /v1/calendars/{id_or_prefix}/reset
Replace a feed's secret, so the URL somebody had stops working immediately.
The feed survives and the subscription does not, which is the point: a leaked URL is fixed without losing the scope, the audience, or the record of when it was last polled. Revoking and making another would lose all three and hand back a different id.
Whoever subscribed to the old URL sees their calendar stop updating and is not told why — there is nobody to tell. Re-subscribing them is the new URL, given to them the same way.
Parameters
id_or_prefix(string, in path, required)
Responses
200:IssuedCalendar. Successful Response422:HTTPValidationError. Validation Error
Fetch a calendar feed
GET /v1/calendars/{prefix}/{secret}.ics
Return one calendar as iCalendar, or 404 if that address names nothing.
The whole credential is rebuilt from the two path segments rather than either being looked
up on its own, so this reaches the same resolve a caller of the domain would — and the
grammar that splits a credential into a prefix and a secret stays in one place.
Parameters
prefix(string, in path, required)secret(string, in path, required)
Responses
200: Successful Response404: No calendar is at that address.422:HTTPValidationError. Validation Error