Groups
Manage group membership and admin roles from the dashboard — and how the resulting groupId connects to POST /api/v1/messages/send for group replies.
PrivacyFlow supports group conversations across Signal, SimpleX, and Session. Group lifecycle (create, member add/remove, promote/demote admins, invite-link) happens in the dashboard’s ManageGroupModal. Group messaging (replies that land in the same thread) happens via the public API’s POST /api/v1/messages/send with a groupId field. This page is the dashboard side; see send for the API side.
Open the Manage Group modal
- Sign in to the dashboard.
- Open Apps → choose the app whose group you want to manage.
- Open Manage Group (either from the app’s row action or from inside the app’s settings).
- The modal opens with per-messenger tabs (Signal / SimpleX / Session, depending on what the app is connected to).
Warning
Screenshot placeholder — ManageGroupModal showing a messenger tab strip, a members list with role badges, and a “Copy invite link” button.
Per-messenger tabs
Each messenger has its own group model. The modal presents them as tabs so you don’t confuse a SimpleX group id with a Signal group id — they’re different identifiers and only the active tab’s group is in scope for the actions you take.
Member operations
From the members list:
| Action | Where |
|---|---|
| Add member | Adds a contactId to the group. The recipient must already be a PrivacyFlow contact (i.e., they’ve initiated a conversation with your app). |
| Remove member | Removes a contactId from the group. |
| Promote to admin | Elevates an existing member. |
| Demote admin | Removes admin privileges from a member. |
Each operation maps to a backend call:
| Operation | Backend path |
|---|---|
| List members | GET /dashboard/group/members |
| Add member | POST /dashboard/group/members/add |
| Remove member | POST /dashboard/group/members/remove |
| Promote admin | POST /dashboard/group/promote-admin |
| Demote admin | POST /dashboard/group/demote-admin |
All go through the dashboard’s BFF proxy — see automation overview. The browser session cookie becomes an X-Session-Token header on the outbound call.
Invite links
Each group has an invite link you can copy and share. Clicking Copy Invite Link in the modal copies the link to your clipboard; the recipient clicks it (or scans the SimpleX/Session QR for those messengers) and joins the group.
| Action | Backend path |
|---|---|
| Get invite link | GET /dashboard/group/invite-link |
The link is messenger-specific — a Signal invite link won’t work on SimpleX.
How this connects to the API
Once the group exists and has members, messaging happens through the public API, not the dashboard. The connection between the two is the groupId.
When a member messages the group, PrivacyFlow routes the inbound to your poll queue with isGroupMessage: true and a groupId field. Your client — the MCP server, Agent Zero channel, or n8n node — sees the groupId and should pass it back unchanged on send:
{
"messages": [
{
"appId": "app_123",
"contactId": "<sender's contactId>",
"messenger": "session",
"message": "Got it — assigning an agent.",
"groupId": "group_abc123"
}
]
}
Without the groupId (or with the wrong one) the reply goes as a DM to the sender, not to the group thread. Each client surfaces this:
- n8n node warns about it in the trigger UI.
- Agent Zero channel propagates
groupIdautomatically throughpf_routing. - MCP server expects the LLM to lift
groupIdfrom the polled JSON and include it on send.
Tip
Group creation and member management are operator actions, not user-facing. End users message the group the same way they’d message any Signal/SimpleX/Session group; PrivacyFlow handles the plumbing. You only need the ManageGroupModal when you’re standing up a new group or rotating admins.
Underlying API calls
| UI action | API route |
|---|---|
| Open ManageGroupModal → loads member list | GET /dashboard/api/dashboard/group/members?appMessengerId=<id> |
| ”Copy invite link” button | GET /dashboard/api/dashboard/group/invite-link?appMessengerId=<id> |
| Add member → Save | POST /dashboard/api/dashboard/group/members/add with { appMessengerId, contactId } |
| Remove member | POST /dashboard/api/dashboard/group/members/remove with { appMessengerId, contactId } |
| Promote to admin | POST /dashboard/api/dashboard/group/promote-admin with { appMessengerId, contactId } |
| Demote admin | POST /dashboard/api/dashboard/group/demote-admin with { appMessengerId, contactId } |
appMessengerId is the join-record id for the specific (app × messenger) group you’re managing — get it from the app object or the modal’s open context. See the account API reference for the full route surface.