Skip to main content

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:

FieldTypeRequiredDescription
namestringYesGroup name
descriptionstringNoGroup description
deletion_policystringNodisband (default) or transfer. Controls what happens when the last admin leaves.

Deletion Policies:

  • disband — Group is deactivated, all memberships revoked, all data shares revoked
  • transfer — 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"
}'
FieldTypeDescription
rolestringadmin or member
exposure_profile_idUUIDGroup 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!"
}'
FieldTypeRequiredDescription
user_idUUIDYesUser to invite
rolestringNomember (default) or admin
messagestringNoOptional 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" }'
FieldTypeRequiredDescription
actionstringYesaccept 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!"
}'
FieldTypeRequiredDescription
target_group_idUUIDYesGroup to connect with
messagestringNoOptional 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:

ParameterTypeDefaultDescription
node_typestring-Filter by node type
meaning_levelstring-Filter by meaning level
graph_viewstring-identity or neutral
searchstring-Search title/value
include_tagsbooleanfalseInclude associated tags
limitinteger20Items to return
offsetinteger0Pagination 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" }'
FieldTypeRequiredDescription
exposure_profile_idUUIDYesPersonal 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:

RoleGroup CRUDMembersInvitationsNodesTagsProfiles
AdminFull accessManage allSend/cancelFull CRUDFull CRUDFull CRUD
MemberRead onlyView listAccept/decline ownGoverned by assigned profileGoverned by assigned profileView 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_permissions control 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)