Authentication
How V3 Custody authenticates requests: a Bearer token for services and mobile apps, an httpOnly cookie for the web, and invite-only registration.
Every request to the V3 Custody API must be authenticated. The platform accepts two methods: a Bearer token (for server integrations and mobile apps) and an httpOnly cookie (for the web console). Every endpoint accepts both.
A token grants access to funds and operations. Never commit it to a repository or embed it in code: keep it in environment variables or a secrets manager.
Two authentication methods
Bearer: services and mobile apps
Pass the session token in the Authorization header. This is how server integrations and mobile clients authenticate.
Bearer token: Authorization: Bearer <token>.
curl "[BASE_URL]/api/v1/vaults" \
-H "Authorization: Bearer $V3_TOKEN"
const res = await fetch("[BASE_URL]/api/v1/vaults", {
headers: { Authorization: `Bearer ${process.env.V3_TOKEN}` },
});
import os, requests
res = requests.get(
"[BASE_URL]/api/v1/vaults",
headers={"Authorization": f"Bearer {os.environ['V3_TOKEN']}"},
)
Cookie: web console
Signing in to the web console sets an httpOnly session cookie. The browser sends it automatically, so you never handle it manually, and by design it isn't accessible from JavaScript. For server-to-server integrations, use a Bearer token rather than a cookie.
Invite-only registration
Self-registration is disabled: a hook blocks sign‑up without a valid invitation. A new member joins a Vault as follows:
An administrator creates an invitation
The invitation specifies an email address and the groups the member will join on acceptance. The endpoint is POST /api/v1/invitations.
The member accepts the invitation
When someone registers through an invitation, the platform automatically creates their group memberships (PolicyGroupMembership) and marks the invitation as accepted.
Groups determine access
A member's permissions come from the groups they belong to. Tokens have no separate scopes.
Invitation not accepted yet? You can revoke it with POST /api/v1/invitations/{id}/revoke. An accepted invitation can't be revoked; remove the member from their groups instead.
Verify authentication
The simplest way to check a token is to request the list of Vaults.
curl -i "[BASE_URL]/api/v1/vaults" \
-H "Authorization: Bearer $V3_TOKEN"
const res = await fetch("[BASE_URL]/api/v1/vaults", {
headers: { Authorization: `Bearer ${process.env.V3_TOKEN}` },
});
console.log(res.status); // 200 — token accepted
res = requests.get(
"[BASE_URL]/api/v1/vaults",
headers={"Authorization": f"Bearer {os.environ['V3_TOKEN']}"},
)
print(res.status_code) # 200 — token accepted
If the token is missing or expired, the API returns 401:
{
"error": "Unauthorized",
"message": "Authentication required. Please provide a valid API token",
"code": 401
}
Who sees what
Authentication answers "who are you," while the access model answers "what are you allowed to do." In V3 Custody, access comes from group membership, and visibility is restricted by default: a regular member sees their own addresses, operations, and balances, while an administrator sees the entire Vault. Permissions are applied before any calculations, so other members' data doesn't leak even into aggregate figures.