v1.0.0 OpenAPI 3.1.0
MeetAgain API
Programmatic access to public events, member-scoped actions (RSVP, comment, image upload), and platform content, monitoring and log sections. Personal Access Token (PAT) authentication is required for non-public endpoints.
Authentication
Personal access token
Authenticate against the API with a Personal Access Token - a long-lived bearer token tied to your account.
For your own CLIs, scripts, or ops jobs. Issue a long-lived bearer token at your access tokens page and revoke it any time from the same page.
Header:
Authorization: Bearer mapat_...
Acts as: you (the token issuer)
cms
CMS page and block authoring. Reserved for users with ROLE_ADMIN.
GET /api/v1/cms/pages List every CMS page with its owning group and per-locale block counts
List every CMS page with its owning group and per-locale block counts
Responses
| Code | Description | |
|---|---|---|
200 |
All CMS pages, newest first | CmsPageSummaryList |
401 |
Missing or invalid bearer token | |
403 |
Insufficient role or scope |
Example request
curl '/api/v1/cms/pages' \
-H "Authorization: Bearer $ACCESS_TOKEN"
GET /api/v1/cms/block-types Catalogue of block types and the fields each one accepts
Catalogue of block types and the fields each one accepts
Responses
| Code | Description | |
|---|---|---|
200 |
Field definitions the write endpoints validate against | CmsBlockTypeCatalog |
401 |
Missing or invalid bearer token | |
403 |
Insufficient role or scope |
Example request
curl '/api/v1/cms/block-types' \
-H "Authorization: Bearer $ACCESS_TOKEN"
DELETE /api/v1/cms/blocks/{blockId} Delete one block
Delete one block
Parameters
| Name | In | Type | Description |
|---|---|---|---|
blockId
*
|
path |
integer
|
Responses
| Code | Description | |
|---|---|---|
204 |
Block deleted | |
401 |
Missing or invalid bearer token | |
403 |
Insufficient role or scope | |
404 |
Block not found |
Example request
curl -X DELETE '/api/v1/cms/blocks/1' \
-H "Authorization: Bearer $ACCESS_TOKEN"
PATCH /api/v1/cms/blocks/{blockId} Overlay fields onto a stored block
Overlay fields onto a stored block
The payload is merged over the stored one, so a partial body only changes the fields it names.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
blockId
*
|
path |
integer
|
Request body
required
Content type: application/json
| Name | Type | Description |
|---|---|---|
type |
any
|
Block type name or numeric id; defaults to the stored type |
payload |
object
|
Responses
| Code | Description | |
|---|---|---|
200 |
The stored block, after hydration and sanitization | CmsBlockSummary |
400 |
Malformed body | |
401 |
Missing or invalid bearer token | |
403 |
Insufficient role or scope | |
404 |
Block not found | |
422 |
Unusable block type or a missing required field | ValidationErrorResponse |
Example request
curl -X PATCH '/api/v1/cms/blocks/1' \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"type":"Text","payload":"value"}'
GET /api/v1/cms/pages/{id}/blocks Ordered blocks of one page in one locale
Ordered blocks of one page in one locale
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id
*
|
path |
integer
|
|
locale
|
query |
string
|
Two-letter language code; defaults to the configured default locale |
Responses
| Code | Description | |
|---|---|---|
200 |
Blocks in priority order | CmsBlockList |
401 |
Missing or invalid bearer token | |
403 |
Insufficient role or scope | |
404 |
Page not found | |
422 |
Unknown locale |
Example request
curl '/api/v1/cms/pages/1/blocks?locale=en' \
-H "Authorization: Bearer $ACCESS_TOKEN"
POST /api/v1/cms/pages/{id}/blocks Append a block to a page in one locale
Append a block to a page in one locale
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id
*
|
path |
integer
|
Request body
required
Content type: application/json
| Name | Type | Description |
|---|---|---|
locale |
string
|
|
type |
any
|
Block type name or numeric id from the block-types catalogue |
payload |
object
|
Responses
| Code | Description | |
|---|---|---|
201 |
The stored block, after hydration and sanitization | CmsBlockSummary |
400 |
Malformed body | |
401 |
Missing or invalid bearer token | |
403 |
Insufficient role or scope | |
404 |
Page not found | |
422 |
Unknown locale, unusable block type, or a missing required field | ValidationErrorResponse |
Example request
curl -X POST '/api/v1/cms/pages/1/blocks' \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"locale":"en","type":"Text","payload":"value"}'
POST /api/v1/cms/blocks/{blockId}/move Move a block one position up or down within its page and locale
Move a block one position up or down within its page and locale
Parameters
| Name | In | Type | Description |
|---|---|---|---|
blockId
*
|
path |
integer
|
Request body
required
Content type: application/json
| Name | Type | Description |
|---|---|---|
direction |
string
|
Responses
| Code | Description | |
|---|---|---|
200 |
The page blocks in their new order | CmsBlockList |
400 |
Malformed body | |
401 |
Missing or invalid bearer token | |
403 |
Insufficient role or scope | |
404 |
Block not found | |
422 |
Direction other than up or down |
Example request
curl -X POST '/api/v1/cms/blocks/1/move' \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"direction":"value"}'
images
Per-language image alt text. Reserved for users with ROLE_ADMIN.
PUT /api/v1/images/{id}/alt Store alt text for one image, keyed by locale
Store alt text for one image, keyed by locale
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id
*
|
path |
integer
|
Request body
required
Content type: application/json
| Name | Type | Description |
|---|---|---|
alt |
object
|
Locale => alt text; empty string unsets |
Responses
| Code | Description | |
|---|---|---|
200 |
Refreshed item with recomputed required/missing locales | MissingAltImageItem |
400 |
Malformed body | |
401 |
Missing or invalid bearer token | |
403 |
Insufficient role or scope | |
404 |
Image not found | |
422 |
A locale outside the image's required set |
Example request
curl -X PUT '/api/v1/images/1/alt' \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"alt":"value"}'
GET /api/v1/images/missing-alt List images missing per-language alt text (keyset-paginated)
List images missing per-language alt text (keyset-paginated)
Parameters
| Name | In | Type | Description |
|---|---|---|---|
after_id
|
query |
integer
|
Keyset cursor: only scan images with a larger ID |
limit
|
query |
integer
|
Candidates scanned per page (matching items may be fewer)
default: 50
|
Responses
| Code | Description | |
|---|---|---|
200 |
Page of images still missing alt text in at least one required locale | MissingAltImageList |
401 |
Missing or invalid bearer token | |
403 |
Insufficient role or scope |
Example request
curl '/api/v1/images/missing-alt?after_id=1&limit=1' \
-H "Authorization: Bearer $ACCESS_TOKEN"
GET /api/v1/images/{id}/content Stream a downscaled preview of the original image
Stream a downscaled preview of the original image
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id
*
|
path |
integer
|
Responses
| Code | Description | |
|---|---|---|
200 |
Preview bytes (usually image/webp; the original media type when conversion fails) | |
401 |
Missing or invalid bearer token | |
403 |
Insufficient role or scope | |
404 |
Image or its original file not found |
Example request
curl '/api/v1/images/1/content' \
-H "Authorization: Bearer $ACCESS_TOKEN"
security
Security incident feed. Read-only, reserved for users with ROLE_ADMIN.
GET /api/v1/security/incidents List recent security incidents
List recent security incidents
Parameters
| Name | In | Type | Description |
|---|---|---|---|
limit
|
query |
integer
|
default: 100
|
since
|
query |
string
(date-time)
|
ISO-8601 datetime lower bound on endedAt |
Responses
| Code | Description | |
|---|---|---|
200 |
Incident list | IncidentList |
401 |
Missing or invalid bearer token | |
403 |
Insufficient role |
Example request
curl '/api/v1/security/incidents?limit=1&since=value' \
-H "Authorization: Bearer $ACCESS_TOKEN"
GET /api/v1/security/incidents/{id} Get a single security incident with full provider reports
Get a single security incident with full provider reports
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id
*
|
path |
integer
|
Responses
| Code | Description | |
|---|---|---|
200 |
Incident detail | IncidentDetail |
401 |
Missing or invalid bearer token | |
403 |
Insufficient role | |
404 |
Incident not found |
Example request
curl '/api/v1/security/incidents/1' \
-H "Authorization: Bearer $ACCESS_TOKEN"
seo
Search-engine monitoring status, issues and actions. Reserved for users with ROLE_ADMIN.
GET /api/v1/seo/status SEO health for one property, with deltas since last pull
SEO health for one property, with deltas since last pull
Parameters
| Name | In | Type | Description |
|---|---|---|---|
property
|
query |
integer
|
Property id; defaults to the first enabled one |
Responses
| Code | Description | |
|---|---|---|
200 |
Compact current state | SeoStatus |
401 |
Missing or invalid bearer token | |
403 |
Insufficient role or scope | |
404 |
No monitored property |
Example request
curl '/api/v1/seo/status?property=1' \
-H "Authorization: Bearer $ACCESS_TOKEN"
GET /api/v1/seo/issues List detected SEO issues
List detected SEO issues
Parameters
| Name | In | Type | Description |
|---|---|---|---|
property
|
query |
integer
|
|
filter
|
query |
string
|
default: open
|
Responses
| Code | Description | |
|---|---|---|
200 |
Issue list | SeoIssueList |
401 |
Missing or invalid bearer token | |
403 |
Insufficient role or scope | |
404 |
No monitored property |
Example request
curl '/api/v1/seo/issues?property=1&filter=value' \
-H "Authorization: Bearer $ACCESS_TOKEN"
GET /api/v1/seo/actions List recently logged SEO actions
List recently logged SEO actions
Parameters
| Name | In | Type | Description |
|---|---|---|---|
limit
|
query |
integer
|
default: 100
|
Responses
| Code | Description | |
|---|---|---|
200 |
Action list | SeoActionList |
401 |
Missing or invalid bearer token | |
403 |
Insufficient role or scope |
Example request
curl '/api/v1/seo/actions?limit=1' \
-H "Authorization: Bearer $ACCESS_TOKEN"
POST /api/v1/seo/actions Log an SEO-relevant action for later attribution
Log an SEO-relevant action for later attribution
Request body
required
Content type: application/json
| Name | Type | Description |
|---|---|---|
kind |
string
|
|
title |
string
|
|
detail |
string | null
|
|
git_sha |
string | null
|
|
issue_id |
integer | null
|
|
occurred_at |
string | null
(date-time)
|
Responses
| Code | Description | |
|---|---|---|
201 |
The stored action | SeoAction |
400 |
Malformed body | |
401 |
Missing or invalid bearer token | |
403 |
Insufficient role or scope | |
422 |
Unknown action kind or unparseable timestamp |
Example request
curl -X POST '/api/v1/seo/actions' \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"kind":"value","title":"value","detail":"value","git_sha":"value","issue_id":"value","occurred_at":"value"}'
logs
Cron and email send logs. Read-only, reserved for users with ROLE_ADMIN.
GET /api/v1/logs/cron List recent cron run log entries
List recent cron run log entries
Parameters
| Name | In | Type | Description |
|---|---|---|---|
limit
|
query |
integer
|
default: 100
|
Responses
| Code | Description | |
|---|---|---|
200 |
Paginated cron log list | CronLogList |
401 |
Missing or invalid bearer token | |
403 |
Insufficient role |
Example request
curl '/api/v1/logs/cron?limit=1' \
-H "Authorization: Bearer $ACCESS_TOKEN"
GET /api/v1/logs/sendlog List email send-log entries
List email send-log entries
Parameters
| Name | In | Type | Description |
|---|---|---|---|
limit
|
query |
integer
|
default: 100
|
Responses
| Code | Description | |
|---|---|---|
200 |
Paginated sendlog list | SendlogList |
401 |
Missing or invalid bearer token | |
403 |
Insufficient role |
Example request
curl '/api/v1/logs/sendlog?limit=1' \
-H "Authorization: Bearer $ACCESS_TOKEN"
GET /api/v1/logs/cron/{id} Get a single cron log entry
Get a single cron log entry
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id
*
|
path |
integer
|
Responses
| Code | Description | |
|---|---|---|
200 |
Cron log detail | CronLogDetail |
401 |
Missing or invalid bearer token | |
403 |
Insufficient role | |
404 |
Cron log not found |
Example request
curl '/api/v1/logs/cron/1' \
-H "Authorization: Bearer $ACCESS_TOKEN"
GET /api/v1/logs/sendlog/{id} Get a single send-log entry
Get a single send-log entry
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id
*
|
path |
integer
|
Responses
| Code | Description | |
|---|---|---|
200 |
Sendlog detail | SendlogDetail |
401 |
Missing or invalid bearer token | |
403 |
Insufficient role | |
404 |
Sendlog entry not found |
Example request
curl '/api/v1/logs/sendlog/1' \
-H "Authorization: Bearer $ACCESS_TOKEN"
auth
Sign in with email and password to obtain a personal access token
POST /api/v1/auth/login Sign in and receive a personal access token
Sign in and receive a personal access token
Issues a new personal access token for this device and revokes the one an earlier sign-in issued for the same device name. Send it as a Bearer token on every call and sign in again on a 401.
Request body
required
Content type: application/json
| Name | Type | Description |
|---|---|---|
email |
string
(email)
|
|
password |
string
(password)
|
|
deviceName |
string
|
Stable name of this installation, shown to the member in their token list |
Responses
| Code | Description | |
|---|---|---|
200 |
Signed in | LoginResult |
400 |
Malformed body or invalid device name (bad_request, invalid_device_name) | ErrorResponse |
401 |
Wrong email or password (invalid_credentials) | ErrorResponse |
403 |
The account cannot sign in yet or any more (account_blocked, email_not_verified, pending_approval); the member fixes it on the website | ErrorResponse |
429 |
Too many attempts (too_many_attempts, with Retry-After) or login protection active (login_restricted); sign in on the website | ErrorResponse |
Example request
curl -X POST '/api/v1/auth/login' \
-H "Content-Type: application/json" \
-d '{"email":"value","password":"value","deviceName":"value"}'
POST /api/v1/auth/logout Sign out and revoke the calling token
Sign out and revoke the calling token
Responses
| Code | Description | |
|---|---|---|
204 |
Token revoked | |
401 |
Missing or invalid Bearer token |
Example request
curl -X POST '/api/v1/auth/logout' \
-H "Authorization: Bearer $ACCESS_TOKEN"
community
GET /api/v1/community/blocks List the members the caller has blocked
List the members the caller has blocked
Responses
| Code | Description | |
|---|---|---|
200 |
Blocked members | MemberList |
401 |
Missing or invalid Bearer token |
Example request
curl '/api/v1/community/blocks' \
-H "Authorization: Bearer $ACCESS_TOKEN"
GET /api/v1/community/members List platform members
List platform members
Members the calling member may see, blocked ones excluded. A member who opted out of the directory is left out here too, exactly as on the website; their profile stays reachable by id.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
limit
|
query |
integer
|
default: 20
|
offset
|
query |
integer
|
default: 0
|
Responses
| Code | Description | |
|---|---|---|
200 |
Members | MemberList |
401 |
Missing or invalid Bearer token |
Example request
curl '/api/v1/community/members?limit=1&offset=1' \
-H "Authorization: Bearer $ACCESS_TOKEN"
POST /api/v1/community/blocks/{id} Block a member
Block a member
Blocking drops any follow in either direction and hides the conversation from both inboxes. Repeating the call is safe.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id
*
|
path |
integer
|
Responses
| Code | Description | |
|---|---|---|
204 |
Blocked | |
401 |
Missing or invalid Bearer token | |
404 |
No such member (not_found) | ErrorResponse |
422 |
Blocking yourself (self_target) | ErrorResponse |
Example request
curl -X POST '/api/v1/community/blocks/1' \
-H "Authorization: Bearer $ACCESS_TOKEN"
DELETE /api/v1/community/blocks/{id} Unblock a member
Unblock a member
Repeating the call is safe. Unblocking does not restore a follow that blocking removed.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id
*
|
path |
integer
|
Responses
| Code | Description | |
|---|---|---|
204 |
Not blocked | |
401 |
Missing or invalid Bearer token | |
404 |
No such member (not_found) | ErrorResponse |
Example request
curl -X DELETE '/api/v1/community/blocks/1' \
-H "Authorization: Bearer $ACCESS_TOKEN"
GET /api/v1/community/members/{id} Read one member profile
Read one member profile
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id
*
|
path |
integer
|
Responses
| Code | Description | |
|---|---|---|
200 |
The member profile | MemberProfile |
401 |
Missing or invalid Bearer token | |
403 |
The member has blocked the caller (forbidden) | ErrorResponse |
404 |
No such member (not_found) | ErrorResponse |
Example request
curl '/api/v1/community/members/1' \
-H "Authorization: Bearer $ACCESS_TOKEN"
GET /api/v1/community/conversations List the calling member conversations
List the calling member conversations
One entry per partner, newest first. Partners blocked in either direction are left out.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
limit
|
query |
integer
|
default: 20
|
offset
|
query |
integer
|
default: 0
|
Responses
| Code | Description | |
|---|---|---|
200 |
Conversations | ConversationList |
401 |
Missing or invalid Bearer token | |
403 |
Token without the community:read scope (insufficient_scope) | ErrorResponse |
Example request
curl '/api/v1/community/conversations?limit=1&offset=1' \
-H "Authorization: Bearer $ACCESS_TOKEN"
PATCH /api/v1/community/messages/{id} Edit a message inside the edit window
Edit a message inside the edit window
A message can be edited for ten minutes after it was sent. The website answers 403 here; this surface answers 409, because the window is a state conflict rather than an authorisation failure.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id
*
|
path |
integer
|
Request body
required
Content type: application/json
| Name | Type | Description |
|---|---|---|
content |
string
|
Responses
| Code | Description | |
|---|---|---|
200 |
The stored message | ThreadMessage |
401 |
Missing or invalid Bearer token | |
404 |
No such message, or it was sent by someone else (not_found) | ErrorResponse |
409 |
The ten-minute window has passed (edit_window_expired) | ErrorResponse |
422 |
content_required or content_too_long | ErrorResponse |
Example request
curl -X PATCH '/api/v1/community/messages/1' \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"content":"value"}'
POST /api/v1/community/members/{id}/follow Follow a member
Follow a member
Repeating the call is safe: it states the wanted end state rather than toggling.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id
*
|
path |
integer
|
Responses
| Code | Description | |
|---|---|---|
204 |
Following | |
401 |
Missing or invalid Bearer token | |
404 |
No such member (not_found) | ErrorResponse |
409 |
A block in either direction (blocked) | ErrorResponse |
422 |
Following yourself (self_target) | ErrorResponse |
Example request
curl -X POST '/api/v1/community/members/1/follow' \
-H "Authorization: Bearer $ACCESS_TOKEN"
DELETE /api/v1/community/members/{id}/follow Stop following a member
Stop following a member
Repeating the call is safe.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id
*
|
path |
integer
|
Responses
| Code | Description | |
|---|---|---|
204 |
Not following | |
401 |
Missing or invalid Bearer token | |
404 |
No such member (not_found) | ErrorResponse |
Example request
curl -X DELETE '/api/v1/community/members/1/follow' \
-H "Authorization: Bearer $ACCESS_TOKEN"
GET /api/v1/community/groups/{slug}/members List the members of one group
List the members of one group
The same list scoped to one group. A group the caller cannot reach answers the same 404 as an unknown slug; reaching a Private or Hidden group needs a token that also carries me:read, because membership is resolved through that scope.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
slug
*
|
path |
string
|
|
limit
|
query |
integer
|
default: 20
|
offset
|
query |
integer
|
default: 0
|
Responses
| Code | Description | |
|---|---|---|
200 |
Members of that group | MemberList |
401 |
Missing or invalid Bearer token | |
404 |
Group not found or not reachable (not_found) | ErrorResponse |
Example request
curl '/api/v1/community/groups/slug/members?limit=1&offset=1' \
-H "Authorization: Bearer $ACCESS_TOKEN"
GET /api/v1/community/conversations/{userId} Read one thread
Read one thread
Oldest first. This read is pure: it does not mark the thread read, unlike opening the page on the website. Call POST /api/v1/community/conversations/{userId}/read for that.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
userId
*
|
path |
integer
|
|
limit
|
query |
integer
|
default: 20
|
offset
|
query |
integer
|
default: 0
|
Responses
| Code | Description | |
|---|---|---|
200 |
The thread | MessageThread |
401 |
Missing or invalid Bearer token | |
404 |
No such member (not_found) | ErrorResponse |
Example request
curl '/api/v1/community/conversations/1?limit=1&offset=1' \
-H "Authorization: Bearer $ACCESS_TOKEN"
POST /api/v1/community/conversations/{userId} Send a direct message
Send a direct message
Parameters
| Name | In | Type | Description |
|---|---|---|---|
userId
*
|
path |
integer
|
Request body
required
Content type: application/json
| Name | Type | Description |
|---|---|---|
content |
string
|
Responses
| Code | Description | |
|---|---|---|
201 |
The stored message | ThreadMessage |
401 |
Missing or invalid Bearer token | |
404 |
No such member (not_found) | ErrorResponse |
409 |
A block in either direction (blocked) | ErrorResponse |
422 |
content_required, content_too_long or self_target | ErrorResponse |
Example request
curl -X POST '/api/v1/community/conversations/1' \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"content":"value"}'
POST /api/v1/community/conversations/{userId}/read Mark a thread read
Mark a thread read
Parameters
| Name | In | Type | Description |
|---|---|---|---|
userId
*
|
path |
integer
|
Responses
| Code | Description | |
|---|---|---|
204 |
Marked read | |
401 |
Missing or invalid Bearer token | |
404 |
No such member (not_found) | ErrorResponse |
Example request
curl -X POST '/api/v1/community/conversations/1/read' \
-H "Authorization: Bearer $ACCESS_TOKEN"
GET /api/v1/community/groups/{slug}/town-hall/topics List the Town Hall topics of one group
List the Town Hall topics of one group
The whole forum tree of the group, depth first, as the website loads it. Not paged. A group without Town Hall, or one whose Town Hall is closed to the caller, answers 404 - the same answer as an unknown slug.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
slug
*
|
path |
string
|
Responses
| Code | Description | |
|---|---|---|
200 |
The topic tree | TopicList |
401 |
Missing or invalid Bearer token | |
404 |
Group not found, not reachable, or Town Hall closed to the caller (not_found) | ErrorResponse |
Example request
curl '/api/v1/community/groups/slug/town-hall/topics' \
-H "Authorization: Bearer $ACCESS_TOKEN"
POST /api/v1/community/groups/{slug}/town-hall/topics Start a topic or a subtopic
Start a topic or a subtopic
Parameters
| Name | In | Type | Description |
|---|---|---|---|
slug
*
|
path |
string
|
Request body
required
Content type: application/json
| Name | Type | Description |
|---|---|---|
title |
string
|
|
parentId |
integer | null
|
Start a subtopic of this topic. |
Responses
| Code | Description | |
|---|---|---|
201 |
Topic created | Topic |
401 |
Missing or invalid Bearer token | |
404 |
Group or parent topic not found, or Town Hall closed to the caller (not_found) | ErrorResponse |
422 |
empty_title, title_too_long or too_deep | ErrorResponse |
Example request
curl -X POST '/api/v1/community/groups/slug/town-hall/topics' \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"title":"value","parentId":"value"}'
GET /api/v1/community/groups/{slug}/town-hall/gallery List the Town Hall gallery of one group
List the Town Hall gallery of one group
The photos uploaded to the group's events, newest first, each with its event. Photos reported by a member are left out, as on the event page.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
slug
*
|
path |
string
|
|
limit
|
query |
integer
|
default: 20
|
offset
|
query |
integer
|
default: 0
|
locale
|
query |
string
|
Language of the event titles |
Responses
| Code | Description | |
|---|---|---|
200 |
A page of photos | GalleryList |
401 |
Missing or invalid Bearer token | |
404 |
Group not found, not reachable, or Town Hall closed to the caller (not_found) | ErrorResponse |
Example request
curl '/api/v1/community/groups/slug/town-hall/gallery?limit=1&offset=1&locale=en' \
-H "Authorization: Bearer $ACCESS_TOKEN"
DELETE /api/v1/community/groups/{slug}/town-hall/topics/{id} Delete a topic
Delete a topic
The author may delete a topic while it has no subtopics and no replies; an admin deletes it with its whole subtree.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
slug
*
|
path |
string
|
|
id
*
|
path |
integer
|
Responses
| Code | Description | |
|---|---|---|
204 |
Topic deleted | |
401 |
Missing or invalid Bearer token | |
403 |
Not allowed to delete it (forbidden) | ErrorResponse |
404 |
Group or topic not found, or Town Hall closed to the caller (not_found) | ErrorResponse |
Example request
curl -X DELETE '/api/v1/community/groups/slug/town-hall/topics/1' \
-H "Authorization: Bearer $ACCESS_TOKEN"
PATCH /api/v1/community/groups/{slug}/town-hall/topics/{id} Rename a topic (author or admin)
Rename a topic (author or admin)
Parameters
| Name | In | Type | Description |
|---|---|---|---|
slug
*
|
path |
string
|
|
id
*
|
path |
integer
|
Request body
required
Content type: application/json
| Name | Type | Description |
|---|---|---|
title |
string
|
Responses
| Code | Description | |
|---|---|---|
200 |
Topic renamed | Topic |
401 |
Missing or invalid Bearer token | |
403 |
Not the author and not admin (forbidden) | ErrorResponse |
404 |
Group or topic not found, or Town Hall closed to the caller (not_found) | ErrorResponse |
422 |
empty_title or title_too_long | ErrorResponse |
Example request
curl -X PATCH '/api/v1/community/groups/slug/town-hall/topics/1' \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"title":"value"}'
GET /api/v1/community/groups/{slug}/town-hall/topics/{id}/replies List the replies to a topic
List the replies to a topic
Newest first, paged backwards like event comments: pass the previous page's nextBefore.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
slug
*
|
path |
string
|
|
id
*
|
path |
integer
|
|
before
|
query |
integer
|
Only replies older than this reply id |
limit
|
query |
integer
|
default: 20
|
Responses
| Code | Description | |
|---|---|---|
200 |
A page of replies | CommentList |
401 |
Missing or invalid Bearer token | |
404 |
Group or topic not found, or Town Hall closed to the caller (not_found) | ErrorResponse |
Example request
curl '/api/v1/community/groups/slug/town-hall/topics/1/replies?before=1&limit=1' \
-H "Authorization: Bearer $ACCESS_TOKEN"
POST /api/v1/community/groups/{slug}/town-hall/topics/{id}/replies Reply to a topic
Reply to a topic
Parameters
| Name | In | Type | Description |
|---|---|---|---|
slug
*
|
path |
string
|
|
id
*
|
path |
integer
|
Request body
required
Content type: application/json
| Name | Type | Description |
|---|---|---|
content |
string
|
Responses
| Code | Description | |
|---|---|---|
201 |
Reply created | CommentCreated |
401 |
Missing or invalid Bearer token | |
404 |
Group or topic not found, or Town Hall closed to the caller (not_found) | ErrorResponse |
422 |
content_required or content_too_long | ErrorResponse |
Example request
curl -X POST '/api/v1/community/groups/slug/town-hall/topics/1/replies' \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"content":"value"}'
DELETE /api/v1/community/groups/{slug}/town-hall/topics/{id}/replies/{replyId} Delete a reply (own or admin)
Delete a reply (own or admin)
Parameters
| Name | In | Type | Description |
|---|---|---|---|
slug
*
|
path |
string
|
|
id
*
|
path |
integer
|
|
replyId
*
|
path |
integer
|
Responses
| Code | Description | |
|---|---|---|
204 |
Reply deleted | |
401 |
Missing or invalid Bearer token | |
403 |
Not your reply and not admin (forbidden) | ErrorResponse |
404 |
Group, topic or reply not found, a reply to another topic, or Town Hall closed to the caller (not_found) | ErrorResponse |
Example request
curl -X DELETE '/api/v1/community/groups/slug/town-hall/topics/1/replies/1' \
-H "Authorization: Bearer $ACCESS_TOKEN"
event-actions
Authenticated user actions on events: RSVP, comments, image upload
PUT /api/v1/events/{id}/rsvp Set RSVP and guests on an event
Set RSVP and guests on an event
Idempotent: sets the RSVP and the guest count in one call and answers the resulting state.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id
*
|
path |
integer
|
Request body
required
Content type: application/json
| Name | Type | Description |
|---|---|---|
going |
boolean
|
|
guests |
integer
|
Guests the member brings, 0 to 5; ignored when not going |
Responses
| Code | Description | |
|---|---|---|
200 |
Resulting RSVP state | RsvpResult |
401 |
Missing or invalid Bearer token | |
403 |
Not allowed (not_a_member) | ErrorResponse |
404 |
Event not found | ErrorResponse |
409 |
Event canceled or already started (event_canceled, event_started) | ErrorResponse |
400 |
Body is not an object, or going is not a boolean (bad_request) | ErrorResponse |
422 |
Guest count out of range (validation_failed) | ErrorResponse |
Example request
curl -X PUT '/api/v1/events/1/rsvp' \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"going":"value","guests":"value"}'
POST /api/v1/events/{id}/rsvp RSVP yes to an event
RSVP yes to an event
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id
*
|
path |
integer
|
Responses
| Code | Description | |
|---|---|---|
200 |
RSVP added (or already present) | RsvpResult |
401 |
Missing or invalid Bearer token | |
403 |
Not allowed (group membership / blocked) | ErrorResponse |
404 |
Event not found | ErrorResponse |
409 |
Event canceled or already started | ErrorResponse |
Example request
curl -X POST '/api/v1/events/1/rsvp' \
-H "Authorization: Bearer $ACCESS_TOKEN"
DELETE /api/v1/events/{id}/rsvp Remove RSVP from an event
Remove RSVP from an event
Withdrawing is never refused: a canceled event, an event that has started and a lost group membership all still let the member off the attendee list.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id
*
|
path |
integer
|
Responses
| Code | Description | |
|---|---|---|
200 |
RSVP removed (or already absent) | RsvpResult |
401 |
Missing or invalid Bearer token | |
404 |
Event not found | ErrorResponse |
Example request
curl -X DELETE '/api/v1/events/1/rsvp' \
-H "Authorization: Bearer $ACCESS_TOKEN"
GET /api/v1/events/{id}/images List the photos of an event
List the photos of an event
The photos of the event in every generated size. Photos reported by a member are left out, as on the event page.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id
*
|
path |
integer
|
Responses
| Code | Description | |
|---|---|---|
200 |
The photos of the event | ImageList |
401 |
Missing or invalid Bearer token | |
403 |
Token without the event-actions:read scope (insufficient_scope) | ErrorResponse |
404 |
Event not found or not visible to the caller (not_found) | ErrorResponse |
Example request
curl '/api/v1/events/1/images' \
-H "Authorization: Bearer $ACCESS_TOKEN"
POST /api/v1/events/{id}/images Upload an image to an event
Upload an image to an event
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id
*
|
path |
integer
|
Request body
required
Content type: multipart/form-data
| Name | Type | Description |
|---|---|---|
file |
string
(binary)
|
Responses
| Code | Description | |
|---|---|---|
201 |
Image uploaded | ImageUploaded |
400 |
file_required, file_rejected or upload_failed | ErrorResponse |
401 |
Missing or invalid Bearer token | |
403 |
Not allowed | ErrorResponse |
404 |
Event not found | ErrorResponse |
Example request
curl -X POST '/api/v1/events/1/images' \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-F "file=@/path/to/file"
GET /api/v1/events/{id}/comments List the comments on an event
List the comments on an event
Newest first, as on the event page. Page backwards by passing the previous page's nextBefore.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id
*
|
path |
integer
|
|
before
|
query |
integer
|
Only comments older than this comment id |
limit
|
query |
integer
|
default: 25
|
Responses
| Code | Description | |
|---|---|---|
200 |
A page of comments | CommentList |
401 |
Missing or invalid Bearer token | |
403 |
Token without the event-actions:read scope (insufficient_scope) | ErrorResponse |
404 |
Event not found or not visible to the caller (not_found) | ErrorResponse |
Example request
curl '/api/v1/events/1/comments?before=1&limit=1' \
-H "Authorization: Bearer $ACCESS_TOKEN"
POST /api/v1/events/{id}/comments Post a comment on an event
Post a comment on an event
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id
*
|
path |
integer
|
Request body
required
Content type: application/json
| Name | Type | Description |
|---|---|---|
content |
string
|
Responses
| Code | Description | |
|---|---|---|
201 |
Comment created | CommentCreated |
400 |
content_required or content_too_long | ErrorResponse |
401 |
Missing or invalid Bearer token | |
403 |
Not allowed | ErrorResponse |
404 |
Event not found | ErrorResponse |
Example request
curl -X POST '/api/v1/events/1/comments' \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"content":"value"}'
GET /api/v1/events/{id}/attendees List who is coming to an event
List who is coming to an event
Who is coming, as the event page shows it to a signed-in member: the people who RSVPed with their guests, plus the organizer-maintained external count.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id
*
|
path |
integer
|
Responses
| Code | Description | |
|---|---|---|
200 |
The people coming | AttendeeList |
401 |
Missing or invalid Bearer token | |
403 |
Token without the event-actions:read scope (insufficient_scope) | ErrorResponse |
404 |
Event not found or not visible to the caller (not_found) | ErrorResponse |
Example request
curl '/api/v1/events/1/attendees' \
-H "Authorization: Bearer $ACCESS_TOKEN"
GET /api/v1/events/{id}/occurrences List the other dates of a recurring meeting
List the other dates of a recurring meeting
The upcoming visible events of the same recurring series, each with the caller's own RSVP state. An event without a series answers with itself.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id
*
|
path |
integer
|
Responses
| Code | Description | |
|---|---|---|
200 |
Upcoming occurrences of the series | EventList |
401 |
Missing or invalid Bearer token | |
404 |
Event not found | ErrorResponse |
Example request
curl '/api/v1/events/1/occurrences' \
-H "Authorization: Bearer $ACCESS_TOKEN"
DELETE /api/v1/events/{id}/images/{imageId} Delete an event image (own upload or admin)
Delete an event image (own upload or admin)
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id
*
|
path |
integer
|
|
imageId
*
|
path |
integer
|
Responses
| Code | Description | |
|---|---|---|
204 |
Image deleted | |
401 |
Missing or invalid Bearer token | |
403 |
Not your image and not admin | ErrorResponse |
404 |
Image or event not found | ErrorResponse |
Example request
curl -X DELETE '/api/v1/events/1/images/1' \
-H "Authorization: Bearer $ACCESS_TOKEN"
DELETE /api/v1/events/{id}/comments/{commentId} Delete an event comment (own or admin)
Delete an event comment (own or admin)
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id
*
|
path |
integer
|
|
commentId
*
|
path |
integer
|
Responses
| Code | Description | |
|---|---|---|
204 |
Comment deleted | |
401 |
Missing or invalid Bearer token | |
403 |
Not your comment and not admin | ErrorResponse |
404 |
Comment or event not found | ErrorResponse |
Example request
curl -X DELETE '/api/v1/events/1/comments/1' \
-H "Authorization: Bearer $ACCESS_TOKEN"
events
Public event listings and detail
GET /api/v1/events List public upcoming events
List public upcoming events
Parameters
| Name | In | Type | Description |
|---|---|---|---|
locale
|
query |
string
|
|
from
|
query |
string
(date-time)
|
ISO-8601 lower bound (default: now) |
to
|
query |
string
(date-time)
|
ISO-8601 upper bound |
limit
|
query |
integer
|
default: 20
|
offset
|
query |
integer
|
default: 0
|
group
|
query |
string
|
Group slug; an unknown slug returns an empty list |
Responses
| Code | Description | |
|---|---|---|
200 |
Paginated event list | EventList |
Example request
curl '/api/v1/events?locale=en&from=value&to=value&limit=1&offset=1&group=weiqi-club'
GET /api/v1/events/{id} Get a single event by ID
Get a single event by ID
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id
*
|
path |
integer
|
|
locale
|
query |
string
|
Responses
| Code | Description | |
|---|---|---|
200 |
Event detail | EventDetail |
404 |
Event not found or not visible in current context | ErrorResponse |
Example request
curl '/api/v1/events/1?locale=value'
group-admin
Group-scoped admin actions. Requires Owner or Organizer role in the named group, or platform ROLE_ADMIN.
GET /api/v1/groups/{groupSlug}/admin/members List members of a group
List members of a group
Parameters
| Name | In | Type | Description |
|---|---|---|---|
groupSlug
*
|
path |
string
|
Responses
| Code | Description | |
|---|---|---|
200 |
Members list | GroupMemberList |
401 |
Missing or invalid bearer token | |
403 |
Caller is not Owner/Organizer of this group | |
404 |
Group not found | ErrorResponse |
Example request
curl '/api/v1/groups/groupSlug/admin/members' \
-H "Authorization: Bearer $ACCESS_TOKEN"
GET /api/v1/groups/{groupSlug}/admin/settings Read a group settings
Read a group settings
Parameters
| Name | In | Type | Description |
|---|---|---|---|
groupSlug
*
|
path |
string
|
Responses
| Code | Description | |
|---|---|---|
200 |
Group settings | GroupSettings |
401 |
Missing or invalid bearer token | |
403 |
Caller is not Owner/Organizer of this group | |
404 |
Group not found | ErrorResponse |
Example request
curl '/api/v1/groups/weiqi-club/admin/settings' \
-H "Authorization: Bearer $ACCESS_TOKEN"
groups
Tenant groups (multisite)
GET /api/v1/groups List active groups
List active groups
Responses
| Code | Description | |
|---|---|---|
200 |
Array of group summaries | GroupList |
Example request
curl '/api/v1/groups'
GET /api/v1/groups/{groupSlug} Get a group by slug
Get a group by slug
Parameters
| Name | In | Type | Description |
|---|---|---|---|
groupSlug
*
|
path |
string
|
Responses
| Code | Description | |
|---|---|---|
200 |
Group detail | GroupDetail |
404 |
Group not found | ErrorResponse |
Example request
curl '/api/v1/groups/groupSlug'
GET /api/v1/groups/{groupSlug}/cms List a group's CMS pages
List a group's CMS pages
Parameters
| Name | In | Type | Description |
|---|---|---|---|
groupSlug
*
|
path |
string
|
|
language
|
query |
string
|
Two-letter language code. If omitted, each item's first available language is used. If given but the page lacks that language, falls back to 'en' (or the first available). |
Responses
| Code | Description | |
|---|---|---|
200 |
List of CMS pages | CmsPageList |
404 |
Group not found | ErrorResponse |
Example request
curl '/api/v1/groups/weiqi-club/cms?language=en'
GET /api/v1/groups/{groupSlug}/cms/{cmsSlug} Get a CMS page metadata by group and slug
Get a CMS page metadata by group and slug
Parameters
| Name | In | Type | Description |
|---|---|---|---|
groupSlug
*
|
path |
string
|
|
cmsSlug
*
|
path |
string
|
|
language
|
query |
string
|
Responses
| Code | Description | |
|---|---|---|
200 |
CMS page metadata | CmsPage |
404 |
Group not found, or page not found / not visible in this group | ErrorResponse |
Example request
curl '/api/v1/groups/platform/cms/about?language=value'
me
Authenticated user (token-scoped reads)
GET /api/v1/me Get the authenticated user profile
Get the authenticated user profile
Responses
| Code | Description | |
|---|---|---|
200 |
User profile | MeProfile |
401 |
Missing or invalid Bearer token |
Example request
curl '/api/v1/me' \
-H "Authorization: Bearer $ACCESS_TOKEN"
PATCH /api/v1/me Edit the authenticated member profile
Edit the authenticated member profile
Only the fields present in the body change. The name follows the website rule: a name already stored above the cap keeps working, but a change has to fit it.
Request body
required
Content type: application/json
| Name | Type | Description |
|---|---|---|
name |
string
|
|
bio |
string | null
|
|
locale |
string
|
One of the languages enabled on this platform |
public |
boolean
|
Responses
| Code | Description | |
|---|---|---|
200 |
The saved profile | MeProfile |
401 |
Missing or invalid Bearer token | |
403 |
Token without the me:write scope (insufficient_scope) | ErrorResponse |
422 |
A field was rejected (validation_failed); errors names them: name_required, name_too_long, locale_not_enabled, bio_invalid, public_invalid | ValidationErrorResponse |
Example request
curl -X PATCH '/api/v1/me' \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"value","bio":"value","locale":"value","public":"value"}'
GET /api/v1/me/rsvps List the authenticated user upcoming RSVPs
List the authenticated user upcoming RSVPs
Parameters
| Name | In | Type | Description |
|---|---|---|---|
locale
|
query |
string
|
Language code; overrides Accept-Language |
Responses
| Code | Description | |
|---|---|---|
200 |
Array of upcoming events the user has RSVPed to | MeRsvpList |
401 |
Missing or invalid Bearer token |
Example request
curl '/api/v1/me/rsvps?locale=en' \
-H "Authorization: Bearer $ACCESS_TOKEN"
POST /api/v1/me/avatar Replace the authenticated member avatar
Replace the authenticated member avatar
Replaces the member avatar. The previous picture stays in the member own gallery, as on the website.
Request body
required
Content type: multipart/form-data
| Name | Type | Description |
|---|---|---|
file |
string
(binary)
|
Responses
| Code | Description | |
|---|---|---|
200 |
The profile with its new avatar | MeProfile |
400 |
file_required, file_rejected or upload_failed | ErrorResponse |
401 |
Missing or invalid Bearer token | |
403 |
Token without the me:write scope (insufficient_scope) | ErrorResponse |
Example request
curl -X POST '/api/v1/me/avatar' \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-F "file=@/path/to/file"
GET /api/v1/me/groups List the groups of the authenticated member
List the groups of the authenticated member
Every group the member belongs to or has asked to join, including the ones that blocked them, each with the role and the membership status.
Responses
| Code | Description | |
|---|---|---|
200 |
The memberships of the authenticated member | MembershipList |
401 |
Missing or invalid Bearer token |
Example request
curl '/api/v1/me/groups' \
-H "Authorization: Bearer $ACCESS_TOKEN"
GET /api/v1/me/events List the upcoming meetings of the authenticated member
List the upcoming meetings of the authenticated member
The upcoming events of the member's groups plus the visible upcoming events they RSVPed to elsewhere, canceled ones included and flagged.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
from
|
query |
string
(date-time)
|
ISO-8601 lower bound (default: now) |
limit
|
query |
integer
|
default: 20
|
offset
|
query |
integer
|
default: 0
|
locale
|
query |
string
|
Language code; overrides Accept-Language |
Responses
| Code | Description | |
|---|---|---|
200 |
Paginated event list | EventList |
401 |
Missing or invalid Bearer token |
Example request
curl '/api/v1/me/events?from=value&limit=1&offset=1&locale=en' \
-H "Authorization: Bearer $ACCESS_TOKEN"
POST /api/v1/me/signal-token Issue the notification signal token for this device
Issue the notification signal token for this device
Issues a second token for the calling app device that can only read GET /api/v1/signal, valid for 90 days. Asking again replaces it, and revoking the device app token revokes it too.
Responses
| Code | Description | |
|---|---|---|
201 |
The signal token | SignalTokenResult |
400 |
The calling token was not issued by the API login (not_an_app_token) | ErrorResponse |
401 |
Missing or invalid Bearer token | |
403 |
Token without the me:write scope (insufficient_scope) | ErrorResponse |
Example request
curl -X POST '/api/v1/me/signal-token' \
-H "Authorization: Bearer $ACCESS_TOKEN"
GET /api/v1/me/notifications List the authenticated member notifications
List the authenticated member notifications
The website navbar bell, as data. Every item is computed live from the same providers the website uses; nothing is stored, so there is no read state, no history and no cursor. Labels come back in the request locale.
Responses
| Code | Description | |
|---|---|---|
200 |
The bell | NotificationList |
401 |
Missing or invalid Bearer token | |
403 |
Token without the me:read scope (insufficient_scope) | ErrorResponse |
Example request
curl '/api/v1/me/notifications' \
-H "Authorization: Bearer $ACCESS_TOKEN"
GET /api/v1/me/push-subscriptions List the registered push devices
List the registered push devices
Also carries the VAPID public key a client needs before it can subscribe, and whether push is configured on this platform at all.
Responses
| Code | Description | |
|---|---|---|
200 |
The registered devices | PushSubscriptionList |
401 |
Missing or invalid Bearer token | |
403 |
Token without the me:read scope (insufficient_scope) | ErrorResponse |
Example request
curl '/api/v1/me/push-subscriptions' \
-H "Authorization: Bearer $ACCESS_TOKEN"
POST /api/v1/me/push-subscriptions Register a push device
Register a push device
Registers a Web Push endpoint against the calling token, so revoking the device at /profile/access-tokens stops its pings. Re-posting a known endpoint moves it to the calling device and answers 200.
Request body
required
Content type: application/json
| Name | Type | Description |
|---|---|---|
endpoint |
string
|
|
p256dh |
string
|
|
auth |
string
|
|
transport |
string
|
Responses
| Code | Description | |
|---|---|---|
200 |
A known endpoint was updated | PushSubscriptionEntry |
201 |
The endpoint was registered | PushSubscriptionEntry |
401 |
Missing or invalid Bearer token | |
403 |
Token without the me:write scope (insufficient_scope) | ErrorResponse |
422 |
validation_failed, endpoint_rejected or too_many_subscriptions | ValidationErrorResponse |
503 |
No VAPID key is configured on this platform (push_unavailable) | ErrorResponse |
Example request
curl -X POST '/api/v1/me/push-subscriptions' \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"endpoint":"value","p256dh":"value","auth":"value","transport":"value"}'
GET /api/v1/me/notification-settings Read the authenticated member notification preferences
Read the authenticated member notification preferences
The same master switch and six toggles the member edits at /profile/config.
Responses
| Code | Description | |
|---|---|---|
200 |
The stored preferences | MeNotificationSettings |
401 |
Missing or invalid Bearer token | |
403 |
Token without the me:read scope (insufficient_scope) | ErrorResponse |
Example request
curl '/api/v1/me/notification-settings' \
-H "Authorization: Bearer $ACCESS_TOKEN"
PATCH /api/v1/me/notification-settings Edit the authenticated member notification preferences
Edit the authenticated member notification preferences
Only the keys present in the body change. Writes through the same service as the website, so a change here shows up at /profile/config.
Request body
required
Content type: application/json
Responses
| Code | Description | |
|---|---|---|
200 |
The saved preferences | MeNotificationSettings |
401 |
Missing or invalid Bearer token | |
403 |
Token without the me:write scope (insufficient_scope) | ErrorResponse |
422 |
A field was rejected (validation_failed); errors names the offending keys | ValidationErrorResponse |
Example request
curl -X PATCH '/api/v1/me/notification-settings' \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{}'
DELETE /api/v1/me/push-subscriptions/{id} Remove a push device
Remove a push device
Removes one registered device. Another member row answers 404 rather than 403, so the endpoint does not confirm that an id exists.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id
*
|
path |
integer
|
The subscription id from the list endpoint |
Responses
| Code | Description | |
|---|---|---|
204 |
Removed | |
401 |
Missing or invalid Bearer token | |
403 |
Token without the me:write scope (insufficient_scope) | ErrorResponse |
404 |
No such device for this member | |
503 |
No VAPID key is configured on this platform (push_unavailable) | ErrorResponse |
Example request
curl -X DELETE '/api/v1/me/push-subscriptions/1' \
-H "Authorization: Bearer $ACCESS_TOKEN"
memberships
The calling member's group memberships: invitations, joining and leaving
GET /api/v1/memberships/invitations List the open group invitations
List the open group invitations
Invitations addressed to the calling member, minus those hidden by a block in either direction.
Responses
| Code | Description | |
|---|---|---|
200 |
The open invitations | InvitationList |
401 |
Missing or invalid Bearer token | |
403 |
Token without the memberships:read scope (insufficient_scope) | ErrorResponse |
Example request
curl '/api/v1/memberships/invitations' \
-H "Authorization: Bearer $ACCESS_TOKEN"
POST /api/v1/memberships/groups/{slug} Join a listed group, or ask to
Join a listed group, or ask to
Only a group listed on the groups portal can be joined here. A Hidden group is joined on its own domain and a Private group by invitation, so both answer group_not_joinable. When the group requires approval the membership comes back pending.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
slug
*
|
path |
string
|
Request body
Content type: application/json
| Name | Type | Description |
|---|---|---|
platformMailConsent |
boolean
|
Answers the platform crossing: whether the platform may send announcements and event mail |
Responses
| Code | Description | |
|---|---|---|
200 |
The resulting membership, approved or pending | Membership |
401 |
Missing or invalid Bearer token | |
404 |
No such group (not_found) | ErrorResponse |
409 |
group_not_joinable, blocked_in_group or platform_crossing_required | ErrorResponse |
Example request
curl -X POST '/api/v1/memberships/groups/slug' \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"platformMailConsent":"value"}'
DELETE /api/v1/memberships/groups/{slug} Leave a group
Leave a group
The same rules the website applies: the last owner cannot leave, a blocked member cannot, and the platform group can only be left once it is no longer needed for another membership.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
slug
*
|
path |
string
|
Responses
| Code | Description | |
|---|---|---|
204 |
Membership ended | |
401 |
Missing or invalid Bearer token | |
404 |
No such group, or no membership in it (not_found) | ErrorResponse |
409 |
last_owner, blocked_in_group or may_not_leave_platform | ErrorResponse |
Example request
curl -X DELETE '/api/v1/memberships/groups/slug' \
-H "Authorization: Bearer $ACCESS_TOKEN"
POST /api/v1/memberships/invitations/{id}/accept Accept a group invitation
Accept a group invitation
Accepting settles the membership at the invited role. While the member still has to join the platform group, this answers 409 platform_crossing_required; retry with platformMailConsent to answer that question first.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id
*
|
path |
integer
|
Request body
Content type: application/json
| Name | Type | Description |
|---|---|---|
platformMailConsent |
boolean
|
Answers the platform crossing: whether the platform may send announcements and event mail |
Responses
| Code | Description | |
|---|---|---|
200 |
The resulting membership | Membership |
401 |
Missing or invalid Bearer token | |
404 |
No such invitation for this member (invitation_not_found) | ErrorResponse |
409 |
blocked_in_group, membership_rejected or platform_crossing_required | ErrorResponse |
Example request
curl -X POST '/api/v1/memberships/invitations/1/accept' \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"platformMailConsent":"value"}'
POST /api/v1/memberships/invitations/{id}/decline Decline a group invitation
Decline a group invitation
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id
*
|
path |
integer
|
Responses
| Code | Description | |
|---|---|---|
204 |
Invitation declined | |
401 |
Missing or invalid Bearer token | |
404 |
No such invitation for this member (invitation_not_found) | ErrorResponse |
Example request
curl -X POST '/api/v1/memberships/invitations/1/decline' \
-H "Authorization: Bearer $ACCESS_TOKEN"
signal
Whether anything changed for the member, without saying what
GET /api/v1/signal Whether anything changed for the member
Whether anything changed for the member
An opaque value that changes when the bell changes, when an event the member said yes to is cancelled, moved in time or to another place, and when its reminder falls due. It reveals nothing else, so a token that can only read this section is safe to keep where the app cannot protect it.
Responses
| Code | Description | |
|---|---|---|
200 |
The current value | SignalState |
401 |
Missing or invalid Bearer token | |
403 |
Token without the signal:read scope (insufficient_scope) | ErrorResponse |
Example request
curl '/api/v1/signal' \
-H "Authorization: Bearer $ACCESS_TOKEN"
status
status
GET /api/status Health check endpoint
Health check endpoint
Responses
| Code | Description | |
|---|---|---|
200 |
Service is healthy | HealthStatus |
Example request
curl '/api/status'