POST /teams
Create a new collaborative team and register the owner’s self-grant for the team’s Data Encryption Key.string
required
A display label for the team. Between 1 and 128 characters.
string
required
The owner’s public key as a PEM-encoded string. Used for asymmetric wrapping of the team DEK.
string
required
The team’s Data Encryption Key (DEK), encrypted (wrapped) to the owner’s public key. The server stores this opaque blob and returns it to the owner when they call
GET /teams/:id/grant.Response — 201 Created
curl Example
POST /teams/:id/grants
Invite a new member or update an existing member’s access by publishing the team DEK wrapped to the recipient’s public key.string
required
Identifier for the new member (e.g. their wallet address or user ID).
string
required
The recipient’s PEM-encoded public key. The team DEK must be wrapped to this key before submission.
string
required
The team DEK encrypted to
member_pubkey. The server stores this opaque blob for the member to retrieve via GET /teams/:id/grant.string
required
Access level for this member. One of
"admin", "write", or "read".Response — 201 Created
Issuing a grant to a new member runs the same seat-quota check as
POST /teams/:id/invitations below — on a paid team plan at its seat limit, this can automatically increment your Polar subscription’s seat count.GET /teams/:id/grant
Fetch the wrapped DEK registered for the authenticated caller. Decrypt it locally with your private key to obtain the team’s plaintext DEK.Response — 200 OK
403 no_grant if the caller has not accepted an invitation or otherwise holds no grant for this team — this is how a revoked member is locked out: their grant row was deleted, so they cannot retrieve the DEK.
curl Example
POST /teams/:id/rotate
Revoke a member, increment the team’s rotation epoch, and re-wrap the team DEK to all remaining active members. Clients must generate a new DEK, wrap it individually to each remaining member’s public key, and submit all updated grants in a single atomic operation.string
Identifier of the member to revoke. Optional — omit to rotate the DEK on a routine schedule without revoking anyone.
string
Human-readable reason for revocation (e.g.
"offboarding", "security_incident"). Defaults to "manual_rotation" if omitted.array
required
Array of updated grant objects for every remaining active member. Each must include
member_id (string) and wrapped_dek (string) — the new DEK wrapped to that member’s existing public key.Response — 200 OK
POST /teams/:id/memories
Append a client-encrypted ciphertext block to the team’s shared memory history. All active members holding the current DEK can decrypt this block locally. Requireswrite role or higher.
string
required
Base64-encoded AES-256-GCM ciphertext with the GCM auth tag appended. Maximum decoded size is 256 KB.
string
Identifier to attribute this write to in the sync log. Optional — defaults to the authenticated caller’s user ID.
Response — 201 Created
GET /teams/:id/memories
Retrieve the complete encrypted memory ciphertext history for the team. Decrypt each entry locally using the team DEK you obtained fromGET /teams/:id/grant. Requires read role or higher — a revoked (inactive) member is rejected here, so even ciphertext is withheld.
Response — 200 OK
POST /teams/:id/subkeys
Issue a programmaticsov_live_ API key bound to a specific team member grant. Sub-keys inherit the member’s role and are independently revocable without affecting other keys. Requires write role or higher to bind a sub-key to yourself; binding to a different member requires admin.
string
required
A human-readable label for this sub-key (e.g.
"ci-sync-script"). Between 1 and 128 characters.string
Identifier of the team member this sub-key is bound to. Optional — defaults to the authenticated caller. The bound member must already hold a grant.
Response — 201 Created
GET /teams/:id/sync-log
Retrieve per-agent telemetry statistics for the team’s recent replication activity (most recent 200 entries). Requiresread role or higher.
Response — 200 OK
GET /teams/:id/members
List all team members with their roles, activation statuses, and grant states. Requiresread role or higher. Never returns wrapped_dek, member_pubkey, or any ciphertext — roster metadata only.
Response — 200 OK
curl Example
GET /teams
List every team the authenticated user belongs to (active memberships only).Response — 200 OK
POST /teams/:id/invitations
Invite a new member by email. Admin-gated. Triggers a seat-quota check — if the team is at its seat limit on a paid plan, this automatically increments the Polar subscription’s seat count and emails the owner; on a plan that doesn’t support auto-scaling, it returns403 seat_limit_reached instead and emails the owner that a seat is needed.
string
required
The invitee’s email address.
string
Access level to grant on acceptance. One of
"admin", "write", "read". Defaults to "read".Response — 201 Created
POST /teams/:id/guardians/invite
Invite a Shamir key-recovery guardian by email — a distinct invitation type from a regular team member, used for the Managed Key Recovery escrow flow.string
required
The guardian’s email address.
Response — 201 Created
GET /teams/:id/audit
List the team’s tamper-evident audit ledger entries, newest first. Requires active membership. Supports optionalactor, action, from, to query filters and limit (default 200, max 1000).
Each row includes prev_hash and entry_hash so a client can re-verify the SHA-256 hash chain locally — see Trust Center for the chain construction.
Response — 200 OK
GET /teams/:id/audit/verify
Re-verify the audit chain’s hash integrity server-side and report the result.Response — 200 OK
broken_seq.
GET /teams/:id/audit/export
Admin-gated (a full ledger export leaving the system is treated as an admin-grade action). Accepts optionalfrom/to date filters. Returns the same verified, well-formed JSON export used for compliance evidence.