Members
Sharing an item, changing a role and revoking access.
All routes are protected. See Sharing for the flow these routes are part of.
List members
GET /api/v1/items/:id/membersAny member may look. The owner is in the list.
{
"data": [
{ "user_id": "…", "name": "Ada", "email": "ada@example.com", "role": "owner", "created_at": "…" }
],
"metadata": { "total": 1 }
}Share
POST /api/v1/items/:id/members{ "user_id": "…", "role": "viewer", "encrypted_item_key": "base64" }Owner only. role is editor or viewer; encrypted_item_key is the item
key wrapped with the recipient's public key. Answers 201.
| Status | When |
|---|---|
403 | The caller holds no paid plan (see Sharing) |
404 | The user does not exist or has not set up a vault |
409 | The item is already shared with this user |
A paid plan
On the hosted service, handing an item out is the one thing a plan pays for,
so with REQUIRE_PAID_SHARING=true POST /api/v1/items/:id/members answers
403 for a caller with no paid plan:
{ "message": "sharing an item needs a paid plan: subscribe in Billing, or run Montara Pass yourself" }A plan is an active subscription whose current_period_end is in the
future, or a paid one-time purchase, which never renews. A pending one
does not count.
Only this route is gated. Receiving an item is not, so a user with no plan is still added to someone else's item. Neither is changing a role or removing a member, so a user who stops paying can still revoke access, and a recipient can still leave.
A deployment without REQUIRE_PAID_SHARING, the default, is never gated. A super_user
account is not gated either: plans are kept to accounts with the user role.
Change a role
PUT /api/v1/items/:id/members/:userId{ "role": "editor" }Owner only.
Remove a member
DELETE /api/v1/items/:id/members/:userIdThe owner may remove anyone but themselves. Any other member may remove only
themselves, which is how they leave an item. Removing the owner answers 400:
delete the item instead.
After removing someone, the owner's client should rotate the item key.