Org Models
GET /api/orgs/{org_id}/feature-models
Section titled “GET /api/orgs/{org_id}/feature-models”List Org Feature Models
Every org-facing feature, in the platform admin’s own display order.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| org_id | path | string (uuid) | yes |
Responses
| Status | Description | Body |
|---|---|---|
| 200 | Successful Response | OrgFeatureModelResponse[] |
| 422 | Validation Error | HTTPValidationError |
PATCH /api/orgs/{org_id}/feature-models/{feature_id}
Section titled “PATCH /api/orgs/{org_id}/feature-models/{feature_id}”Set Org Feature Model
Set or clear this org’s override for one org-facing feature.
model: null clears it, and the feature falls back to the platform’s own
choice on the very next call — no cache to invalidate, matching
resolve_feature_model’s own reasoning for reading settings live.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| feature_id | path | string | yes | |
| org_id | path | string (uuid) | yes |
Request body (required)
| Field | Type | Required | Description |
|---|---|---|---|
| model | string | no |
Responses
| Status | Description | Body |
|---|---|---|
| 200 | Successful Response | OrgFeatureModelResponse |
| 422 | Validation Error | HTTPValidationError |
GET /api/orgs/{org_id}/model-offerings
Section titled “GET /api/orgs/{org_id}/model-offerings”List Org Offerings
This org’s own offerings, and how many more its plan allows.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| org_id | path | string (uuid) | yes |
Responses
| Status | Description | Body |
|---|---|---|
| 200 | Successful Response | OrgModelOfferingListResponse |
| 422 | Validation Error | HTTPValidationError |
POST /api/orgs/{org_id}/model-offerings
Section titled “POST /api/orgs/{org_id}/model-offerings”Create Org Offering
Offer a model on one of this org’s routes — the platform’s, or its own.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| org_id | path | string (uuid) | yes |
Request body (required)
| Field | Type | Required | Description |
|---|---|---|---|
| cache_write_price_per_1m | number | string | no | |
| cached_input_price_per_1m | number | string | no | |
| custom | CustomModelSpec | no | |
| enabled | boolean | no | |
| input_price_per_1m | number | string | no | |
| model_key | string | yes | |
| output_price_per_1m | number | string | no | |
| remote_model_id | string | no | |
| route_slug | string | yes |
Responses
| Status | Description | Body |
|---|---|---|
| 201 | Successful Response | OrgModelOfferingResponse |
| 422 | Validation Error | HTTPValidationError |
PATCH /api/orgs/{org_id}/model-offerings/{offering_id}
Section titled “PATCH /api/orgs/{org_id}/model-offerings/{offering_id}”Update Org Offering
Re-route, re-price or switch off one of this org’s offerings.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| offering_id | path | string (uuid) | yes | |
| org_id | path | string (uuid) | yes |
Request body (required)
| Field | Type | Required | Description |
|---|---|---|---|
| cache_write_price_per_1m | number | string | no | |
| cached_input_price_per_1m | number | string | no | |
| custom | CustomModelSpec | no | |
| enabled | boolean | no | |
| input_price_per_1m | number | string | no | |
| output_price_per_1m | number | string | no | |
| remote_model_id | string | no | |
| route_slug | string | no |
Responses
| Status | Description | Body |
|---|---|---|
| 200 | Successful Response | OrgModelOfferingResponse |
| 422 | Validation Error | HTTPValidationError |
DELETE /api/orgs/{org_id}/model-offerings/{offering_id}
Section titled “DELETE /api/orgs/{org_id}/model-offerings/{offering_id}”Delete Org Offering
Remove one of this org’s offerings.
The model itself is untouched — it is the platform’s, and agents pinned to it fall back to the platform’s offering on the next turn rather than losing the model.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| offering_id | path | string (uuid) | yes | |
| org_id | path | string (uuid) | yes |
Responses
| Status | Description | Body |
|---|---|---|
| 204 | Successful Response | |
| 422 | Validation Error | HTTPValidationError |
GET /api/orgs/{org_id}/model-offerings/{offering_id}/dependents
Section titled “GET /api/orgs/{org_id}/model-offerings/{offering_id}/dependents”List Offering Dependents
What in this org would stop working if this offering were removed.
Its own read rather than a field on the offering, because it is a question asked once — at the moment somebody clicks remove — and answering it on every list would put two extra queries per row behind a page that mostly does not need them.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| offering_id | path | string (uuid) | yes | |
| org_id | path | string (uuid) | yes |
Responses
| Status | Description | Body |
|---|---|---|
| 200 | Successful Response | OfferingDependentsResponse |
| 422 | Validation Error | HTTPValidationError |
POST /api/orgs/{org_id}/model-offerings/{offering_id}/test
Section titled “POST /api/orgs/{org_id}/model-offerings/{offering_id}/test”Test Org Offering
Actually call this offering’s endpoint and report what happened.
Everything else about a custom offering is declarative — the org states a URL, a dialect, a model id and a window, and nothing disagrees until an agent takes a turn and the turn fails inside a chat, days later, looking like a bad agent. This is the org asking directly, while they are still on the page that caused it.
A failed test is a 200. The request succeeded; the endpoint is what did not. Returning 4xx/5xx would make “your endpoint is down” indistinguishable from “your session expired” to every client that branches on status, and would throw away the per-step detail that is the entire value here.
The verdict is stored on the row (last_tested_at / last_test_ok) but
gates nothing: an endpoint that answered a minute ago can be down now, and
refusing dispatch on a remembered verdict would substitute a stale fact for
a live one.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| offering_id | path | string (uuid) | yes | |
| org_id | path | string (uuid) | yes |
Responses
| Status | Description | Body |
|---|---|---|
| 200 | Successful Response | OfferingTestResponse |
| 422 | Validation Error | HTTPValidationError |
GET /api/orgs/{org_id}/model-offerings/platform-rates
Section titled “GET /api/orgs/{org_id}/model-offerings/platform-rates”List Platform Model Rates
The platform’s own rates, keyed by (model, route) — what a blank inherits.
Declared above the /{offering_id} routes so a literal path segment is
never a candidate offering id.
Read from the platform’s uncollapsed catalog rows (org_id omitted on
purpose: the merged view would echo this org’s own offering back and call
its blank a platform rate). Chat rows only — an org neither picks nor
authors an embedding model, so there is no offering here to inherit one.
Gated on byo_keys as well as admin, unlike the list it accompanies.
These are the rates the platform pays providers. For an org that authors its
own offerings they are the rate its own calls bill at — a number it has to
be able to see, and the entitlement that lets dollars leave the API at all
(spend_context). For everyone else they are our cost basis and nothing
the org could act on, which is what the spend guard exists to keep in.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| org_id | path | string (uuid) | yes |
Responses
| Status | Description | Body |
|---|---|---|
| 200 | Successful Response | PlatformModelRateListResponse |
| 422 | Validation Error | HTTPValidationError |