Capabilities
Budgets
Budgets hold the money your organization and its projects spend on AI usage, and the per-user spend limits that apply inside them. These endpoints let you read the budgets you administer, see what each member has spent against their limit, set per-user limits in bulk, and create, fund, and configure project budgets from automation instead of the admin UI.
Every organization has one organization budget. When project budgets are turned on, each project can also have a project budget that draws from the organization budget. The organization budget is funded by its contract, so only its member limits can be changed through the API. Turning project budgets on for the organization is done in the admin UI.
Every change made through these endpoints is recorded in the audit log, the same as a change made in the admin UI.
All paths below are relative to your instance's base URL
(https://<your-domain>.nomic.ai/api/v0). See the
overview for authentication details.
Scopes
| Scope | Grants |
|---|---|
developer:budgets:read | Read the budgets you administer and their per-user limits. |
developer:budgets:write | Create and change the budgets you administer, and set their per-user limits. |
The broad developer scope implies developer:budgets:write, which in turn
implies developer:budgets:read.
Scopes only let a key call these endpoints; access to each budget still follows
your role. Organization admins administer the organization budget and every
project budget. A project admin administers that project's budget. A budget you
do not administer is reported as 404.
Wherever a path takes a budget {id}, you can pass organization in place of a
UUID to address the organization budget.
List budgets
GET /budgets
List the budgets the caller administers: the organization budget first, then
project budgets by name. All budgets fit in one page, so nextCursor is always
null.
Scope: developer:budgets:read · Rate limit: Standard (300 req / min)
Query parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
scope | organization | project | — | Only return budgets of this type. |
projectId | uuid | — | Only return this project's budget. |
Response
{
"data": [
{
"id": "019abc12-3456-7890-abcd-ef1234567890",
"name": "Acme",
"parentId": null,
"scope": { "type": "organization", "projectBudgetsEnabled": true },
"funding": {
"amountCents": 5000000,
"spentCents": 1234500,
"remainingCents": 3765500,
"renewal": null
},
"onExhausted": "block",
"memberLimits": {
"enabled": true,
"defaultCents": 20000,
"period": "monthly",
"resetsAt": "2026-11-01T00:00:00.000Z"
}
},
{
"id": "019abc12-3456-7890-abcd-ef1234567891",
"name": "Downtown Office Tower",
"parentId": "019abc12-3456-7890-abcd-ef1234567890",
"scope": {
"type": "project",
"projectId": "019c587e-3456-7890-abcd-ef1234567890"
},
"funding": {
"amountCents": 100000,
"spentCents": 42000,
"remainingCents": 58000,
"renewal": { "cadence": "monthly", "amountCents": 100000 }
},
"onExhausted": "use_parent",
"memberLimits": {
"enabled": false,
"defaultCents": null,
"period": null,
"resetsAt": null
}
}
],
"nextCursor": null,
"totalCount": 2
}
| Field | Type | Description |
|---|---|---|
data[].id | uuid | Budget ID. |
data[].name | string | Project name for project budgets, else the budget name. |
data[].parentId | uuid? | Budget this one draws from, or null for the organization budget. |
data[].scope | object | { "type": "organization", "projectBudgetsEnabled": boolean } or { "type": "project", "projectId": uuid }. |
data[].funding.amountCents | number | Total granted to this budget, in US cents. The organization budget is funded by its contract. |
data[].funding.spentCents | number | Spent from this budget, in US cents. |
data[].funding.remainingCents | number | Left to spend, in US cents. Negative when overspent. |
data[].funding.renewal | object? | { "cadence": "weekly" | "monthly", "amountCents": number } — a repeating grant that refills the budget — or null. |
data[].onExhausted | block | use_parent | When the budget runs out, block stops spend and use_parent keeps spending from the parent budget. |
data[].memberLimits.enabled | boolean | Whether per-user limits apply on this budget. |
data[].memberLimits.defaultCents | number? | Limit for members without their own, in US cents. null means no default limit. |
data[].memberLimits.period | daily | weekly | monthly | null | Window each member limit resets on (UTC; weeks start Monday). null means the limit covers the whole contract. |
data[].memberLimits.resetsAt | string? | ISO-8601 end of the current window, or null when period is null. |
nextCursor | null | Always null. |
totalCount | number | Number of budgets returned. |
Errors
| Status | Cause |
|---|---|
400 | Invalid query parameters. |
401 | Missing or invalid API key. |
403 | API key lacks developer:budgets:read scope. |
429 | Standard rate limit exceeded. |
Example
curl "https://<your-domain>.nomic.ai/api/v0/budgets?scope=project" \
-H "Authorization: Bearer $NOMIC_API_KEY"
Get a budget
GET /budgets/{id}
Fetch a single budget. Pass organization as the ID for the organization
budget, which holds the organization-wide per-user limits.
Scope: developer:budgets:read · Rate limit: Standard (300 req / min)
Path parameters
| Parameter | Type | Description |
|---|---|---|
id | string (uuid or literal) | Budget ID, or organization for the organization budget. |
Response
Returns 200 OK with the budget under data, in the same shape as an item of
List budgets.
Errors
| Status | Cause |
|---|---|
401 | Missing or invalid API key. |
403 | API key lacks developer:budgets:read scope. |
404 | No budget with this ID that the caller administers. |
429 | Standard rate limit exceeded. |
Example
curl "https://<your-domain>.nomic.ai/api/v0/budgets/organization" \
-H "Authorization: Bearer $NOMIC_API_KEY"
List budget members
GET /budgets/{id}/members
List each member's own limit, the limit that applies to them, and their spend in the budget's current window, ordered by email. The organization budget covers every user in the organization; a project budget covers the project's members.
Scope: developer:budgets:read · Rate limit: Standard (300 req / min)
Path parameters
| Parameter | Type | Description |
|---|---|---|
id | string (uuid or literal) | Budget ID, or organization for the organization budget. |
Query parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
limit | int | 50 | Max results per page (1–100). |
cursor | string | — | Opaque cursor from a previous page's nextCursor. |
Response
{
"data": [
{
"id": "019abc12-3456-7890-abcd-ef1234567890",
"email": "alice@example.com",
"name": "Alice Johnson",
"limitCents": 50000,
"effectiveLimitCents": 50000,
"spentCents": 12340,
"status": "within_limit"
},
{
"id": "019abc12-3456-7890-abcd-ef1234567891",
"email": "bob@example.com",
"name": "Bob Lee",
"limitCents": null,
"effectiveLimitCents": 20000,
"spentCents": 20000,
"status": "limit_reached"
}
],
"nextCursor": null,
"totalCount": 2
}
| Field | Type | Description |
|---|---|---|
data[].id | uuid | User ID of the member. |
data[].email | string | Member email. |
data[].name | string? | Member display name, or null if unset. |
data[].limitCents | number? | The member's own limit in US cents, or null when they follow the budget's memberLimits.defaultCents. |
data[].effectiveLimitCents | number? | The limit that applies to the member, in US cents. null when member limits are off or neither an own limit nor a default is set. |
data[].spentCents | number | Spent in the budget's current limit window (see memberLimits.period), in US cents. |
data[].status | unlimited | within_limit | limit_reached | unlimited when no limit applies, limit_reached once spend in the current window has reached the limit, else within_limit. |
nextCursor | string? | Cursor for the next page, or null if none remain. |
totalCount | number | Total members of the budget. |
Errors
| Status | Cause |
|---|---|
401 | Missing or invalid API key. |
403 | API key lacks developer:budgets:read scope. |
404 | No budget with this ID that the caller administers. |
409 | A project budget while project budgets are turned off (project_budgets_disabled). |
429 | Standard rate limit exceeded. |
Example
curl "https://<your-domain>.nomic.ai/api/v0/budgets/organization/members?limit=100" \
-H "Authorization: Bearer $NOMIC_API_KEY"
Set budget member limits
POST /budgets/{id}/members
Set or clear per-user limits in one batch of 1–100 changes, applied atomically:
nothing is written unless every entry is valid. A limitCents of null clears
the member's own limit so the budget's default applies. Sending the same batch
twice changes nothing.
Member limits must be turned on for the budget, and every user must already be one of the budget's members; identify each by user ID or email. Changing limits on the organization budget requires the key owner to be an organization admin.
Scope: developer:budgets:write · Rate limit: Write (60 req / min)
Path parameters
| Parameter | Type | Description |
|---|---|---|
id | string (uuid or literal) | Budget ID, or organization for the organization budget. |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
members | array | Yes | 1–100 limit changes to apply as one batch. |
members[].user | string (uuid or email) | Yes | The member, by user ID or email address. |
members[].limitCents | integer (≥ 0) | null | Yes | The member's own limit in US cents, or null to clear it so the default applies. |
Response
Returns 200 OK with the changed members after the batch, ordered by email, in
the same shape as List budget members (without
pagination fields).
Errors
| Status | Cause |
|---|---|
400 | Validation error, or an unknown, repeated, or non-member user. |
401 | Missing or invalid API key. |
403 | API key lacks developer:budgets:write scope, or the organization budget and the key owner is not an organization admin. |
404 | No budget with this ID that the caller administers. |
409 | Member limits are off for this budget (member_limits_disabled), or project budgets are turned off (project_budgets_disabled). |
429 | Write rate limit exceeded. |
Example
Give Bob a $250 limit and put Carol back on the budget default:
curl -X POST "https://<your-domain>.nomic.ai/api/v0/budgets/organization/members" \
-H "Authorization: Bearer $NOMIC_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"members": [
{ "user": "bob@example.com", "limitCents": 25000 },
{ "user": "carol@example.com", "limitCents": null }
]
}'
Update a budget
POST /budgets/{id}
Change a budget's funding, overage behavior, renewal, or member limits. Send
only the fields you want to change; everything else keeps its current value.
Inside memberLimits, an omitted field is also left alone, while an explicit
null clears it. Sending the same body twice changes nothing.
The organization budget is funded by its contract, so only its memberLimits
can be changed, and only by an organization admin. When a project budget change
includes amountCents, the funding change and every other field are applied as
one step: if the parent budget can't cover the amount, nothing changes.
Scope: developer:budgets:write · Rate limit: Write (60 req / min)
Path parameters
| Parameter | Type | Description |
|---|---|---|
id | string (uuid or literal) | Budget ID, or organization for the organization budget. |
Request body
At least one field is required.
| Field | Type | Budgets | Description |
|---|---|---|---|
amountCents | integer (≥ 0) | Project | New funding level in US cents. Raising it draws from the parent budget; lowering it returns the difference. |
onExhausted | block | use_parent | Project | What happens when the budget runs out. |
renewal | object | null | Project | { "cadence": "weekly" | "monthly", "amountCents": number } to refill the budget each period, or null. |
memberLimits.enabled | boolean | Both | Turn per-user limits on or off. |
memberLimits.defaultCents | integer (≥ 0) | null | Both | Limit for members without their own, in US cents. 0 blocks them; null removes the default. |
memberLimits.period | daily | weekly | monthly | null | Both | Window each member limit resets on. null (limits cover the whole contract) is allowed only on the organization budget. |
Response
Returns 200 OK with the budget after the change under data, in the same
shape as an item of List budgets.
Errors
| Status | Cause |
|---|---|
400 | Validation error, amountCents, onExhausted, or renewal sent to the organization budget (organization_budget_contract_funded), or a project member limit without a period (invalid_budget_change). |
401 | Missing or invalid API key. |
403 | API key lacks developer:budgets:write scope, or the key owner cannot administer the budget or the parent budget it draws from. |
404 | No budget with this ID that the caller administers. |
409 | The parent budget cannot cover the new amount (insufficient_funds), or project budgets are turned off (project_budgets_disabled). |
429 | Write rate limit exceeded. |
Example
Make spend opt-in: block everyone without their own limit, then give Alice one with Set budget member limits.
curl -X POST "https://<your-domain>.nomic.ai/api/v0/budgets/organization" \
-H "Authorization: Bearer $NOMIC_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "memberLimits": { "enabled": true, "defaultCents": 0, "period": "monthly" } }'
curl -X POST "https://<your-domain>.nomic.ai/api/v0/budgets/organization/members" \
-H "Authorization: Bearer $NOMIC_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "members": [{ "user": "alice@example.com", "limitCents": 10000 }] }'
Create a project budget
POST /budgets
Give a project its own budget, funded from the organization budget. Funding,
onExhausted, renewal, and member limits are applied together: if the
organization budget can't cover amountCents, nothing is created. A project can
have only one budget; change it later with Update a budget.
Project budgets must be turned on for the organization. The key owner needs admin access to the project, and funding it also requires admin access to the organization budget.
Scope: developer:budgets:write · Rate limit: Write (60 req / min)
Request body
Takes projectId and amountCents, plus any field of
Update a budget. A project member limit always needs a
daily, weekly, or monthly period.
| Field | Type | Required | Description |
|---|---|---|---|
projectId | uuid | Yes | Project to fund. |
amountCents | integer (≥ 0) | Yes | Amount to move into the budget from the organization budget, in US cents. |
Response
Returns 201 Created with the new budget under data, in the same shape as an
item of List budgets.
Errors
| Status | Cause |
|---|---|
400 | Validation error, or a member limit without a period (invalid_budget_change). |
401 | Missing or invalid API key. |
403 | API key lacks developer:budgets:write scope, or the key owner cannot administer the project or the organization budget. |
404 | No project with this ID that the key owner can read. |
409 | The project already has a budget (budget_exists), the organization budget cannot cover the amount (insufficient_funds), or project budgets are turned off (project_budgets_disabled). |
429 | Write rate limit exceeded. |
Example
curl -X POST "https://<your-domain>.nomic.ai/api/v0/budgets" \
-H "Authorization: Bearer $NOMIC_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"projectId": "019c587e-3456-7890-abcd-ef1234567890",
"amountCents": 50000,
"onExhausted": "use_parent",
"renewal": { "cadence": "monthly", "amountCents": 50000 },
"memberLimits": { "enabled": true, "defaultCents": 5000, "period": "weekly" }
}'