End-user Organizations
End-user organizations (end-user orgs) give your application’s users a way to collaborate as a team under a shared billing plan. Each org has a seat limit, and usage is metered at the org level rather than per individual user.
Key Concepts
- Seat-based billing: Organizations are billed by seat count. A billing plan assigns a
seat_limit, and active members occupy seats. - Seat enforcement:
seat_enforcement_modecontrols what happens when the seat limit is reached —hardblocks new members,softallows over-provisioning with a warning. - Domain auto-join: When enabled, users who sign up with a matching verified domain are automatically added to the org.
- Roles: Members have a
role(owner,admin, ormember) and astatus(active,pending,invited,suspended).
Organization Endpoints
Create an organization
POST /v1/end-user-orgs
{
"name": "Acme Corp",
"billing_plan_id": "plan-uuid",
"seat_limit": 25,
"seat_enforcement_mode": "hard",
"domain_auto_join_enabled": false,
"settings": {}
}All fields except name are optional.
List organizations
GET /v1/end-user-orgs
Returns all organizations the authenticated user belongs to.
Get an organization
GET /v1/end-user-orgs/:id
Update an organization
PATCH /v1/end-user-orgs/:id
Send only the fields you want to change:
{
"name": "Acme Corp (renamed)",
"domain_auto_join_enabled": true
}Delete an organization
DELETE /v1/end-user-orgs/:id
Organization fields
| Field | Type | Description |
|---|---|---|
id | uuid | Org identifier |
organization_id | uuid | Builder org this belongs to |
application_id | uuid | Application this belongs to |
name | string | Display name |
slug | string | URL-safe identifier |
billing_plan_id | uuid | Active billing plan |
stripe_subscription_id | string | Stripe subscription reference |
seat_limit | integer | Maximum number of active members |
seat_count | integer | Current active member count |
seat_enforcement_mode | string | hard or soft |
domain_auto_join_enabled | boolean | Auto-add users by verified domain |
settings | object | Arbitrary org-level settings |
created_at | timestamp | |
updated_at | timestamp |
Member Management
Add a member
POST /v1/end-user-orgs/:id/members
{
"user_id": "user-uuid",
"role": "member"
}role defaults to member if omitted. Returns 409 if the user is already a member.
List members
GET /v1/end-user-orgs/:id/members
Update a member’s role
PATCH /v1/end-user-orgs/:id/members/:member_id/role
{
"role": "admin"
}Approve a pending member
POST /v1/end-user-orgs/:id/members/:member_id/approve
Moves a member from pending to active status. Requires admin or owner role.
Remove a member
DELETE /v1/end-user-orgs/:id/members/:member_id
Member fields
| Field | Type | Description |
|---|---|---|
id | uuid | Membership record identifier |
end_user_org_id | uuid | Parent org |
user_id | uuid | User reference |
role | string | owner, admin, or member |
status | string | active, pending, invited, or suspended |
invited_by | uuid | User who created the invitation |
created_at | timestamp | |
updated_at | timestamp |
Domain Management
Verified domains enable automatic org membership for users signing up with a matching email domain.
Add a domain
POST /v1/end-user-orgs/:id/domains
{
"domain": "acme.com"
}Returns a verification_record DNS TXT value that must be published before the domain can be verified.
List domains
GET /v1/end-user-orgs/:id/domains
Verify a domain
POST /v1/end-user-orgs/:id/domains/:domain_id/verify
Triggers a DNS lookup for the verification_record TXT entry. Returns 200 with verified: true on success, or 400 if the record is not found.
Remove a domain
DELETE /v1/end-user-orgs/:id/domains/:domain_id
Domain fields
| Field | Type | Description |
|---|---|---|
id | uuid | Domain record identifier |
end_user_org_id | uuid | Parent org |
domain | string | Domain name (e.g., acme.com) |
verified | boolean | DNS verification status |
verification_record | string | TXT value to publish for verification |
created_at | timestamp |
Seat Management
Adjust seat limit
PATCH /v1/end-user-orgs/:id/seats
{
"seat_limit": 50
}Increasing seats on a metered plan triggers a Stripe proration. Use the preview endpoint first to show the user the cost.
Get seat usage
GET /v1/end-user-orgs/:id/seats
{
"end_user_org_id": "org-uuid",
"seat_limit": 25,
"seat_count": 18,
"available_seats": 7
}Preview seat proration
POST /v1/end-user-orgs/:id/seats/preview-proration
{
"seat_limit": 50
}Returns the prorated charge that would be applied immediately for the current billing period, before any changes are committed.