Event management endpoints
20 endpoints.
| Method | Path | Summary |
|---|---|---|
GET | /api/events | List events |
POST | /api/events | Create an event |
DELETE | /api/events/{id} | Delete an event |
GET | /api/events/{id} | One event |
PUT | /api/events/{id} | Edit an event |
DELETE | /api/events/{id}/attend | Withdraw your RSVP |
POST | /api/events/{id}/attend | RSVP for yourself |
PATCH | /api/events/{id}/attendance | Set a member's RSVP (moderators) |
GET | /api/events/{id}/attendance/stats | Attendance counts (moderators) |
GET | /api/events/{id}/attendees | Attendees of an event |
GET | /api/events/{id}/attendees/export.csv | Download the attendee list (organisers — calendar:manage / calendar:moderate) |
GET | /api/events/{id}/confirmed | Members who confirmed they are going |
POST | /api/events/{id}/interest | Toggle your interest bookmark |
GET | /api/events/{id}/interested | Members who marked the event as interesting |
DELETE | /api/events/{id}/waitlist | Leave the waitlist |
GET | /api/events/{id}/waitlist | The waitlist in order (organisers — calendar:manage / calendar:moderate) |
POST | /api/events/{id}/waitlist | Join the waitlist of a FULL event (first come, first served) |
GET | /api/events/{id}/waitlist/me | My place in the waitlist (null when not waiting) |
GET | /api/events/user/{userId} | Events a member responded to (moderators) |
GET | /api/events/user/{userId}/attendance | A member's attendance history (moderators) |
GET /api/eventsoptionalAuth. What comes back depends on who is asking in THIS community:
- A moderator sees every event.
- An APPROVED member sees every event except other people's drafts.
- A guest, or a signed-in non-member, gets only PUBLISHED events opted into guest preview, and only in a PUBLIC community whose plan includes it.
- Anyone else gets an empty page. Guests receive a reduced event: no meeting link or passcode, no attendee list, no attachments. Attendee emails go to moderators only. All event routes sit behind the router-level feature gate requireFeature(events): a plan without it gets 403 FEATURE_NOT_AVAILABLE on every route, reads included.
Auth: optional — a token changes what you can see (see "Who may read what").
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
communityId | query | no | string (uuid) | Defaults to the community the request resolved to (custom domain / X-Tenant-Id). |
status | query | no | string | Comma-separated DRAFT,PUBLISHED,CANCELLED,COMPLETED (still filtered by visibility). |
includePast | query | no | boolean | Past events are excluded unless true. |
onlyAvailable | query | no | boolean | Only events with free seats. |
isOnline | query | no | boolean | — |
search | query | no | string | — |
tags | query | no | string | Comma-separated. |
categoryId | query | no | string (uuid) | — |
fromDate | query | no | string (date-time) | Events still running at or after this instant (an event overlapping the period is included, not only one that starts inside it). |
toDate | query | no | string (date-time) | — |
page | query | no | integer | — |
pageSize | query | no | integer | — |
Responses
| Status | Description | Body |
|---|---|---|
200 | success, data: [event], page, pageSize, total, hasNext. Each event carries attendeeStats going, maybe (= interested), notGoing, capacity, availableSpots and creator (the community name, or isFormerMember). | — |
403 | FEATURE_NOT_AVAILABLE — the plan lacks events. | — |
POST /api/eventsNeeds an APPROVED member holding calendar:manage or calendar:create, who is not suspended or blocked from events. The community is the one the guards checked (?communityId= or X-Tenant-Id). A body communityId that disagrees is refused with 400 COMMUNITY_MISMATCH. Uploads count against the plan's storage and are refused over the cap. Rate limit: 10 per burst, 1 per 5 seconds. All event routes sit behind the router-level feature gate requireFeature(events): a plan without it gets 403 FEATURE_NOT_AVAILABLE on every route, reads included.
Auth: Bearer JWT required.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
communityId | query | yes | string (uuid) | The community the event belongs to (also accepted as X-Tenant-Id). |
Request body (required) — multipart/form-data
| Field | Type | Required | Description |
|---|---|---|---|
communityId | string (uuid) | no | Optional; must equal the checked community when sent. |
title | string | yes | — |
titleArabic | string | yes | — |
description | string | no | Rich text; sanitized server-side. |
startDate | string (date-time) | yes | — |
endDate | string (date-time) | yes | Must not be before startDate. |
status | enum: DRAFT, PUBLISHED, CANCELLED, COMPLETED | no | Only PUBLISHED notifies members and fires the event.created webhook. A DRAFT is visible to its creator and to moderators only. |
location | string | no | — |
isOnline | boolean | no | — |
meetingUrl | string | no | Absolute http:// or https:// only (400 INVALID_URL otherwise). Never sent to guests or in home-feed cards. |
meetingPasscode | string | no | Never sent to guests. |
meetingLinkVisibility | enum: BEFORE_BOOKING, AFTER_BOOKING | no | When members see meetingUrl + meetingPasscode. AFTER_BOOKING = only after «going» (free) or a PAID ticket (paid); moderators and the creator always. Optional — absent or empty leaves it unchanged (NULL on create = paid → after, free → before). Any other value → 400 EVENT_LINK_VISIBILITY_INVALID. |
registrationUrl | string | no | Absolute http:// or https:// only (400 INVALID_URL otherwise). |
timezone | string | no | — |
capacity | integer | no | GOING seats. Empty or 0 means unlimited. |
fee | number | no | — |
currency | string | no | — |
hasCertificate | boolean | no | — |
allowGuests | boolean | no | — |
allowComments | boolean | no | — |
isGuestVisible | boolean | no | Show to guests of a PUBLIC community. Requires the community and its events section to be opted into guest preview; 400 otherwise. |
tags | string | no | JSON array or comma-separated list. |
categoryIds | string | no | JSON array of existing event-category ids (see /api/event-categories). At most 3 together with newCategories. A malformed array is a 400. |
newCategories | string | no | JSON array of name, description to find-or-create before linking. At most 3 together with categoryIds. |
eventCover | string (binary) | no | — |
eventDocuments | string (binary)[] | no | — |
Responses
| Status | Description | Body |
|---|---|---|
201 | success, data: event | — |
400 | A validation error: a missing title or date, endDate before startDate, INVALID_URL, more than 3 categories, a malformed JSON field, or COMMUNITY_MISMATCH. | — |
401 | No or invalid token. | — |
403 | Read the body's error to tell which guard refused (CLAUDE.md §14). NOT_A_COMMUNITY_MEMBER or a membership message means you are not an APPROVED member of this community. FEATURE_NOT_AVAILABLE means the plan lacks events. error:'Forbidden', message:'Missing permission: …' means a permission is missing. RESTRICTION_BLOCKED means the member is suspended or blocked from events. | — |
429 | Rate limited. | — |
DELETE /api/events/{id}Same access rules as PUT. Nobody is notified. To tell attendees, set status=CANCELLED with PUT instead.
Auth: Bearer JWT required.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
id | path | yes | string (uuid) | — |
communityId | query | yes | string (uuid) | The community the event belongs to (also accepted as X-Tenant-Id). |
Responses
| Status | Description | Body |
|---|---|---|
200 | success: true | — |
401 | No or invalid token. | — |
403 | Read the body's error to tell which guard refused (CLAUDE.md §14). NOT_A_COMMUNITY_MEMBER or a membership message means you are not an APPROVED member of this community. FEATURE_NOT_AVAILABLE means the plan lacks events. error:'Forbidden', message:'Missing permission: …' means a permission is missing. RESTRICTION_BLOCKED means the member is suspended or blocked from events. | — |
404 | No such event. | — |
GET /api/events/{id}optionalAuth, with the same visibility as the list: another member's draft, or any event a guest may not preview, answers 404 exactly as a missing id does. Guests get the reduced event. Attendee emails go to moderators only. The creator's email is visible to members (intended). All event routes sit behind the router-level feature gate requireFeature(events): a plan without it gets 403 FEATURE_NOT_AVAILABLE on every route, reads included.
Auth: optional — a token changes what you can see (see "Who may read what").
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
id | path | yes | string (uuid) | — |
communityId | query | no | string (uuid) | — |
Responses
| Status | Description | Body |
|---|---|---|
200 | success, data: event | — |
404 | No such event, or not visible to this caller. | — |
PUT /api/events/{id}The event's creator, or a holder of calendar:manage or calendar:moderate. Either way the caller must be an APPROVED member who is not suspended or blocked from events. calendar:create alone does not let you edit other people's events. Only the fields you send change.
- A link is checked only when you change it, so an old link stays savable.
- existingAttachments selects which current attachments to keep, by id or url; the server's copy is kept, never yours.
- removeAttachments (or removeAttachmentIds) removes attachments by id.
- removeCover=true clears the cover. Bytes are recorded, but an edit is never refused over the storage cap. Setting status=CANCELLED, or moving the start date, notifies the attendees who are still members.
Auth: Bearer JWT required.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
id | path | yes | string (uuid) | — |
communityId | query | yes | string (uuid) | The community the event belongs to (also accepted as X-Tenant-Id). |
Request body — multipart/form-data
| Field | Type | Required | Description |
|---|---|---|---|
title | string | no | — |
titleArabic | string | no | — |
description | string | no | Rich text; sanitized server-side. |
startDate | string (date-time) | no | — |
endDate | string (date-time) | no | Must not be before startDate. |
status | enum: DRAFT, PUBLISHED, CANCELLED, COMPLETED | no | Only PUBLISHED notifies members and fires the event.created webhook. A DRAFT is visible to its creator and to moderators only. |
location | string | no | — |
isOnline | boolean | no | — |
meetingUrl | string | no | Absolute http:// or https:// only (400 INVALID_URL otherwise). Never sent to guests or in home-feed cards. |
meetingPasscode | string | no | Never sent to guests. |
meetingLinkVisibility | enum: BEFORE_BOOKING, AFTER_BOOKING | no | When members see meetingUrl + meetingPasscode. AFTER_BOOKING = only after «going» (free) or a PAID ticket (paid); moderators and the creator always. Optional — absent or empty leaves it unchanged (NULL on create = paid → after, free → before). Any other value → 400 EVENT_LINK_VISIBILITY_INVALID. |
registrationUrl | string | no | Absolute http:// or https:// only (400 INVALID_URL otherwise). |
timezone | string | no | — |
capacity | integer | no | GOING seats. Empty or 0 means unlimited. |
fee | number | no | — |
currency | string | no | — |
hasCertificate | boolean | no | — |
allowGuests | boolean | no | — |
allowComments | boolean | no | — |
isGuestVisible | boolean | no | Show to guests of a PUBLIC community. Requires the community and its events section to be opted into guest preview; 400 otherwise. |
tags | string | no | JSON array or comma-separated list. |
categoryIds | string | no | JSON array of existing event-category ids (see /api/event-categories). At most 3 together with newCategories. A malformed array is a 400. |
newCategories | string | no | JSON array of name, description to find-or-create before linking. At most 3 together with categoryIds. |
eventCover | string (binary) | no | — |
eventDocuments | string (binary)[] | no | — |
existingAttachments | string | no | JSON array of id or url. Malformed → 400. |
removeAttachments | string | no | JSON array or comma-separated attachment ids. |
removeAttachmentIds | string | no | Same as removeAttachments (the Flutter app's name for it). |
removeCover | enum: true | no | — |
Responses
| Status | Description | Body |
|---|---|---|
200 | success, data: event | — |
400 | Validation error (dates, INVALID_URL, categories, malformed JSON). | — |
401 | No or invalid token. | — |
403 | Read the body's error to tell which guard refused (CLAUDE.md §14). NOT_A_COMMUNITY_MEMBER or a membership message means you are not an APPROVED member of this community. FEATURE_NOT_AVAILABLE means the plan lacks events. error:'Forbidden', message:'Missing permission: …' means a permission is missing. RESTRICTION_BLOCKED means the member is suspended or blocked from events. | — |
404 | No such event. | — |
429 | Rate limited. | — |
DELETE /api/events/{id}/attendSame access rules as POST. Keeps your interest bookmark. Auth: Bearer JWT required.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
id | path | yes | string (uuid) | — |
communityId | query | yes | string (uuid) | The community the event belongs to (also accepted as X-Tenant-Id). |
Responses
| Status | Description | Body |
|---|---|---|
200 | success, data: event | — |
401 | No or invalid token. | — |
403 | Read the body's error to tell which guard refused (CLAUDE.md §14). NOT_A_COMMUNITY_MEMBER or a membership message means you are not an APPROVED member of this community. FEATURE_NOT_AVAILABLE means the plan lacks events. error:'Forbidden', message:'Missing permission: …' means a permission is missing. RESTRICTION_BLOCKED means the member is suspended or blocked from events. | — |
404 | No such event, the caller cannot open it, or there is no RSVP to withdraw. | — |
POST /api/events/{id}/attendAny APPROVED member who is not suspended or blocked from RSVPs, on an event they can open (another member's draft answers 404 and nothing is written). GOING is refused with 400 "Event capacity reached" when the seats are taken. Re-confirming a seat you already hold always succeeds. The event comes back at the caller's own visibility.
Auth: Bearer JWT required.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
id | path | yes | string (uuid) | — |
communityId | query | yes | string (uuid) | The community the event belongs to (also accepted as X-Tenant-Id). |
Request body — application/json
| Field | Type | Required | Description |
|---|---|---|---|
status | enum: GOING, MAYBE, NOT_GOING | no | — |
Responses
| Status | Description | Body |
|---|---|---|
201 | success, data: event | — |
400 | Event capacity reached. | — |
401 | No or invalid token. | — |
403 | Read the body's error to tell which guard refused (CLAUDE.md §14). NOT_A_COMMUNITY_MEMBER or a membership message means you are not an APPROVED member of this community. FEATURE_NOT_AVAILABLE means the plan lacks events. error:'Forbidden', message:'Missing permission: …' means a permission is missing. RESTRICTION_BLOCKED means the member is suspended or blocked from events. | — |
404 | No such event, or the caller cannot open it. | — |
PATCH /api/events/{id}/attendanceNeeds an APPROVED member holding calendar:manage or calendar:moderate. A moderator decision, so it is not held to capacity. The member must already have a response row.
Auth: Bearer JWT required.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
id | path | yes | string (uuid) | — |
communityId | query | yes | string (uuid) | The community the event belongs to (also accepted as X-Tenant-Id). |
Request body (required) — application/json
| Field | Type | Required | Description |
|---|---|---|---|
userId | string (uuid) | yes | A User.id. |
status | enum: GOING, MAYBE, NOT_GOING | yes | — |
Responses
| Status | Description | Body |
|---|---|---|
200 | success, data: event | — |
400 | userId or status missing or invalid. | — |
401 | No or invalid token. | — |
403 | Read the body's error to tell which guard refused (CLAUDE.md §14). NOT_A_COMMUNITY_MEMBER or a membership message means you are not an APPROVED member of this community. FEATURE_NOT_AVAILABLE means the plan lacks events. error:'Forbidden', message:'Missing permission: …' means a permission is missing. RESTRICTION_BLOCKED means the member is suspended or blocked from events. | — |
404 | That member has no response row for this event. | — |
GET /api/events/{id}/attendance/statsNeeds an APPROVED member holding calendar:manage or calendar:moderate. maybe is the interested count. notGoing excludes interest-only bookmarks.
Auth: Bearer JWT required.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
id | path | yes | string (uuid) | — |
communityId | query | yes | string (uuid) | The community the event belongs to (also accepted as X-Tenant-Id). |
Responses
| Status | Description | Body |
|---|---|---|
200 | success, data: { total, going, maybe, notGoing, capacity, availableSpots } | — |
401 | No or invalid token. | — |
403 | Read the body's error to tell which guard refused (CLAUDE.md §14). NOT_A_COMMUNITY_MEMBER or a membership message means you are not an APPROVED member of this community. FEATURE_NOT_AVAILABLE means the plan lacks events. error:'Forbidden', message:'Missing permission: …' means a permission is missing. RESTRICTION_BLOCKED means the member is suspended or blocked from events. | — |
404 | No such event. | — |
GET /api/events/{id}/attendeesEveryone with a response row, optionally filtered by ?status=GOING,MAYBE,NOT_GOING. Any APPROVED member may call it, but the caller must be able to open the event, so another member's draft answers 404. Lists current APPROVED members only. The email field is filled for moderator-tier callers only and is null for everyone else.
Auth: Bearer JWT required.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
id | path | yes | string (uuid) | — |
communityId | query | yes | string (uuid) | The community the event belongs to (also accepted as X-Tenant-Id). |
status | query | no | string | Comma-separated GOING,MAYBE,NOT_GOING. |
Responses
| Status | Description | Body |
|---|---|---|
200 | success, data: [attendee], count | — |
401 | No or invalid token. | — |
403 | Read the body's error to tell which guard refused (CLAUDE.md §14). NOT_A_COMMUNITY_MEMBER or a membership message means you are not an APPROVED member of this community. FEATURE_NOT_AVAILABLE means the plan lacks events. error:'Forbidden', message:'Missing permission: …' means a permission is missing. RESTRICTION_BLOCKED means the member is suspended or blocked from events. | — |
404 | No such event, or the caller cannot open it. | — |
GET /api/events/{id}/attendees/export.csvCSV (UTF-8 with BOM): name, status (going / maybe / not going / interested / waitlisted), waitlist position, registration time (UTC), and email for the moderator tier (the in-app roster's rule). Current members only. Every export is recorded.
Auth: Bearer JWT required.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
id | path | yes | string | — |
Responses
| Status | Description | Body |
|---|---|---|
200 | text/csv | — |
GET /api/events/{id}/confirmedThe GOING list. Any APPROVED member may call it, but the caller must be able to open the event, so another member's draft answers 404. Lists current APPROVED members only. The email field is filled for moderator-tier callers only and is null for everyone else.
Auth: Bearer JWT required.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
id | path | yes | string (uuid) | — |
communityId | query | yes | string (uuid) | The community the event belongs to (also accepted as X-Tenant-Id). |
Responses
| Status | Description | Body |
|---|---|---|
200 | success, data: [attendee], count | — |
401 | No or invalid token. | — |
403 | Read the body's error to tell which guard refused (CLAUDE.md §14). NOT_A_COMMUNITY_MEMBER or a membership message means you are not an APPROVED member of this community. FEATURE_NOT_AVAILABLE means the plan lacks events. error:'Forbidden', message:'Missing permission: …' means a permission is missing. RESTRICTION_BLOCKED means the member is suspended or blocked from events. | — |
404 | No such event, or the caller cannot open it. | — |
POST /api/events/{id}/interestIndependent of the RSVP, and the same access rules as POST /attend. The creator is notified when interest is added, as long as the creator is still a member.
Auth: Bearer JWT required.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
id | path | yes | string (uuid) | — |
communityId | query | yes | string (uuid) | The community the event belongs to (also accepted as X-Tenant-Id). |
Responses
| Status | Description | Body |
|---|---|---|
200 | success, data: event, isInterested | — |
401 | No or invalid token. | — |
403 | Read the body's error to tell which guard refused (CLAUDE.md §14). NOT_A_COMMUNITY_MEMBER or a membership message means you are not an APPROVED member of this community. FEATURE_NOT_AVAILABLE means the plan lacks events. error:'Forbidden', message:'Missing permission: …' means a permission is missing. RESTRICTION_BLOCKED means the member is suspended or blocked from events. | — |
404 | No such event, or the caller cannot open it. | — |
GET /api/events/{id}/interestedThe heart / bookmark list. Any APPROVED member may call it, but the caller must be able to open the event, so another member's draft answers 404. Lists current APPROVED members only. The email field is filled for moderator-tier callers only and is null for everyone else.
Auth: Bearer JWT required.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
id | path | yes | string (uuid) | — |
communityId | query | yes | string (uuid) | The community the event belongs to (also accepted as X-Tenant-Id). |
Responses
| Status | Description | Body |
|---|---|---|
200 | success, data: [attendee], count | — |
401 | No or invalid token. | — |
403 | Read the body's error to tell which guard refused (CLAUDE.md §14). NOT_A_COMMUNITY_MEMBER or a membership message means you are not an APPROVED member of this community. FEATURE_NOT_AVAILABLE means the plan lacks events. error:'Forbidden', message:'Missing permission: …' means a permission is missing. RESTRICTION_BLOCKED means the member is suspended or blocked from events. | — |
404 | No such event, or the caller cannot open it. | — |
DELETE /api/events/{id}/waitlistAuth: Bearer JWT required.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
id | path | yes | string | — |
Responses
| Status | Description | Body |
|---|---|---|
200 | success | — |
GET /api/events/{id}/waitlistAuth: Bearer JWT required.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
id | path | yes | string | — |
Responses
| Status | Description | Body |
|---|---|---|
200 | success, data: [{ userId, position, joinedAt, name, avatar }] — current, unblocked members only, numbered in seat order; name + photo as this community knows them, never contact fields | — |
POST /api/events/{id}/waitlistOnly when the event is published, not over, free, has a seat limit and every seat is taken. When a seat frees up the first person in line is moved to GOING automatically and notified. 409 codes: EVENT_HAS_SEATS, ALREADY_GOING, EVENT_NOT_OPEN, NO_CAPACITY, EVENT_NOT_FREE.
Auth: Bearer JWT required.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
id | path | yes | string | — |
Responses
| Status | Description | Body |
|---|---|---|
201 | success, data: { position } | — |
409 | Not possible now — see the code | — |
GET /api/events/{id}/waitlist/meAuth: Bearer JWT required.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
id | path | yes | string | — |
Responses
| Status | Description | Body |
|---|---|---|
200 | success, data: { position, length } | — |
GET /api/events/user/{userId}Needs an APPROVED member holding calendar:manage or calendar:moderate. Auth: Bearer JWT required.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
userId | path | yes | string (uuid) | A User.id. |
communityId | query | yes | string (uuid) | The community the event belongs to (also accepted as X-Tenant-Id). |
status | query | no | string | Comma-separated GOING,MAYBE,NOT_GOING. |
fromDate | query | no | string (date-time) | — |
toDate | query | no | string (date-time) | — |
page | query | no | integer | — |
pageSize | query | no | integer | — |
Responses
| Status | Description | Body |
|---|---|---|
200 | success, data: [event], page, pageSize, total | — |
401 | No or invalid token. | — |
403 | Read the body's error to tell which guard refused (CLAUDE.md §14). NOT_A_COMMUNITY_MEMBER or a membership message means you are not an APPROVED member of this community. FEATURE_NOT_AVAILABLE means the plan lacks events. error:'Forbidden', message:'Missing permission: …' means a permission is missing. RESTRICTION_BLOCKED means the member is suspended or blocked from events. | — |
GET /api/events/user/{userId}/attendanceNeeds an APPROVED member holding calendar:manage or calendar:moderate. Auth: Bearer JWT required.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
userId | path | yes | string (uuid) | A User.id (not a CommunityMember.id). |
communityId | query | yes | string (uuid) | The community the event belongs to (also accepted as X-Tenant-Id). |
status | query | no | string | Comma-separated GOING,MAYBE,NOT_GOING. |
Responses
| Status | Description | Body |
|---|---|---|
200 | success, data: [attendance] | — |
401 | No or invalid token. | — |
403 | Read the body's error to tell which guard refused (CLAUDE.md §14). NOT_A_COMMUNITY_MEMBER or a membership message means you are not an APPROVED member of this community. FEATURE_NOT_AVAILABLE means the plan lacks events. error:'Forbidden', message:'Missing permission: …' means a permission is missing. RESTRICTION_BLOCKED means the member is suspended or blocked from events. | — |