Skip to main content
OpenAPI

Billing Group APIs

Manage Credits attribution, group limits, members, and period usage.

Use Billing Group APIs to attribute member Credits consumption, set a shared limit for a billing period, and retrieve period usage. A member belongs to at most one billing group at a time.
Applicable plans: Enterprise.
Complete Get API Key and review OpenAPI Conventions before calling these endpoints.

Requirements

  • Send Authorization: Bearer <api_key>.
  • Send Content-Type: application/json for requests with a JSON body.
  • Use the organization bound to the API key as organization_id.
  • Use user IDs, not organization member IDs, in member assignment requests. Obtain them from the userId field returned by Member APIs.

Key behavior

  • Unassigned is the built-in billing group for members without an explicit assignment. Its ID is the literal string unassigned.
  • Unassigned cannot be renamed, deleted, or assigned a group limit.
  • Reassigning a member changes only the current assignment. Usage already recorded remains attributed to the billing group captured when the Credits were consumed.
  • Deleting a billing group moves its current members to Unassigned; historical usage, the deleted group ID, and its last stored name remain available through the usage endpoint.
  • Group limits and usage values are expressed in Credits.

Data models

Billing group

FieldTypeDescription
idstringBilling group ID; unassigned for the built-in group
organizationIdstringOrganization ID
namestringBilling group name; always Unassigned for the built-in group
descriptionstringDescription; omitted when empty
isUnassignedbooleanWhether this is the built-in Unassigned group
memberCountintegerNumber of members currently assigned to the group
limitAmountnumberPeriod limit in Credits; -1 means unlimited and 0 means frozen
currentUsednumberCredits used in the selected period; this value can exceed the configured limit
isBlockedbooleanWhether the selected-period usage has reached or exceeded a nonnegative limit
creatorIdstringCreator user ID; omitted when unavailable
createdAtstringCreation time in ISO 8601 format; omitted when unavailable
updatedAtstringLast update time in ISO 8601 format; omitted when unavailable

Usage period

A usage period is a half-open interval: periodStart is inclusive and periodEnd is exclusive.
FieldTypeDescription
periodStartstringPeriod start in ISO 8601 format
periodEndstringPeriod end in ISO 8601 format

API reference

List billing groups

GET /v1/organizations/{organization_id}/billing-groups
Query parameterTypeRequiredDescription
periodEndstringNoExact period end in RFC 3339 format; omit to use the current or latest period
keywordstringNoMatch a billing group name, or a current member name or email
maxResultsintegerNoNumber of regular billing groups per page; default 20, max 100
nextTokenstringNoCursor returned by the previous response
The first page prepends the synthetic Unassigned row. Because this row is not counted against maxResults, the first page can contain up to maxResults + 1 entries. When keyword is set, Unassigned is included only when the keyword matches its name or one of its current members.

Success response (200 OK)

{
  "billingGroups": [
    {
      "id": "unassigned",
      "organizationId": "org_xxx",
      "name": "Unassigned",
      "isUnassigned": true,
      "memberCount": 4,
      "limitAmount": -1,
      "currentUsed": 320,
      "isBlocked": false
    },
    {
      "id": "9bcb59cb-07e6-4a2d-9655-56aaf16b0e34",
      "organizationId": "org_xxx",
      "name": "Platform",
      "description": "Platform cost center",
      "isUnassigned": false,
      "memberCount": 12,
      "limitAmount": 10000,
      "currentUsed": 4250,
      "isBlocked": false,
      "creatorId": "550e8400-e29b-41d4-a716-446655440000",
      "createdAt": "2026-08-01T08:00:00Z",
      "updatedAt": "2026-08-10T09:30:00Z"
    }
  ],
  "maxResults": 20,
  "nextToken": "cursor_from_response",
  "selectedPeriod": {
    "periodStart": "2026-08-01T00:00:00Z",
    "periodEnd": "2026-09-01T00:00:00Z"
  }
}
selectedPeriod identifies the period used for each group's currentUsed and isBlocked; it is omitted when no period is available. limitAmount is the group's current configuration, not a historical snapshot. When you select a historical period, isBlocked compares that current limit with the selected period's usage. nextToken is omitted on the last page and must be treated as opaque.

