Invite your team
Invite members by email with group assignments, revoke an invitation, and add an existing user to a group.
Registration in V3 Custody is invite-only. You invite a member by email and assign the groups they'll join on acceptance right away; their access comes from exactly those groups. For the access model, see Authentication and Policy Engine.
The invitation lifecycle, from creation to group membership:
Prerequisites
- A Vault (
vaultId) and an access token (see Authentication). - The invitee's email address, which must be free (no existing user and no active invitation).
- Group ids, all from the same Vault.
Step 1. Create an invitation
POST /api/v1/invitations creates a pending invitation with a list of groups. Validation checks that the email is free (no existing user and no active invitation) and that all groups belong to the Vault.
curl -X POST "[BASE_URL]/api/v1/invitations" \
-H "Authorization: Bearer $V3_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"vaultId": "VAULT_ID",
"email": "trader@acme.com",
"groups": ["POLICY_GROUP_ID"]
}'
const res = await fetch("[BASE_URL]/api/v1/invitations", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.V3_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
vaultId: "VAULT_ID",
email: "trader@acme.com",
groups: ["POLICY_GROUP_ID"],
}),
});
console.log(await res.json());
res = requests.post(
"[BASE_URL]/api/v1/invitations",
headers={"Authorization": f"Bearer {os.environ['V3_TOKEN']}"},
json={
"vaultId": "VAULT_ID",
"email": "trader@acme.com",
"groups": ["POLICY_GROUP_ID"],
},
)
print(res.json())
The response contains the created invitation with a token for the magic link.
Check the exact body field names (vaultId, email, groups here) on the create invitation page in the API Reference.
Step 2. Accepting the invitation
Each invitation has a token. The acceptance page reads it through a public endpoint:
GET /api/v1/invitations/by-token/{token}is public and requires no authorization (security relies on the token's entropy). It shows "You're invited to <vault> as <groups>"; for revoked or accepted invitations, it returns410 Gone.
During actual registration, acceptance happens automatically: the platform finds the pending invitation by email, creates a PolicyGroupMembership, and marks the invitation as accepted. For debugging, POST /api/v1/invitations/accept-debug runs the same logic for an existing user.
Invitation states and what by-token returns:
| State | Meaning | by-token |
|---|---|---|
pending | created, awaiting acceptance | 200 + details |
accepted | accepted, membership created | 410 Gone |
revoked | revoked before acceptance | 410 Gone |
Step 3. Manage invitations and groups
| Action | Request |
|---|---|
| list a Vault's invitations | GET /api/v1/vaults/{code}/invitations |
| revoke a pending invitation | POST /api/v1/invitations/{id}/revoke |
| read by token (public) | GET /api/v1/invitations/by-token/{token} |
| debug acceptance | POST /api/v1/invitations/accept-debug |
| create a policy group | POST /api/v1/policy-groups |
| add a member to a group | POST /api/v1/policy-groups/{id}/members |
An accepted invitation can't be revoked; remove the user from their groups instead.
Step 4. Roles are groups
A member's permissions come from the groups they belong to; tokens have no separate scopes. The userId you pass when adding someone to a group can be any string, which is also how service accounts are connected. Removing someone from a group revokes the access that group granted. For details, see the Share and revoke access guide.
Common mistakes
| Symptom | Cause |
|---|---|
| email is taken or already has an invitation | you can't create a second active invitation for the same email |
| group isn't from this Vault | all groups must belong to the invitation's Vault |
by-token returned 410 | the invitation has already been accepted or revoked |
| accepted invitation can't be revoked | remove the user from their groups instead of using revoke |
| member has no permissions | they haven't been added to any group; access = membership |
You're done when
POST /api/v1/invitationsreturned an invitation with atoken;by-tokenreturns details forpendingand410for accepted or revoked invitations;- a
PolicyGroupMembershipis created after acceptance; - removing someone from a group revokes the corresponding access.