Groups API
Groups are shared identity graphs where multiple users collaborate. Members interact via roles (admin/member) with permissions governed by exposure profiles.
Base URL
https://api.ofself.ai/api/v1
Authentication
All group endpoints require JWT authentication (Authorization: Bearer <token>). Groups are a first-party feature — third-party apps cannot directly manage groups.
Group CRUD
POST /groups
POST Create a new group. The creator is automatically made an admin.
curl -X POST "https://api.ofself.ai/api/v1/groups" \
-H "Authorization: Bearer your-jwt-token" \
-H "Content-Type: application/json" \
-d '{
"name": "Research Team",
"description": "Shared identity graph for our research group",
"deletion_policy": "transfer"
}'
Request Body:
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Group name |
description | string | No | Group description |
deletion_policy | string | No | disband (default) or transfer. Controls what happens when the last admin leaves. |
Deletion Policies:
disband— Group is deactivated, all memberships revoked, all data shares revokedtransfer— Admin role transfers to the longest-tenured member
Response: 201 Created
{
"id": "group-uuid",
"name": "Research Team",
"description": "Shared identity graph for our research group",
"deletion_policy": "transfer",
"created_by": "user-uuid",
"created_at": "2026-01-15T10:30:00Z",
"is_active": true
}
GET /groups
GET List groups the current user is a member of.
curl -X GET "https://api.ofself.ai/api/v1/groups" \
-H "Authorization: Bearer your-jwt-token"
Response: 200 OK
{
"groups": [
{
"id": "group-uuid",
"name": "Research Team",
"description": "Shared identity graph",
"member_count": 5,
"my_role": "admin",
"created_at": "2026-01-15T10:30:00Z"
}
]
}
GET /groups/:group_id
GET Get group details. Requires membership.
curl -X GET "https://api.ofself.ai/api/v1/groups/group-uuid" \
-H "Authorization: Bearer your-jwt-token"
PUT /groups/:group_id
PUT Update group details. Admin only.
curl -X PUT "https://api.ofself.ai/api/v1/groups/group-uuid" \
-H "Authorization: Bearer your-jwt-token" \
-H "Content-Type: application/json" \
-d '{ "name": "Updated Name", "description": "New description" }'
DELETE /groups/:group_id
DELETE Delete group. Admin only. Deactivates all memberships and revokes data shares.
curl -X DELETE "https://api.ofself.ai/api/v1/groups/group-uuid" \
-H "Authorization: Bearer your-jwt-token"
Response: 200 OK
Membership
GET /groups/:group_id/members
GET List group members with roles.
curl -X GET "https://api.ofself.ai/api/v1/groups/group-uuid/members" \
-H "Authorization: Bearer your-jwt-token"
Response: 200 OK
{
"members": [
{
"user_id": "user-uuid",
"username": "alice",
"role": "admin",
"exposure_profile_id": null,
"joined_at": "2026-01-15T10:30:00Z"
},
{
"user_id": "user-uuid-2",
"username": "bob",
"role": "member",
"exposure_profile_id": "profile-uuid",
"joined_at": "2026-01-16T09:00:00Z"
}
]
}
PUT /groups/:group_id/members/:user_id
PUT Update a member's role or assigned exposure profile. Admin only.
curl -X PUT "https://api.ofself.ai/api/v1/groups/group-uuid/members/user-uuid-2" \
-H "Authorization: Bearer your-jwt-token" \
-H "Content-Type: application/json" \
-d '{
"role": "member",
"exposure_profile_id": "profile-uuid"
}'
| Field | Type | Description |
|---|---|---|
role | string | admin or member |
exposure_profile_id | UUID | Group exposure profile controlling what this member can see/do |
DELETE /groups/:group_id/members/:user_id
DELETE Remove a member (admin action) or leave the group (self).
If the last admin leaves, the group's deletion_policy determines behavior.
curl -X DELETE "https://api.ofself.ai/api/v1/groups/group-uuid/members/user-uuid-2" \
-H "Authorization: Bearer your-jwt-token"
POST /groups/:group_id/members/:user_id/promote
POST Promote a member to admin. Admin only.
curl -X POST "https://api.ofself.ai/api/v1/groups/group-uuid/members/user-uuid-2/promote" \
-H "Authorization: Bearer your-jwt-token"
Invitations
POST /groups/:group_id/invitations
POST Invite a user to the group. Admin only.
curl -X POST "https://api.ofself.ai/api/v1/groups/group-uuid/invitations" \
-H "Authorization: Bearer your-jwt-token" \
-H "Content-Type: application/json" \
-d '{
"user_id": "user-uuid-3",
"role": "member",
"message": "Join our research group!"
}'
| Field | Type | Required | Description |
|---|---|---|---|
user_id | UUID | Yes | User to invite |
role | string | No | member (default) or admin |
message | string | No | Optional invitation message |
Response: 201 Created
{
"id": "invitation-uuid",
"group_id": "group-uuid",
"invited_user_id": "user-uuid-3",
"invited_by": "user-uuid",
"role": "member",
"status": "pending",
"created_at": "2026-01-15T10:30:00Z"
}
GET /groups/invitations/incoming
GET List pending invitations for the current user.
curl -X GET "https://api.ofself.ai/api/v1/groups/invitations/incoming" \
-H "Authorization: Bearer your-jwt-token"
GET /groups/:group_id/invitations
GET List pending invitations for a group. Admin only.
PUT /groups/invitations/:invitation_id
PUT Accept or decline an invitation.
curl -X PUT "https://api.ofself.ai/api/v1/groups/invitations/invitation-uuid" \
-H "Authorization: Bearer your-jwt-token" \
-H "Content-Type: application/json" \
-d '{ "action": "accept" }'
| Field | Type | Required | Description |
|---|---|---|---|
action | string | Yes | accept or decline |
DELETE /groups/:group_id/invitations/:invitation_id
DELETE Cancel a pending invitation. Admin only.
Group-to-Group Connections
Groups can establish connections with other groups for cross-group collaboration.
POST /groups/:group_id/connections
POST Request a connection to another group. Admin only.
curl -X POST "https://api.ofself.ai/api/v1/groups/group-uuid/connections" \
-H "Authorization: Bearer your-jwt-token" \
-H "Content-Type: application/json" \
-d '{
"target_group_id": "other-group-uuid",
"message": "Let us collaborate!"
}'
| Field | Type | Required | Description |
|---|---|---|---|
target_group_id | UUID | Yes | Group to connect with |
message | string | No | Optional message |
GET /groups/:group_id/connections
GET List outgoing connections for a group.
GET /groups/:group_id/connections/incoming
GET List pending incoming connection requests. Admin only.
PUT /groups/:group_id/connections/:connection_id
PUT Accept or decline a connection request. Admin only.
curl -X PUT "https://api.ofself.ai/api/v1/groups/group-uuid/connections/conn-uuid" \
-H "Authorization: Bearer your-jwt-token" \
-H "Content-Type: application/json" \
-d '{ "action": "accept" }'
DELETE /groups/:group_id/connections/:connection_id
DELETE Revoke a connection. Admin only.
Group Nodes
Groups have their own nodes, separate from personal nodes.
POST /groups/:group_id/nodes
POST Create a node within the group. Admins always have access. Members need create permission via their assigned exposure profile.
curl -X POST "https://api.ofself.ai/api/v1/groups/group-uuid/nodes" \
-H "Authorization: Bearer your-jwt-token" \
-H "Content-Type: application/json" \
-d '{
"title": "Team research findings",
"node_type": "EXPERIENCE",
"meaning_level": "CONTEXT",
"graph_view": "identity",
"value": "Our key findings from Q4 research..."
}'
Request body follows the same schema as POST /nodes.
Response: 201 Created
GET /groups/:group_id/nodes
GET List group nodes. Non-admin members see nodes filtered by their assigned exposure profile.
curl -X GET "https://api.ofself.ai/api/v1/groups/group-uuid/nodes?include_tags=true&limit=50" \
-H "Authorization: Bearer your-jwt-token"
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
node_type | string | - | Filter by node type |
meaning_level | string | - | Filter by meaning level |
graph_view | string | - | identity or neutral |
search | string | - | Search title/value |
include_tags | boolean | false | Include associated tags |
limit | integer | 20 | Items to return |
offset | integer | 0 | Pagination offset |
PUT /groups/:group_id/nodes/:node_id
PUT Update a group node. Requires edit permission.
DELETE /groups/:group_id/nodes/:node_id
DELETE Soft-delete a group node. Requires delete permission.
Group Tags
POST /groups/:group_id/tags
POST Create a tag within the group. Requires create permission.
curl -X POST "https://api.ofself.ai/api/v1/groups/group-uuid/tags" \
-H "Authorization: Bearer your-jwt-token" \
-H "Content-Type: application/json" \
-d '{ "name": "Research", "color": "#3B82F6" }'
GET /groups/:group_id/tags
GET List group tags.
Data Sharing
Members can share personal data with the group by linking an exposure profile.
POST /groups/:group_id/share
POST Share personal data with the group via an exposure profile.
curl -X POST "https://api.ofself.ai/api/v1/groups/group-uuid/share" \
-H "Authorization: Bearer your-jwt-token" \
-H "Content-Type: application/json" \
-d '{ "exposure_profile_id": "profile-uuid" }'
| Field | Type | Required | Description |
|---|---|---|---|
exposure_profile_id | UUID | Yes | Personal exposure profile controlling what data is shared |
Response: 201 Created
GET /groups/:group_id/share
GET Get current user's data sharing configuration for a group.
PUT /groups/:group_id/share
PUT Update data sharing configuration (change exposure profile).
DELETE /groups/:group_id/share
DELETE Revoke personal data sharing with the group.
Group Exposure Profiles
Admins create exposure profiles for the group to control what members can see and do with group data.
POST /groups/:group_id/exposure-profiles
POST Create an exposure profile for the group. Admin only.
curl -X POST "https://api.ofself.ai/api/v1/groups/group-uuid/exposure-profiles" \
-H "Authorization: Bearer your-jwt-token" \
-H "Content-Type: application/json" \
-d '{
"name": "Read-Only Members",
"tag_permissions": {
"read": { "allow_all": true },
"create": { "allow_all": false },
"edit": { "allow_all": false }
}
}'
GET /groups/:group_id/exposure-profiles
GET List group exposure profiles.
PUT /groups/:group_id/exposure-profiles/:profile_id
PUT Update a group exposure profile. Admin only.
DELETE /groups/:group_id/exposure-profiles/:profile_id
DELETE Delete a group exposure profile. Admin only.
Permission Model
Groups enforce a role-based permission model:
| Role | Group CRUD | Members | Invitations | Nodes | Tags | Profiles |
|---|---|---|---|---|---|---|
| Admin | Full access | Manage all | Send/cancel | Full CRUD | Full CRUD | Full CRUD |
| Member | Read only | View list | Accept/decline own | Governed by assigned profile | Governed by assigned profile | View list |
Member permissions via exposure profiles:
- Admins assign a group exposure profile to each member via
PUT /groups/:id/members/:uid - The profile's
tag_permissionscontrol what actions (read/create/edit/delete) the member can perform - Members without an assigned profile are read-only
Error Responses
403 Forbidden — Not a member or insufficient role
{
"error": {
"code": "NOT_A_MEMBER",
"message": "You are not a member of this group"
}
}
{
"error": {
"code": "ADMIN_REQUIRED",
"message": "Only admins can perform this action"
}
}
404 Not Found
{
"error": {
"code": "NOT_FOUND",
"message": "Group not found"
}
}
Next Steps
- Exposure Profiles — Create profiles to control group permissions
- Nodes API — Node schema (same as group nodes)
- Sharing — User-to-user sharing (complementary to groups)