Create a billing group

POST /v1/organizations/{organization_id}/billing-groups name is trimmed and must not be empty. Active billing group names must be unique. The name Unassigned is reserved, regardless of capitalization.

Request body

{
  "name": "Platform",
  "description": "Platform cost center"
}
FieldTypeRequiredDescription
namestringYesBilling group name
descriptionstringNoBilling group description
Returns the created Billing group with 201 Created. A new billing group defaults to limitAmount: -1 (unlimited). Creating the group, setting its limit, and assigning members are separate, non-transactional requests; persist the returned group ID and resume from the failed step when orchestrating the workflow.

Update a billing group

PUT /v1/organizations/{organization_id}/billing-groups/{billing_group_id} Omitted fields remain unchanged. Send an empty description to clear it. The built-in Unassigned group cannot be updated.

Request body

{
  "name": "Platform Engineering",
  "description": ""
}
FieldTypeRequiredDescription
namestringNoNew name; must not be empty after trimming
descriptionstringNoNew description; an empty string clears it
Returns the updated Billing group with 200 OK.

Delete a billing group

DELETE /v1/organizations/{organization_id}/billing-groups/{billing_group_id} The built-in Unassigned group cannot be deleted. Deleting another billing group moves its current members to Unassigned. Historical usage keeps its billingGroupId and resolves the deleted group's last stored name. Returns 200 OK:
{}

Set a billing group limit

POST /v1/organizations/{organization_id}/billing-groups/{billing_group_id}/limit Sets the shared Credits limit applied to the billing group in each usage period. The field is required because omitting it must not accidentally freeze the group. A new value applies to subsequent Credits consumption immediately.

Request body

{
  "limitAmount": 10000
}
Supported values:
limitAmountMeaning
-1Unlimited
0Freeze the group
Greater than 0Credits cap for the period
The limit is a soft enforcement threshold: after recorded usage reaches it, subsequent consumption from the organization's shared Credits pool is blocked. In-flight or concurrent consumption and delayed accounting can make currentUsed exceed limitAmount; do not treat it as an exact hard cap. Lowering the limit to or below current usage blocks subsequent consumption. The built-in Unassigned group does not support a limit. Returns the updated Billing group with 200 OK.

Assign one member

POST /v1/organizations/{organization_id}/billing-groups/assign Assigns or reassigns one organization member. Set billingGroupId to unassigned to remove the member's explicit billing group assignment.

Request body

{
  "userId": "550e8400-e29b-41d4-a716-446655440001",
  "billingGroupId": "9bcb59cb-07e6-4a2d-9655-56aaf16b0e34"
}
FieldTypeRequiredDescription
userIdstringYesUser UUID of an organization member
billingGroupIdstringYesTarget billing group ID, or unassigned
Returns 200 OK:
{}

Resolve Unassigned members in batch

POST /v1/organizations/{organization_id}/billing-groups/resolve Moves members from Unassigned into one regular billing group. Unlike the single-member assignment endpoint, this endpoint does not reassign members that already belong to another regular billing group. It returns partial-success details instead of failing the entire batch.

Request body

{
  "userIds": [
    "550e8400-e29b-41d4-a716-446655440001",
    "550e8400-e29b-41d4-a716-446655440002"
  ],
  "billingGroupId": "9bcb59cb-07e6-4a2d-9655-56aaf16b0e34"
}
userIds must contain at least one user ID and should not contain duplicates. billingGroupId must identify a regular billing group and cannot be unassigned.

Success response (200 OK)

{
  "succeeded": 1,
  "failed": [
    {
      "userId": "550e8400-e29b-41d4-a716-446655440002",
      "reason": "not_unassigned"
    }
  ]
}
Failure reasonMeaning
not_foundUser does not exist
not_in_orgUser is not a current member of the organization
not_unassignedMember already belongs to a regular billing group

List billing group members

