API Reference
The Groupi REST API v2. All endpoints require an API key via the x-api-key header.
Versions & Migration
v2 is recommended for new integrations. It returns resources directly and uses 204 No Content after successful deletes.
v2: https://api.groupi.gg/api/v2 v1: https://api.groupi.gg/api/v1
The v1 contract remains available for existing integrations. Its successful responses use { "success": true, "data": ... } envelopes, and deletes return a JSON confirmation with status 200.
Migrating from v1
- Change the base path from /api/v1 to /api/v2.
- Read successful response fields from the top level instead of from
data. - Treat a 204 response to DELETE as success without parsing a response body.
- Handle validation failures as
VALIDATION_ERRORin the standard error object.
Authentication
Include your API key in the x-api-key header:
curl -H "x-api-key: grp_your_key_here" \ https://api.groupi.gg/api/v2/events
Create API keys in your account settings.
Events
GET/events
Get all events the authenticated user is a member of.
Response
[{
"id": "k170...",
"title": "Team Offsite",
"description": "Annual event",
"location": "Mountain View",
"chosenDateTime": 1704067200000,
"memberCount": 12,
"userRole": "ORGANIZER",
"userRsvpStatus": "YES"
}]Example
curl -H "x-api-key: grp_xxx" \ https://api.groupi.gg/api/v2/events
POST/events
Create a new event. Use potentialDateTimeOptions for explicit ISO dates, or gdl for a Groupi Date Language expression (not both). GDL is parsed server-side with no AI dependency — see the GDL reference for more information. Invalid expressions return GDL_PARSE_ERROR.
Request Body
{
"title": "Team Dinner", // required, 1-200 chars
"description": "Quarterly meetup", // optional, max 5000
"location": "Downtown", // optional, max 500
"gdl": "[Tu,Th]@18-20", // optional GDL expression
"potentialDateTimeOptions": [{ // optional (mutually exclusive with gdl)
"start": "2024-02-15T18:00:00Z",
"end": "2024-02-15T21:00:00Z"
}],
"chosenDateTime": "...", // optional, for single-date events
"chosenEndDateTime": "...", // optional
"reminderOffset": "1_DAY" // optional
}Response
{
"eventId": "k170...",
"membershipId": "k171..."
}Example
curl -X POST -H "x-api-key: grp_xxx" \
-H "Content-Type: application/json" \
-d '{"title":"Dinner","gdl":"Fr@19"}' \
https://api.groupi.gg/api/v2/eventsGET/events/{eventId}
Get full details of a specific event. Requires membership.
Response
{
"id": "k170...",
"title": "Team Offsite",
"description": "...",
"location": "...",
"timezone": "America/New_York",
"chosenDateTime": null,
"reminderOffset": "1_DAY",
"creator": {
"id": "k172...",
"user": { "name": "Alice", "username": "alice" }
}
}PATCH/events/{eventId}
Update event details. Requires MODERATOR role or higher.
Request Body
{
"title": "New Title", // optional
"description": "Updated", // optional
"location": "New Location", // optional
"reminderOffset": "2_HOURS" // optional, null to remove
}DELETE/events/{eventId}
Permanently delete an event and all associated data. Requires ORGANIZER role.
Posts
GET/events/{eventId}/posts
Get all posts for an event. Requires membership.
POST/events/{eventId}/posts
Create a new post in an event. Requires membership.
Request Body
{
"title": "Meeting Notes", // required
"content": "Discussed..." // required
}Response
{ "postId": "k173..." }GET/posts/{postId}
Get a post with its replies.
PATCH/posts/{postId}
Update a post. Requires author or MODERATOR role.
Request Body
{ "title": "...", "content": "..." }DELETE/posts/{postId}
Delete a post and its replies. Requires author or MODERATOR role.
Replies
GET/posts/{postId}/replies
List replies
POST/posts/{postId}/replies
Create reply
Request Body
{ "text": "Sounds good!" }PATCH/replies/{replyId}
Update reply
Request Body
{ "text": "Updated text" }DELETE/replies/{replyId}
Delete reply
Members
GET/events/{eventId}/members
Get all members of an event with their roles and RSVP status.
Response
[{
"id": "k174...",
"role": "ATTENDEE",
"rsvpStatus": "YES",
"personId": "k175...",
"user": { "name": "Bob", "username": "bob" }
}]PATCH/events/{eventId}/members/{memberId}
Change a member's role. Requires MODERATOR or higher.
Request Body
{ "role": "MODERATOR" } // ORGANIZER, MODERATOR, or ATTENDEEDELETE/events/{eventId}/members/{memberId}
Remove a member from the event. Requires MODERATOR or higher.
POST/events/{eventId}/leave
Remove yourself from an event. Cannot leave as the last organizer.
Availability
GET/events/{eventId}/availability
Get the full availability voting grid showing all members' votes on all potential dates.
POST/events/{eventId}/availability
Submit or update your availability votes for potential dates.
Request Body
{
"votes": [
{ "potentialDateTimeId": "k175...", "status": "YES" },
{ "potentialDateTimeId": "k176...", "status": "MAYBE" },
{ "potentialDateTimeId": "k177...", "status": "NO" }
]
}GET/events/{eventId}/potential-dates
Get the list of potential date/time options for an event.
Friends
GET/friends
List friends
GET/friends/requests/incoming
Incoming friend requests
GET/friends/requests/outgoing
Outgoing friend requests
GET/friends/search?q={query}
Search for users by name or username.
GET/friends/status/{targetPersonId}
Get friendship status
Notifications
GET/notifications
Get notifications. Add ?unread=true to filter.
GET/notifications/count
Get unread count
Response
{ "count": 5 }POST/notifications/{notificationId}/read
Mark as read
POST/notifications/read-all
Mark all as read
Profile
GET/profile
Get your profile
GET/profile/{username}
Get profile by username
PUT/profile
Update profile
Request Body
{ "bio": "Hello!", "pronouns": "they/them" }Invites
GET/events/{eventId}/invites
List event invites
POST/events/{eventId}/invites
Create invite link
Response
{ "id": "...", "token": "abc123" }DELETE/invites/{inviteId}
Delete invite
POST/invites/{token}/accept
Accept invite
Add-ons
GET/events/{eventId}/addons
List add-on configs
POST/events/{eventId}/addons/{addonType}/enable
Enable an add-on for an event. Requires MODERATOR or higher.
Request Body
{ "config": { ... } } // addon-specific configPOST/events/{eventId}/addons/{addonType}/disable
Disable add-on
PATCH/events/{eventId}/addons/{addonType}/config
Update add-on config
Request Body
{ "config": { ... } }Settings
GET/settings/privacy
Get privacy settings
PUT/settings/privacy
Update privacy settings
GET/settings/notifications
Get notification preferences
Themes
GET/themes
List custom themes
GET/themes/preferences
Get theme preferences
POST/themes
Create custom theme
PUT/themes/{themeId}
Update theme
DELETE/themes/{themeId}
Delete theme
Muting
GET/muting
List muted events and posts. Filter with ?type=events or ?type=posts.
POST/muting/events/{eventId}
Mute event
DELETE/muting/events/{eventId}
Unmute event
POST/muting/posts/{postId}
Mute post
DELETE/muting/posts/{postId}
Unmute post
Reports
POST/reports
Report a post, reply, or user for review.
Request Body
{
"targetType": "post", // "post", "reply", or "user"
"targetId": "k178...",
"reason": "Spam or abuse"
}Admin
GET/admin/users
Admin only.
DELETE/admin/users/{userId}
Admin only. Deletes user and associated data.
PUT/admin/users/{userId}/role
Admin only.
GET/admin/events
Admin only.
Response Format (v2)
Success
Data is returned directly — no envelope. HTTP status code indicates success (200, 201, 204).
// GET /events/{eventId} → 200
{ "id": "k170...", "title": "Team Offsite", ... }
// DELETE /events/{eventId} → 204 No ContentError
{
"error": {
"code": "NOT_FOUND",
"message": "Event not found"
}
}Common Error Codes
UNAUTHORIZEDMissing or invalid API keyFORBIDDENInsufficient permissionsNOT_FOUNDResource does not existVALIDATION_ERRORInvalid request bodyGDL_PARSE_ERRORInvalid GDL expression