Organizations
Manage organizations, members, invitations, and billing. Organizations are the top-level entity for multi-tenancy, grouping users, projects, and resources under a shared namespace.
All endpoints require authentication via X-API-Key header and the appropriate scope.
Organization Object
{
"_id": "org-admin-user-ecr5aqmqq",
"name": "Admin User's Organization",
"description": "Personal organization for Admin User",
"ownerId": "okRpaKPh8B9asdKb2",
"adminIds": [],
"billingEmail": "admin@strongly.ai",
"settings": {
"timezone": "America/New_York",
"currency": "USD",
"fiscalYearStart": 1
},
"credits": {
"balance": 0,
"lifetimeUsed": 0,
"lastUpdated": null,
"alertThresholds": [2000, 1000, 500, 0]
},
"status": "active",
"createdAt": "2026-04-26T16:07:16.269Z",
"updatedAt": "2026-04-26T16:07:16.269Z",
"createdBy": "okRpaKPh8B9asdKb2"
}
| Field | Description |
|---|---|
_id | Organization ID, for example org-acme-7ohe2kqcw. |
name, description | Name and description. |
ownerId | User ID of the organization's owner. |
adminIds | User IDs of additional administrators recorded on the organization. Membership and member roles are read with GET /api/v1/organizations/:id/members. |
billingEmail | Where billing notifications are sent. |
settings | timezone (IANA name), currency, and fiscalYearStart (month, 1-12). |
credits | The organization's stored credit record (amounts in US cents). It is present on every organization but applies only when billing is enabled; read the balance with GET /api/v1/organizations/:id/credits, which answers 409 billing-disabled on platforms without billing. |
status | active, suspended, or archived. |
createdAt, updatedAt | ISO 8601 UTC timestamps. |
createdBy | User ID of whoever created the organization. |
On billing-enabled platforms an organization can also carry billingMode (saas, offering, or exempt) and its subscription details.
Member Object
{
"_id": "mem_002",
"userId": "user_789",
"email": "bob@example.com",
"name": "Bob Johnson",
"role": "member",
"status": "active",
"joinedAt": "2024-08-20T14:00:00Z"
}
role is owner, admin, member or viewer. In a multi-tenant deployment a member also carries organizationId, invitedBy, platformRole and active (whether the account can sign in).
Invitation Object
{
"_id": "inv_abc001",
"organizationId": "org_xyz",
"email": "newmember@example.com",
"role": "member",
"status": "pending",
"tokenExpiresAt": "2025-02-08T14:22:00Z",
"invitedBy": "user_456",
"createdAt": "2025-02-01T14:22:00Z"
}
role is admin, member or viewer. tokenExpiresAt is when the invitation link stops working. In a multi-tenant deployment an invitation can also carry platformRole and name, and a resent one resentAt and resentBy.
GET /api/v1/organizations
List organizations, newest first. Platform administrators get every organization; everyone else gets the organizations they are an active member of.
Scope: organizations:read
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
status | string | No | Only organizations with this status: active, suspended, or archived. Without it, every organization that is not archived. |
limit | integer | No | Page size (default 50, maximum 200) |
cursor | string | No | meta.nextCursor of the previous page; omit for the first page |
Response 200 OK
{
"data": [
{ "_id": "org-admin-user-ecr5aqmqq", "name": "Admin User's Organization", "status": "active", "...": "Organization object" }
],
"meta": { "total": 41, "limit": 50, "nextCursor": null, "requestId": "9bdf2457-3dbf-42ef-949f-d85d5f851215" }
}
Each item is a full Organization object. meta.total counts every matching organization; page with cursor while meta.hasMore is true.
GET /api/v1/organizations/:id
Get a single organization by ID.
Scope: organizations:read
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Organization ID |
Response 200 OK
{ "data": { "...": "Organization object" }, "meta": { "requestId": "2c6f1d8a-4b3e-4f0a-9e7d-5a1b8c3d2e10" } }
data is the full Organization object.
PATCH /api/v1/organizations/:id
Update an organization's details.
Scope: organizations:write
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Organization ID |
Request Body
{
"name": "Acme Corporation",
"description": "Updated description",
"billingEmail": "billing@acme.example.com",
"settings": { "timezone": "Europe/London" }
}
| Field | Type | Required | Description |
|---|---|---|---|
name | string | No | Organization name |
description | string | No | Organization description |
billingEmail | string | No | Where billing notifications are sent |
settings | object | No | Any of timezone, currency, fiscalYearStart; merged into the current settings |
alertThresholds | integer[] | No | Credits only: balances, in cents, at which the organization is alerted |
Only an owner or admin of the organization, or a platform administrator, can update it. The credit fields exist only when billing is enabled; sending any of them otherwise returns 409 billing-disabled and changes nothing.
Response 200 OK
Returns the updated Organization object.
GET /api/v1/organizations/:id/members
List all members of an organization.
Scope: organizations:read
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Organization ID |
Response 200 OK
{
"data": [
{
"_id": "mem_001",
"userId": "user_456",
"email": "jane@example.com",
"name": "Jane Smith",
"role": "owner",
"status": "active",
"joinedAt": "2024-01-10T08:00:00Z"
},
{
"_id": "mem_002",
"userId": "user_789",
"email": "bob@example.com",
"name": "Bob Johnson",
"role": "member",
"status": "active",
"joinedAt": "2024-08-20T14:00:00Z"
}
],
"meta": { "requestId": "req_abc123" }
}
data holds the organization's active members. In a multi-tenant deployment each member also has platformRole and active (whether the account can sign in).
POST /api/v1/organizations/:id/members
Add an existing user as a member to the organization.
Scope: organizations:write
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Organization ID |
Request Body
{
"userId": "user_new001",
"role": "member"
}
| Field | Type | Required | Description |
|---|---|---|---|
userId | string | Yes | ID of the user to add |
role | string | No | Member role: member, admin, billing (default: member) |
Response 201 Created
{
"data": {
"_id": "mem_003",
"organizationId": "org_xyz",
"userId": "user_new001",
"role": "member",
"joinedAt": "2025-02-01T14:22:00Z",
"invitedBy": "user_456",
"status": "active"
},
"meta": { "requestId": "req_abc123" }
}
data is the new membership.
DELETE /api/v1/organizations/:organizationId/members/:id
Remove a member from the organization. The organization owner cannot be removed.
Scope: organizations:write
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
organizationId | string | Yes | Organization ID |
id | string | Yes | User ID of the member to remove |
Response 200 OK
{
"data": {
"assetAction": "transfer",
"transferTo": "user_456",
"assetsHandled": {
"workflows": 2,
"projects": 1,
"volumes": 0,
"apps": 1,
"addons": 0,
"workspaces": 1,
"datasources": 0,
"prompts": 3,
"abTests": 0,
"routers": 0,
"aiModels": 0,
"guardrails": 0,
"mlModels": 0,
"total": 8
}
},
"meta": { "requestId": "req_abc123" }
}
The removed member's resources are transferred to the organization owner (transferTo); assetsHandled counts what was transferred, by type.
PATCH /api/v1/organizations/:organizationId/members/:id
Update a member's role within the organization.
Scope: organizations:write
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
organizationId | string | Yes | Organization ID |
id | string | Yes | User ID of the member |
Request Body
{
"role": "admin"
}
| Field | Type | Required | Description |
|---|---|---|---|
role | string | Yes | New role: member, admin, billing |
Response 200 OK
{
"data": {
"_id": "mem_002",
"organizationId": "org_xyz",
"userId": "user_789",
"role": "admin",
"joinedAt": "2024-08-20T14:00:00Z",
"status": "active"
},
"meta": { "requestId": "req_abc123" }
}
data is the member's updated membership.
POST /api/v1/organizations/:id/invitations
Send an invitation to join the organization via email.
Scope: organizations:write
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Organization ID |
Request Body
{
"email": "newmember@example.com",
"role": "member"
}
| Field | Type | Required | Description |
|---|---|---|---|
email | string | Yes | Email address to invite |
role | string | Yes | Role to assign upon acceptance: member, admin, billing |
Response 201 Created
The new invitation, status pending (its acceptance token is only in the email).
GET /api/v1/organizations/:id/invitations
List the organization's pending invitations, newest first.
Scope: organizations:read
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Organization ID |
Response 200 OK
{
"data": [
{
"_id": "inv_abc001",
"organizationId": "org_xyz",
"email": "newmember@example.com",
"role": "member",
"status": "pending",
"invitedBy": "user_456",
"tokenExpiresAt": "2025-02-15T00:00:00Z",
"createdAt": "2025-02-01T14:22:00Z"
}
],
"meta": { "requestId": "req_abc123" }
}
DELETE /api/v1/organizations/:organizationId/invitations/:id
Cancel a pending invitation.
Scope: organizations:write
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
organizationId | string | Yes | Organization ID |
id | string | Yes | Invitation ID |
Response 204 No Content
POST /api/v1/organizations/:organizationId/invitations/:id/resend
Resend a pending invitation (multi-tenant deployments only). The invitation gets a new link, valid for 7 days from now (the previous link stops working), and the invitation email is sent again. The invitation's resentAt and resentBy are set.
Scope: organizations:write
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
organizationId | string | Yes | Organization ID |
id | string | Yes | Invitation ID |
Response 200 OK
{
"data": { "resent": true },
"meta": { "requestId": "req_abc123" }
}
Errors
| Status | Code | When |
|---|---|---|
| 400 | validation-error | Invalid organization ID or invitation ID |
| 403 | forbidden | You are not an owner or admin of the invitation's organization (platform administrators can resend any invitation) |
| 404 | not-found | No pending invitation with this ID (it does not exist, or was already accepted or revoked) |
| 500 | internal-error | The deployment is not multi-tenant; the message is Resending invitations is part of multi-tenant team management |
Credits
Credits are the organization's prepaid balance on platforms with billing enabled. On a platform without billing, credits do not apply: nothing is charged against a balance, and every credit endpoint below (and the credit fields of PATCH /api/v1/organizations/:id) answers:
{
"type": "urn:strongly:problem:billing-disabled",
"title": "billing-disabled",
"status": 409,
"detail": "Billing is not enabled on this install, so credits and subscriptions do not apply.",
"code": "billing-disabled",
"requestId": "4866806e-f016-4672-b611-d8fb864a6e59"
}
Credits are separate from FinOps budgets: a budget never charges or deducts credits. All amounts are integer US cents (10000 is $100.00).
GET /api/v1/organizations/:id/credits
Get the organization's credit balance. Members of the organization and platform administrators can read it.
Scope: organizations:read
Response 200 OK
{
"data": {
"balance": 12500,
"monthlyCreditsBalance": 2500,
"purchasedCreditsBalance": 10000,
"monthlyCreditsExpireAt": "2026-10-01T00:00:00.000Z",
"purchasedCreditsExpireAt": "2026-12-20T14:02:11.000Z",
"lifetimeAdded": 20000,
"lifetimeUsed": 7500,
"alertThresholds": [2000, 1000, 500, 0],
"autoPurchase": null
},
"meta": { "requestId": "7c1d5e0a-2b7e-4f8e-9d59-1f0b3a6c2e11" }
}
| Field | Description |
|---|---|
balance | Credits available: monthlyCreditsBalance + purchasedCreditsBalance. |
monthlyCreditsBalance, monthlyCreditsExpireAt | Credits from the subscription and when they expire (the end of the billing period). |
purchasedCreditsBalance, purchasedCreditsExpireAt | Purchased credits and when the oldest of them expire (90 days after purchase). |
lifetimeAdded, lifetimeUsed | Totals since the organization was created. |
alertThresholds | Balances, in cents, at which the organization is alerted. |
autoPurchase | The subscription's automatic top-up (enabled, threshold, packageId, maxPerMonth), or null. |
When the balance is used up (zero or below), every new launch is refused and the organization's running services are stopped (their data is kept); they are deleted after 30 days if no credits are added. A launch is never refused for what it might cost: what runs is charged as it runs, so a balance can go slightly negative.
Errors
| Status | Code | When |
|---|---|---|
| 403 | forbidden | You are not a member of the organization or a platform administrator |
| 404 | not-found | No organization has this ID |
| 409 | billing-disabled | Billing is not enabled on this platform |
POST /api/v1/organizations/:id/credits
Add credits to an organization, as Add Credits does on the organization's page. Platform administrators only. The credits are added to the purchased pool and recorded as an admin_allocation transaction, which is returned.
Scope: organizations:write
Request Body
{ "amount": 10000, "note": "Pilot allowance" }
| Field | Type | Required | Description |
|---|---|---|---|
amount | integer | Yes | Credits to add, in US cents. Must be greater than zero. |
note | string | No | Why the credits were added. Shown as the transaction's description. |
Response 201 Created: the transaction.
Errors
| Status | Code | When |
|---|---|---|
| 400 | validation-error | amount is not a positive whole number, or note is not a string |
| 403 | forbidden | You are not a platform administrator |
| 409 | billing-disabled | Billing is not enabled on this platform |
GET /api/v1/organizations/:id/transactions
List the organization's credit transactions, newest first. Members of the organization and platform administrators can read them.
Scope: organizations:read
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
type | string | No | Only transactions of this type (see below) |
limit | integer | No | Page size (default 50, maximum 200) |
cursor | string | No | meta.nextCursor of the previous page; omit for the first page |
Response 200 OK
{
"data": [
{
"_id": "hS3kq8WbLx2nTzP4c",
"organizationId": "org-acme",
"userId": "okRpaKPh8B9asdKb2",
"type": "usage_charge",
"status": "completed",
"amount": -1250,
"balanceBefore": 13750,
"balanceAfter": 12500,
"description": "Workspace ml-dev: 5 hours",
"reference": {
"resourceType": "workspace",
"resourceId": "ws-7fk2m",
"resourceName": "ml-dev",
"deductedFromMonthly": 1250,
"deductedFromPurchased": 0
},
"createdAt": "2026-09-23T03:00:12.532Z"
}
],
"meta": { "total": 1, "limit": 50, "nextCursor": null, "requestId": "0b8e4f3a-5d62-4c1e-a7f9-2e6d8c4b1a90" }
}
| Field | Description |
|---|---|
type | subscription_credit, credit_purchase, auto_purchase, admin_allocation, admin_adjustment, usage_charge, refund, promo_credit, transfer_in, or transfer_out. |
status | pending, completed, failed, or refunded. |
amount | Positive adds credits, negative uses them. |
balanceBefore, balanceAfter | The balance around the transaction. |
reference | What the transaction is about: the resource a usage charge is for and how it split between monthly and purchased credits, the administrator and note of an allocation, or the purchase. |
Errors
| Status | Code | When |
|---|---|---|
| 403 | forbidden | You are not a member of the organization or a platform administrator |
| 409 | billing-disabled | Billing is not enabled on this platform |