GET /v1/organizations/{organization_id}/billing-groups/{billing_group_id}/members Use unassigned as billing_group_id to list members without an explicit billing group assignment.
Query parameterTypeRequiredDescription
keywordstringNoMatch member name or email
maxResultsintegerNoPage size; default 20, max 100
nextTokenstringNoCursor returned by the previous response

Success response (200 OK)

{
  "members": [
    {
      "userId": "550e8400-e29b-41d4-a716-446655440001",
      "name": "Alice",
      "email": "alice@example.com"
    }
  ],
  "maxResults": 20,
  "nextToken": "cursor_from_response"
}
email and nextToken are omitted when unavailable. A billing group ID with no current members, including an unknown ID, returns 200 OK with an empty members array.

Get billing group usage

GET /v1/organizations/{organization_id}/billing-groups/usage Returns one rollup row per billing group, user, and usage period. The row key is (billingGroupId, userId, periodStart, periodEnd). If a member consumes Credits in two billing groups during the same period, the response contains two rows for that user. Attribution is frozen when Credits are consumed, so historical rows do not move when a member is reassigned or a billing group is deleted.
Query parameterTypeRequiredDescription
billingGroupIdstringNoBilling group ID, or unassigned; omit to return all groups
periodEndstringNoExact period end in RFC 3339 format; omit to use the current or latest period
maxResultsintegerNoPage size; default 20, max 100
nextTokenstringNoCursor returned by the previous response
Use a periodEnd returned by List usage periods. If the timestamp does not match a known period exactly, the response can be empty. To query a deleted billing group, pass its retained ID as billingGroupId. Deleted groups are not returned by List billing groups; enumerate their IDs from an unfiltered usage response. Aggregate by billingGroupId, not by name, because renaming a group changes the name resolved for historical rows.

Success response (200 OK)

{
  "rows": [
    {
      "billingGroupId": "9bcb59cb-07e6-4a2d-9655-56aaf16b0e34",
      "billingGroupName": "Platform",
      "isUnassigned": false,
      "userId": "550e8400-e29b-41d4-a716-446655440001",
      "memberName": "Alice",
      "email": "alice@example.com",
      "periodStart": "2026-08-01T00:00:00Z",
      "periodEnd": "2026-09-01T00:00:00Z",
      "billingCycle": "monthly",
      "usedCredits": 1250
    }
  ],
  "maxResults": 20,
  "nextToken": "cursor_from_response"
}
Row fieldTypeDescription
billingGroupIdstringBilling group captured when usage was recorded
billingGroupNamestringCurrent or last stored billing group name; soft-deleted groups are resolved, and renames also affect historical display
isUnassignedbooleanWhether usage was attributed to Unassigned
userIdstringUser ID
memberNamestringMember name
emailstringMember email; may be empty
periodStartstringPeriod start in ISO 8601 format; always returned for a usage row
periodEndstringPeriod end in ISO 8601 format; always returned for a usage row
billingCyclestringBilling cycle for the usage row, such as monthly or yearly
usedCreditsnumberCredits attributed to the user and billing group in this period

List usage periods

GET /v1/organizations/{organization_id}/billing-groups/usage/periods Returns all usage periods currently available to the organization, newest first. The current plan month is included even when it has no usage. The endpoint is not paginated; it does not promise an indefinite retention period.

Success response (200 OK)

{
  "periods": [
    {
      "periodStart": "2026-08-01T00:00:00Z",
      "periodEnd": "2026-09-01T00:00:00Z"
    },
    {
      "periodStart": "2026-07-01T00:00:00Z",
      "periodEnd": "2026-08-01T00:00:00Z"
    }
  ]
}

Errors

Errors use the standard response shape described in OpenAPI Conventions.
HTTP statusError codeTypical cause
400BadRequestMalformed request, invalid RFC 3339 time, missing required field, or unsupported operation on Unassigned
401UnauthorizedAPI key is missing or invalid
403ForbiddenAPI key does not belong to the target organization
404NotFoundBilling group or member does not exist for an operation
409AlreadyExistsAn active billing group with the same name already exists
The member-list endpoint returns an empty list for an unknown billing group ID; use operation endpoints when you need a NotFound response for existence checks.