Organizations API
Org-level routes. All require Authorization: Bearer <access_token>
with the appropriate IdentityOrgPermission granted on the org by
the caller’s role.
:orgSlug in the URL identifies the org. Slugs are stable, lowercase,
URL-safe.
Create an org
POST /identity/organizations
{
name: string // 1–80 chars
slug: string // [a-z0-9-]{3,30}, globally unique
description?: string // up to 500 chars
}Response (201): the created Org.
Errors:
validation_failed— slug or name failed validation.conflict— slug already exists.
Get an org
GET /identity/organizations/:orgSlug
Requires org.read (implied by every member).
Response:
interface Org {
id: string
name: string
slug: string
description?: string
iconFile?: FileTracker
createdBy: string
stripeProductId?: string | null
stripeCustomerId?: string
createdAt: string
updatedAt: string
}Update an org
PATCH /identity/organizations/:orgSlug — requires org.edit.
{
name?: string
description?: string | null
iconFile?: string | null // FileTracker id, or null to clear
}slug is not editable once set. Create a new org if you need a
new slug.
Delete an org
DELETE /identity/organizations/:orgSlug — requires org.delete,
owner-only.
Soft-deletes. All brands, apps, members, webhooks, and token gates under the org are disabled. The slug is reserved (cannot be reused for 90 days).
Response: 204 No Content.
List orgs
GET /identity/organizations — returns orgs the caller is a member
of (or all orgs, with admin.orgs.view).
Query params:
| Param | Type | Default |
|---|---|---|
limit | 1–100 | 50 |
offset | number | 0 |
Response:
{
items: Org[]
total: number
}Members
List members
GET /identity/organizations/:orgSlug/members
Requires org.members.view.
{
items: Array<{
userId: string
user: User // full shape
roles: Array<{ id: string; name: string }>
joinedAt: string
}>
total: number
}Add role
POST /identity/organizations/:orgSlug/members/:userId/roles
Requires org.members.edit.
{ roleId: string }Idempotent. If the role is already assigned, returns the unchanged state. Returns 201.
Remove role
DELETE /identity/organizations/:orgSlug/members/:userId/roles/:roleId
Requires org.members.edit.
Returns 204. Cannot remove the last role from a member — call
DELETE /members/:userId to remove them entirely.
Remove member
DELETE /identity/organizations/:orgSlug/members/:userId
Requires org.members.edit. Removes the member from the org. Their
access tokens for this org are not invalidated automatically — they
expire on their own; revoke explicitly if you need immediate cutoff.
Owner cannot be removed; transfer ownership first.
Transfer ownership
POST /identity/organizations/:orgSlug/transfer-ownership
Requires org.ownership.transfer (owner-only).
{ newOwnerUserId: string }Transitions ownership atomically. The previous owner keeps Admin role; the new owner gains the Owner role.
Roles
List roles
GET /identity/organizations/:orgSlug/roles
{
items: Array<{
id: string
name: string
description?: string
isBuiltIn: boolean
permissions: string[] // IdentityOrgPermission strings
createdAt: string
updatedAt: string
}>
}Built-in roles (Owner, Admin, Member) cannot be edited or
deleted.
Create a custom role
POST /identity/organizations/:orgSlug/roles
Requires org.members.edit.
{
name: string // 1–60 chars
description?: string
permissions: string[] // any subset of IdentityOrgPermission
}Response (201): the new role.
Update a custom role
PATCH /identity/organizations/:orgSlug/roles/:roleId
{
name?: string
description?: string | null
permissions?: string[] // replaces existing list
}Cannot edit built-in roles.
Delete a custom role
DELETE /identity/organizations/:orgSlug/roles/:roleId
Cannot delete if any member currently has this role assigned; unassign first.
Admin (system) routes
Routes under /admin/identity/organizations/... require
AdminPermission.OrgsView / .OrgsEdit. They mirror the
org-scoped routes above but bypass org membership checks. Used by
Synq staff for support; you probably will not call these.
Rate limits
| Endpoint pattern | Limit |
|---|---|
GET /identity/organizations/* | 60/min/org |
POST/PATCH/DELETE … | 30/min/org |
Errors
Standard REST envelope. See Errors for the full catalog.
Most common:
forbidden— missing org permission.details.missingis the required permission.conflict— slug or role name in use.validation_failed— body validation;details.fieldslists each.