API reference

v0.1.0 · 154 operations
Base URLhttps://api.opennozzle.com
AuthenticationAuthorization: Bearer pk_live_…Each operation names the scope it needs.
RetriesIdempotency-Key: <uuid>Required where marked; a retry replays, never repeats.
The error envelope every failure uses
errorobjectrequired
codestringrequired
Stable machine-readable code, e.g. `auth.missing_scope`, `request.invalid`, `upstream.rate_limited`.
detailsobject
Optional structured context — the offending parameter, the unsupported fields, the upstream's own error code.
messagestringrequired
Human-facing explanation.
request_idstring
UUIDv7 for this request; quote it in support requests.
trace_idstring
W3C trace id, for correlating across services.

Inference

17 operations
post/anthropic/v1/messages

Anthropic Messages API drop-in — translated to the one chat pipeline.

inference:call

Request body

object

Response · 200

object

curl -X POST https://api.opennozzle.com/anthropic/v1/messages \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'
post/v1/audio/speech

OpenAI-compatible text-to-speech. Audio bytes out; bills by estimated duration.

inference:call

Request body

object

Response · 200

object

curl -X POST https://api.opennozzle.com/v1/audio/speech \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'
post/v1/audio/transcriptions

OpenAI-compatible transcription (multipart). Bills by reported duration.

inference:call

Request body

object

Response · 200

object

curl -X POST https://api.opennozzle.com/v1/audio/transcriptions \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'
post/v1/audio/translations

OpenAI-compatible speech translation to English (multipart). Bills by reported duration.

inference:call

Request body

object

Response · 200

object

curl -X POST https://api.opennozzle.com/v1/audio/translations \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'
post/v1/chat/completions

OpenAI-compatible chat completion. Routes through model_registry.

inference:call

Request body

object

Response · 200

object

curl -X POST https://api.opennozzle.com/v1/chat/completions \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'
post/v1/classify

Classify inputs. Bills per classification.

inference:call

Request body

object

Response · 200

object

curl -X POST https://api.opennozzle.com/v1/classify \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'
post/v1/completions

OpenAI-compatible legacy text completion. Adapts onto the chat pipeline.

inference:call

Request body

object

Response · 200

object

curl -X POST https://api.opennozzle.com/v1/completions \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'
post/v1/embeddings

OpenAI-compatible embeddings. Routes through model_registry.

inference:call

Request body

object

Response · 200

object

curl -X POST https://api.opennozzle.com/v1/embeddings \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'
post/v1/images/edits

OpenAI-compatible image edits (multipart: reference images + prompt). gpt-image dialect only; bills from token usage.

inference:call

Request body

object

Response · 200

object

curl -X POST https://api.opennozzle.com/v1/images/edits \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'
post/v1/images/generations

OpenAI-compatible image generation. Bills per image at the quality-multiplied baseline, or from token usage on the gpt-image dialect.

inference:call

Request body

object

Response · 200

object

curl -X POST https://api.opennozzle.com/v1/images/generations \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'
get/v1/models

OpenAI-compatible model list — drop-in for OpenAI SDK clients.

catalog:read

Response · 200

dataOpenAiModel[]required
createdinteger · int64required
idstringrequired
objectstringrequired
owned_bystringrequired
objectstringrequired
curl -X GET https://api.opennozzle.com/v1/models \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s
get/v1/models/{id}

OpenAI-compatible model retrieve — one callable model by name.

catalog:read

Parameters

idpath · stringrequired

Response · 200

createdinteger · int64required
idstringrequired
objectstringrequired
owned_bystringrequired
curl -X GET https://api.opennozzle.com/v1/models/<id> \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s
get/v1/models/{id}/capabilities

Per-wire capability declaration for a model — the same truths the router refuses on.

catalog:read

Parameters

idpath · stringrequired

Response · 200

object

curl -X GET https://api.opennozzle.com/v1/models/<id>/capabilities \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s
get/v1/models/{id}/health

What this model's serving lane did last: healthy, degraded, dead or unknown, with the evidence.

catalog:read

Parameters

idpath · stringrequired

Response · 200

binding_idstring · uuidrequired
consecutive_failuresinteger · int32required
kindstringrequired
last_failure_atstring · date-time
last_failure_codestring
last_failure_statusinteger · int16
last_success_atstring · date-time
modelstringrequired
providerstring
statusstringrequired
curl -X GET https://api.opennozzle.com/v1/models/<id>/health \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s
post/v1/moderations

OpenAI-compatible content moderation. Flat per-call rate.

inference:call

Request body

object

Response · 200

object

curl -X POST https://api.opennozzle.com/v1/moderations \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'
post/v1/rerank

Rerank documents against a query. Bills in search units.

inference:call

Request body

object

Response · 200

object

curl -X POST https://api.opennozzle.com/v1/rerank \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'
post/v1/responses

OpenAI Responses API — reasoning items and function tools together, streamed as Responses events, billed like chat.

inference:call

Request body

object

Response · 200

object

curl -X POST https://api.opennozzle.com/v1/responses \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'

Models & catalog

8 operations
get/v1/catalog

Nested Model → Variants browse surface for the dashboard catalog page.

catalog:read

Response · 200

object

curl -X GET https://api.opennozzle.com/v1/catalog \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s
get/v1/catalog/health

Health of every platform-served model lane: healthy, degraded, dead or unknown. Public; no tenant data.

no auth

Response · 200

consecutive_failuresinteger · int32required
kindstringrequired
last_failure_atstring · date-time
last_failure_codestring
last_success_atstring · date-time
modelstringrequired
providerstring
statusstringrequired
curl -X GET https://api.opennozzle.com/v1/catalog/health \
  -s
get/v1/catalog/models

List the browsable catalog. Each row carries pricing, deployability, and what THIS caller resolves to: `bound`, `provider`, `upstream_model`, `kind` and `wire_capabilities` (the booleans `/v1/models/{id}/capabilities` answers). Optional query filters, all AND-ed: `provider`, `modality`, `q` (substring of id or display name), `min_context`, `max_input_cents_per_mtok`, `bound` (true|false), `deployability` (callable|launchable|blueprint_no_gpu|no_blueprint|all), `limit` (1-500, default 100), `offset`.

no auth

Response · 200

activebooleanrequired
boundbooleanrequired
Whether the caller can call this model right now: a global active binding, or a binding in the caller's own tenant. Unlike `active` (any tenant's binding counts) and `deployability.status == callable` (same), this is answered for the caller who asked.
capabilitiesstring[]required
context_windowinteger · int32
created_atstring · date-timerequired
deployabilityDeployabilityrequired
How (and whether) this model can be served — see [`Deployability`].
blueprintsstring[]required
Names of the Blueprints that can launch this model's family.
est_hourly_centsinteger · int64
Floor hourly cost of a self-hosted launch, integer cents. Present only when a Blueprint AND a priced GPU both exist.
gpu_requiredbooleanrequired
Whether serving this model needs a GPU launch (i.e. it has a Blueprint) versus being callable through an existing binding.
statusDeployabilityStatusrequired
Deployability tiers, in descending readiness. The wire strings are the `?deployability=` filter values.
display_namestringrequired
familystringrequired
hf_repostring
idstringrequired
kindstring
The binding kind — which inference surface serves it (`openai_chat`, `openai_embed`, `openai_transcription`, `openai_image`, …); `null` when `bound` is false.
licensestring
max_output_tokensinteger · int32
The most tokens one reply may carry, as the provider states it. `None` ⇒ unpublished; a consumer must not guess it.
modalitystringrequired
params_total_bnumber · double
pricingPricingrequired
The list price, every dimension the cost writer bills on. The three cache rates are published so a consumer that mirrors this catalog and estimates its own spend (Lighthouse does) prices a cache read and a cache write with the SAME numbers the ledger uses, instead of guessing a multiplier and drifting from the bill. Absent when the model has no such rate.
cache_creation_1hr_cents_per_mtoknumber · double
cache_creation_cents_per_mtoknumber · double
cached_input_cents_per_mtoknumber · double
currencystringrequired
input_cents_per_mtoknumber · double
output_cents_per_mtoknumber · double
providerstring
The upstream provider the caller's resolving binding routes to; `null` when `bound` is false.
updated_atstring · date-timerequired
upstream_modelstring
The model id on that provider's wire; `null` when `bound` is false.
wire_capabilitiesWireCapabilities | null
The parameter support the router enforces for the caller's resolving binding — the same booleans `GET /v1/models/{id}/capabilities` answers, computed the same way (wire family, narrowed by the provider row, the model's own profile and the binding kind). `null` when `bound` is false: there is no binding to answer for. Distinct from `capabilities`, which is the curated tag list a discovered model carries before any binding exists.
curl -X GET https://api.opennozzle.com/v1/catalog/models \
  -s
get/v1/catalog/models/{id}

Get a single catalog model by id (typed flat shape — legacy).

no auth

Parameters

idpath · stringrequired

Response · 200

activebooleanrequired
boundbooleanrequired
Whether the caller can call this model right now: a global active binding, or a binding in the caller's own tenant. Unlike `active` (any tenant's binding counts) and `deployability.status == callable` (same), this is answered for the caller who asked.
capabilitiesstring[]required
context_windowinteger · int32
created_atstring · date-timerequired
deployabilityDeployabilityrequired
How (and whether) this model can be served — see [`Deployability`].
blueprintsstring[]required
Names of the Blueprints that can launch this model's family.
est_hourly_centsinteger · int64
Floor hourly cost of a self-hosted launch, integer cents. Present only when a Blueprint AND a priced GPU both exist.
gpu_requiredbooleanrequired
Whether serving this model needs a GPU launch (i.e. it has a Blueprint) versus being callable through an existing binding.
statusDeployabilityStatusrequired
Deployability tiers, in descending readiness. The wire strings are the `?deployability=` filter values.
display_namestringrequired
familystringrequired
hf_repostring
idstringrequired
kindstring
The binding kind — which inference surface serves it (`openai_chat`, `openai_embed`, `openai_transcription`, `openai_image`, …); `null` when `bound` is false.
licensestring
max_output_tokensinteger · int32
The most tokens one reply may carry, as the provider states it. `None` ⇒ unpublished; a consumer must not guess it.
modalitystringrequired
params_total_bnumber · double
pricingPricingrequired
The list price, every dimension the cost writer bills on. The three cache rates are published so a consumer that mirrors this catalog and estimates its own spend (Lighthouse does) prices a cache read and a cache write with the SAME numbers the ledger uses, instead of guessing a multiplier and drifting from the bill. Absent when the model has no such rate.
cache_creation_1hr_cents_per_mtoknumber · double
cache_creation_cents_per_mtoknumber · double
cached_input_cents_per_mtoknumber · double
currencystringrequired
input_cents_per_mtoknumber · double
output_cents_per_mtoknumber · double
providerstring
The upstream provider the caller's resolving binding routes to; `null` when `bound` is false.
updated_atstring · date-timerequired
upstream_modelstring
The model id on that provider's wire; `null` when `bound` is false.
wire_capabilitiesWireCapabilities | null
The parameter support the router enforces for the caller's resolving binding — the same booleans `GET /v1/models/{id}/capabilities` answers, computed the same way (wire family, narrowed by the provider row, the model's own profile and the binding kind). `null` when `bound` is false: there is no binding to answer for. Distinct from `capabilities`, which is the curated tag list a discovered model carries before any binding exists.
curl -X GET https://api.opennozzle.com/v1/catalog/models/<id> \
  -s
post/v1/models

Register a model your project can call, served by a named provider.

catalog:readcatalog:writeIdempotency-Keyemits model.promoted

Request body

cents_per_audio_minutenumber · double
Cost per minute of audio, in cents — the unit an audio model bills in. Required for `modality: "audio"` unless the catalog already prices it.
input_cents_per_mtoknumber · double
Cost per million input tokens, in cents. Required only when the catalog does not already price this model under this provider, and only for a token-billed modality.
modalitystring
What the model serves, and therefore which surface it answers on: `text` (the default) for `/v1/chat/completions`, `embedding` for `/v1/embeddings`, `audio` for `/v1/audio/transcriptions`. The binding kind is derived from it by the same mapping a self-hosted pod uses, so there is one vocabulary for "what is this model", not two. One of `text`, `embedding`, `audio`. Sent as a string because the vocabulary belongs to the registry crate, which has no business deriving a JSON schema; an unknown value is refused by name.
namestringrequired
The name you will send in `{"model": "..."}`. Any string you like — an alias you invent, or an existing catalog name you are re-pointing at your own provider account.
output_cents_per_mtoknumber · double
Cost per million output tokens, in cents.
providerstringrequired
Which upstream serves it. Must be enabled; `GET /v1/providers` lists the ones available to you.
upstream_modelstringrequired
The provider's own name for the model. Routinely differs from `name` (`Qwen/Qwen3.8-27B` at DeepInfra vs `qwen3.8-27b` at Groq), which is exactly why both exist.

Response · 200

idstringrequired
modalitystringrequired
What it serves, echoed back so a client can see which surface to call.
namestringrequired
providerstringrequired
scopestringrequired
Always `"tenant"`. Stated rather than implied so a client can tell a model it registered from one the platform published.
upstream_modelstringrequired
curl -X POST https://api.opennozzle.com/v1/models \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "cents_per_audio_minute": null,
  "input_cents_per_mtok": null,
  "modality": null,
  "name": "string",
  "output_cents_per_mtok": null,
  "provider": "string",
  "upstream_model": "string"
}'
delete/v1/models/{id}

Stop serving a model you registered; platform models are unaffected.

catalog:readcatalog:writeIdempotency-Key

Parameters

idpath · stringrequired

Response · 204

Success. No response body.

curl -X DELETE https://api.opennozzle.com/v1/models/<id> \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -s
get/v1/providers

List providers you can register a model against.

catalog:read

Response · 200

credentialstringrequired
`"platform"` when Nozzle holds the credential and bills you for tokens; `"byok"` when you must supply your own via `POST /v1/byok/credentials`; `"self_hosted"` for pods we run.
namestringrequired
wire_familystringrequired
curl -X GET https://api.opennozzle.com/v1/providers \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s
get/v1/registrations

List the models you registered, as opposed to the platform catalog.

catalog:read

Response · 200

idstringrequired
modalitystringrequired
What it serves, echoed back so a client can see which surface to call.
namestringrequired
providerstringrequired
scopestringrequired
Always `"tenant"`. Stated rather than implied so a client can tell a model it registered from one the platform published.
upstream_modelstringrequired
curl -X GET https://api.opennozzle.com/v1/registrations \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s

API keys & service accounts

12 operations
get/v1/keys/{key_id}

Get a virtual key's metadata (no token returned).

keys:read

Parameters

key_idpath · stringrequired

Response · 200

created_atstring · date-timerequired
created_byUserId | null
environmentKeyEnvironmentrequired
expires_atstring · date-time
idVirtualKeyIdrequired
A customer-facing programmatic key (pk_live_* / pk_test_*).
last_used_atstring · date-time
namestringrequired
previewstringrequired
Suffix of the token (e.g. `…aB3xQ`) for UI identification.
project_idProjectIdrequired
Project within an organization — the unit virtual keys belong to.
rate_limit_rpminteger · uint32required
restrictionsKeyRestrictionsrequired
The restrictions a key carries beyond scopes and RPM. Enforced at the dispatch seam (`keys::enforce`) and, for `ip_allowlist`, at authentication; settable at mint and by PATCH.
blocked_modelsarray
Refused even when `models` admits them.
ip_allowlistarray
CIDR blocks (or bare addresses) this key may be used from.
model_access_groupsarray
Named model access groups; their models are added to `models`.
modelsarray
Models this key may call. `null` = every model the tenant reaches.
tpm_limitinteger · uint32
Tokens per minute, prompt + completion.
revoked_atstring · date-time
scopesScope[]required
service_account_idstring · uuid
spend_capSpendCap | null
The spend ceiling this key carries, or `null` when it is uncapped. Readable because it is settable: a cap you cannot see is a cap you cannot audit.
statusKeyStatusrequired
tenant_idTenantIdrequired
Top-level tenancy: an organization / customer.
curl -X GET https://api.opennozzle.com/v1/keys/<key_id> \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s
patch/v1/keys/{key_id}

Update a virtual key (name, scopes-reduction, rate limit, expiry).

keys:writeIdempotency-Keyemits virtual_key.updated

Parameters

key_idpath · stringrequired

Request body

expires_atstring · date-time
Setting to `None` clears the expiry (no-op for never-expiring keys).
namestring
rate_limit_rpminteger · uint32
restrictionsKeyRestrictions | null
Replace the key's restrictions wholesale. Omit to leave them; send `{}` (every field null) to lift them all. Whole-object rather than per-field so a console editing the restrictions form sends exactly what it shows, and "absent" never has to mean two things.
scopesarray
Reducing the scope set is allowed; expanding requires a remint.
spend_capSpendCap | null
The most this key may spend, over which window. Both halves arrive together because the type carries both: a ceiling with no window never enforces and a window with no ceiling means nothing, which is what the `virtual_keys_budget_coherent` CHECK says in the database. Omitting it leaves the existing cap alone, as every other field here does. Removing a cap is deliberately not expressible for the same reason clearing an expiry is not: one PATCH body cannot distinguish "absent" from "set to nothing" without a second nesting level, and a silent uncapping is the wrong thing to guess.

Response · 200

created_atstring · date-timerequired
created_byUserId | null
environmentKeyEnvironmentrequired
expires_atstring · date-time
idVirtualKeyIdrequired
A customer-facing programmatic key (pk_live_* / pk_test_*).
last_used_atstring · date-time
namestringrequired
previewstringrequired
Suffix of the token (e.g. `…aB3xQ`) for UI identification.
project_idProjectIdrequired
Project within an organization — the unit virtual keys belong to.
rate_limit_rpminteger · uint32required
restrictionsKeyRestrictionsrequired
The restrictions a key carries beyond scopes and RPM. Enforced at the dispatch seam (`keys::enforce`) and, for `ip_allowlist`, at authentication; settable at mint and by PATCH.
blocked_modelsarray
Refused even when `models` admits them.
ip_allowlistarray
CIDR blocks (or bare addresses) this key may be used from.
model_access_groupsarray
Named model access groups; their models are added to `models`.
modelsarray
Models this key may call. `null` = every model the tenant reaches.
tpm_limitinteger · uint32
Tokens per minute, prompt + completion.
revoked_atstring · date-time
scopesScope[]required
service_account_idstring · uuid
spend_capSpendCap | null
The spend ceiling this key carries, or `null` when it is uncapped. Readable because it is settable: a cap you cannot see is a cap you cannot audit.
statusKeyStatusrequired
tenant_idTenantIdrequired
Top-level tenancy: an organization / customer.
curl -X PATCH https://api.opennozzle.com/v1/keys/<key_id> \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "expires_at": "2026-09-22T12:00:00Z",
  "name": null,
  "rate_limit_rpm": null,
  "restrictions": null,
  "scopes": null,
  "spend_cap": null
}'
delete/v1/keys/{key_id}

Revoke a virtual key (immediate, no grace window).

keys:writeIdempotency-Keyemits virtual_key.revoked

Parameters

key_idpath · stringrequired

Response · 204

Success. No response body.

curl -X DELETE https://api.opennozzle.com/v1/keys/<key_id> \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -s
post/v1/keys/{key_id}/rotate

Rotate a virtual key, optionally with a grace window.

keys:writeIdempotency-Keyemits virtual_key.rotated

Parameters

key_idpath · stringrequired

Request body

grace_period_secondsinteger · uint32
Seconds during which the *old* token remains valid after rotation. Defaults to 0 (immediate cutover). Bounded by `MAX_ROTATION_GRACE_SECS`.

Response · 200

grace_expires_atstring · date-timerequired
When the previous token stops accepting requests.
keyVirtualKeyPublicrequired
created_atstring · date-timerequired
created_byUserId | null
environmentKeyEnvironmentrequired
expires_atstring · date-time
idVirtualKeyIdrequired
A customer-facing programmatic key (pk_live_* / pk_test_*).
last_used_atstring · date-time
namestringrequired
previewstringrequired
Suffix of the token (e.g. `…aB3xQ`) for UI identification.
project_idProjectIdrequired
Project within an organization — the unit virtual keys belong to.
rate_limit_rpminteger · uint32required
restrictionsKeyRestrictionsrequired
The restrictions a key carries beyond scopes and RPM. Enforced at the dispatch seam (`keys::enforce`) and, for `ip_allowlist`, at authentication; settable at mint and by PATCH.
blocked_modelsarray
Refused even when `models` admits them.
ip_allowlistarray
CIDR blocks (or bare addresses) this key may be used from.
model_access_groupsarray
Named model access groups; their models are added to `models`.
modelsarray
Models this key may call. `null` = every model the tenant reaches.
tpm_limitinteger · uint32
Tokens per minute, prompt + completion.
revoked_atstring · date-time
scopesScope[]required
service_account_idstring · uuid
spend_capSpendCap | null
The spend ceiling this key carries, or `null` when it is uncapped. Readable because it is settable: a cap you cannot see is a cap you cannot audit.
statusKeyStatusrequired
tenant_idTenantIdrequired
Top-level tenancy: an organization / customer.
tokenstringrequired
The new plaintext token. Display once.
curl -X POST https://api.opennozzle.com/v1/keys/<key_id>/rotate \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "grace_period_seconds": 0
}'
get/v1/organizations/{organization_id}/service-accounts

List service accounts in a organization.

keys:read

Parameters

organization_idpath · stringrequired

Response · 200

activebooleanrequired
created_atstring · date-timerequired
created_byUserId | null
descriptionstring
disabled_atstring · date-time
idstring · uuidrequired
max_scopesScope[]required
namestringrequired
organization_idOrganizationIdrequired
Organization within a tenant.
tenant_idTenantIdrequired
Top-level tenancy: an organization / customer.
curl -X GET https://api.opennozzle.com/v1/organizations/<organization_id>/service-accounts \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s
post/v1/organizations/{organization_id}/service-accounts

Create a service account (a non-human principal that owns keys).

keys:writeIdempotency-Keyemits service_account.created

Parameters

organization_idpath · stringrequired

Request body

descriptionstring
max_scopesScope[]required
The scope ceiling for every key this account mints.
namestringrequired

Response · 201

activebooleanrequired
created_atstring · date-timerequired
created_byUserId | null
descriptionstring
disabled_atstring · date-time
idstring · uuidrequired
max_scopesScope[]required
namestringrequired
organization_idOrganizationIdrequired
Organization within a tenant.
tenant_idTenantIdrequired
Top-level tenancy: an organization / customer.
curl -X POST https://api.opennozzle.com/v1/organizations/<organization_id>/service-accounts \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "description": null,
  "max_scopes": [
    "catalog:read"
  ],
  "name": "string"
}'
get/v1/projects/{project_id}/keys

List virtual keys for a project.

keys:read

Parameters

project_idpath · stringrequired

Response · 200

created_atstring · date-timerequired
created_byUserId | null
environmentKeyEnvironmentrequired
expires_atstring · date-time
idVirtualKeyIdrequired
A customer-facing programmatic key (pk_live_* / pk_test_*).
last_used_atstring · date-time
namestringrequired
previewstringrequired
Suffix of the token (e.g. `…aB3xQ`) for UI identification.
project_idProjectIdrequired
Project within an organization — the unit virtual keys belong to.
rate_limit_rpminteger · uint32required
restrictionsKeyRestrictionsrequired
The restrictions a key carries beyond scopes and RPM. Enforced at the dispatch seam (`keys::enforce`) and, for `ip_allowlist`, at authentication; settable at mint and by PATCH.
blocked_modelsarray
Refused even when `models` admits them.
ip_allowlistarray
CIDR blocks (or bare addresses) this key may be used from.
model_access_groupsarray
Named model access groups; their models are added to `models`.
modelsarray
Models this key may call. `null` = every model the tenant reaches.
tpm_limitinteger · uint32
Tokens per minute, prompt + completion.
revoked_atstring · date-time
scopesScope[]required
service_account_idstring · uuid
spend_capSpendCap | null
The spend ceiling this key carries, or `null` when it is uncapped. Readable because it is settable: a cap you cannot see is a cap you cannot audit.
statusKeyStatusrequired
tenant_idTenantIdrequired
Top-level tenancy: an organization / customer.
curl -X GET https://api.opennozzle.com/v1/projects/<project_id>/keys \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s
post/v1/projects/{project_id}/keys

Mint a new virtual API key in a project.

keys:writeIdempotency-Keyemits virtual_key.created

Parameters

project_idpath · stringrequired

Request body

environmentKeyEnvironmentrequired
expires_atstring · date-time
Optional absolute expiry. When `None`, the key never expires (revocation is the only way to disable it).
namestringrequired
rate_limit_rpminteger · uint32
Optional per-key override of the project's default rate limit. Bounded at the gateway-level configured maximum.
restrictionsKeyRestrictions | null
Model, throughput and network restrictions; omit for none.
scopesScope[]required
service_account_idstring · uuid
Mint the key FOR a service account in this project's organization. Its scopes are clipped to the account's ceiling, and the account is the owner of record (the minting human stays `created_by`).
spend_capSpendCap | null
A spend ceiling from birth; omit for uncapped.

Response · 201

keyVirtualKeyPublicrequired
created_atstring · date-timerequired
created_byUserId | null
environmentKeyEnvironmentrequired
expires_atstring · date-time
idVirtualKeyIdrequired
A customer-facing programmatic key (pk_live_* / pk_test_*).
last_used_atstring · date-time
namestringrequired
previewstringrequired
Suffix of the token (e.g. `…aB3xQ`) for UI identification.
project_idProjectIdrequired
Project within an organization — the unit virtual keys belong to.
rate_limit_rpminteger · uint32required
restrictionsKeyRestrictionsrequired
The restrictions a key carries beyond scopes and RPM. Enforced at the dispatch seam (`keys::enforce`) and, for `ip_allowlist`, at authentication; settable at mint and by PATCH.
blocked_modelsarray
Refused even when `models` admits them.
ip_allowlistarray
CIDR blocks (or bare addresses) this key may be used from.
model_access_groupsarray
Named model access groups; their models are added to `models`.
modelsarray
Models this key may call. `null` = every model the tenant reaches.
tpm_limitinteger · uint32
Tokens per minute, prompt + completion.
revoked_atstring · date-time
scopesScope[]required
service_account_idstring · uuid
spend_capSpendCap | null
The spend ceiling this key carries, or `null` when it is uncapped. Readable because it is settable: a cap you cannot see is a cap you cannot audit.
statusKeyStatusrequired
tenant_idTenantIdrequired
Top-level tenancy: an organization / customer.
tokenstringrequired
Full plaintext token. Display once; never returned again.
curl -X POST https://api.opennozzle.com/v1/projects/<project_id>/keys \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "environment": "live",
  "expires_at": null,
  "name": "string",
  "rate_limit_rpm": null,
  "restrictions": null,
  "scopes": [
    "catalog:read"
  ],
  "service_account_id": null,
  "spend_cap": null
}'
get/v1/service-accounts/{service_account_id}

Get a service account.

keys:read

Parameters

service_account_idpath · stringrequired

Response · 200

activebooleanrequired
created_atstring · date-timerequired
created_byUserId | null
descriptionstring
disabled_atstring · date-time
idstring · uuidrequired
max_scopesScope[]required
namestringrequired
organization_idOrganizationIdrequired
Organization within a tenant.
tenant_idTenantIdrequired
Top-level tenancy: an organization / customer.
curl -X GET https://api.opennozzle.com/v1/service-accounts/<service_account_id> \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s
patch/v1/service-accounts/{service_account_id}

Rename a service account, change its description, or narrow its scope ceiling.

keys:writeIdempotency-Keyemits service_account.updated

Parameters

service_account_idpath · stringrequired

Request body

descriptionstring
max_scopesarray
Narrow the ceiling. Must be a subset of the current one.
namestring

Response · 200

activebooleanrequired
created_atstring · date-timerequired
created_byUserId | null
descriptionstring
disabled_atstring · date-time
idstring · uuidrequired
max_scopesScope[]required
namestringrequired
organization_idOrganizationIdrequired
Organization within a tenant.
tenant_idTenantIdrequired
Top-level tenancy: an organization / customer.
curl -X PATCH https://api.opennozzle.com/v1/service-accounts/<service_account_id> \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "description": null,
  "max_scopes": null,
  "name": null
}'
delete/v1/service-accounts/{service_account_id}

Disable a service account (keys it owns keep their attribution).

keys:writeIdempotency-Keyemits service_account.disabled

Parameters

service_account_idpath · stringrequired

Response · 204

Success. No response body.

curl -X DELETE https://api.opennozzle.com/v1/service-accounts/<service_account_id> \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -s
get/v1/service-accounts/{service_account_id}/keys

List the keys a service account owns.

keys:read

Parameters

service_account_idpath · stringrequired

Response · 200

created_atstring · date-timerequired
created_byUserId | null
environmentKeyEnvironmentrequired
expires_atstring · date-time
idVirtualKeyIdrequired
A customer-facing programmatic key (pk_live_* / pk_test_*).
last_used_atstring · date-time
namestringrequired
previewstringrequired
Suffix of the token (e.g. `…aB3xQ`) for UI identification.
project_idProjectIdrequired
Project within an organization — the unit virtual keys belong to.
rate_limit_rpminteger · uint32required
restrictionsKeyRestrictionsrequired
The restrictions a key carries beyond scopes and RPM. Enforced at the dispatch seam (`keys::enforce`) and, for `ip_allowlist`, at authentication; settable at mint and by PATCH.
blocked_modelsarray
Refused even when `models` admits them.
ip_allowlistarray
CIDR blocks (or bare addresses) this key may be used from.
model_access_groupsarray
Named model access groups; their models are added to `models`.
modelsarray
Models this key may call. `null` = every model the tenant reaches.
tpm_limitinteger · uint32
Tokens per minute, prompt + completion.
revoked_atstring · date-time
scopesScope[]required
service_account_idstring · uuid
spend_capSpendCap | null
The spend ceiling this key carries, or `null` when it is uncapped. Readable because it is settable: a cap you cannot see is a cap you cannot audit.
statusKeyStatusrequired
tenant_idTenantIdrequired
Top-level tenancy: an organization / customer.
curl -X GET https://api.opennozzle.com/v1/service-accounts/<service_account_id>/keys \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s

Billing & costs

15 operations
get/v1/billing/balance

Read your own prepaid credit balance.

billing:read

Response · 200

balance_centsinteger · int64required
currencystringrequired
tenant_idTenantIdrequired
Top-level tenancy: an organization / customer.
curl -X GET https://api.opennozzle.com/v1/billing/balance \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s
get/v1/billing/costs

Page through your own cost ledger, newest first, with filters.

billing:read

Parameters

cursorquery · string
Opaque cursor from a previous page's `X-Nozzle-Next-Cursor` header.
fromquery · date-time
Inclusive lower bound on `occurred_at` (RFC 3339).
key_idquery · uuid
Virtual key that incurred the cost.
kindquery · string
Ledger kind, e.g. `inference.chat`, `inference.embed`, `instance_tick`.
limitquery · uint32
Rows per page, 1–1000. Default 200, the size this route always answered.
modelquery · string
Model the row was billed for.
project_idquery · uuid
Project the cost was attributed to.
providerquery · string
Provider that served the call (rows written from 2026-09-22 on).
toquery · date-time
Exclusive upper bound on `occurred_at` (RFC 3339).

Response · 200

cached_tokensinteger · int64
completion_tokensinteger · int64
cost_centsinteger · int64required
Whole cents, rounded once at the edge. Kept because it shipped; a typical inference call is well under one cent and reads `0` here, so reconcile on `cost_micro_cents`.
cost_micro_centsinteger · int64required
The exact figure — the same integer the `X-Nozzle-Cost-Micro-Cents` response header carried for `request_id`.
currencystringrequired
estimatedbooleanrequired
`true` when the token counts were counted locally because the upstream returned no usage block; the amount is then an estimate.
idstring · uuidrequired
kindstringrequired
occurred_atstring · date-timerequired
project_idProjectId | null
prompt_tokensinteger · int64
providerstring
The provider that served the call — the same value the call's `X-Nozzle-Provider` header carried. `null` on rows written before 2026-09-22 and on charges no provider served.
ref_idstring
ref_typestring
request_idstring
The `X-Request-Id` of the call that produced this row; `null` on rows that are not one call (a GPU-hour tick).
tenant_idTenantIdrequired
Top-level tenancy: an organization / customer.
virtual_key_idstring · uuid
The virtual key that incurred this cost; `null` for dashboard-session calls and for charges no caller made (a GPU-hour tick).
X-Nozzle-Next-Cursor
Opaque cursor for the next page; send it back as `cursor`. Absent on the last page.
curl -X GET https://api.opennozzle.com/v1/billing/costs \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s
get/v1/billing/costs/{request_id}

What one of your calls cost, by its X-Request-Id.

billing:read

Parameters

request_idpath · stringrequired

Response · 200

cached_tokensinteger · int64
completion_tokensinteger · int64
cost_centsinteger · int64required
Whole cents, rounded once at the edge. Kept because it shipped; a typical inference call is well under one cent and reads `0` here, so reconcile on `cost_micro_cents`.
cost_micro_centsinteger · int64required
The exact figure — the same integer the `X-Nozzle-Cost-Micro-Cents` response header carried for `request_id`.
currencystringrequired
estimatedbooleanrequired
`true` when the token counts were counted locally because the upstream returned no usage block; the amount is then an estimate.
idstring · uuidrequired
kindstringrequired
occurred_atstring · date-timerequired
project_idProjectId | null
prompt_tokensinteger · int64
providerstring
The provider that served the call — the same value the call's `X-Nozzle-Provider` header carried. `null` on rows written before 2026-09-22 and on charges no provider served.
ref_idstring
ref_typestring
request_idstring
The `X-Request-Id` of the call that produced this row; `null` on rows that are not one call (a GPU-hour tick).
tenant_idTenantIdrequired
Top-level tenancy: an organization / customer.
virtual_key_idstring · uuid
The virtual key that incurred this cost; `null` for dashboard-session calls and for charges no caller made (a GPU-hour tick).
curl -X GET https://api.opennozzle.com/v1/billing/costs/<request_id> \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s
get/v1/billing/credits

List your own credit ledger entries.

billing:read

Response · 200

has_morebooleanrequired
itemsCreditEntryPublic[]required
currencystringrequired
delta_centsinteger · int64required
idstring · uuidrequired
occurred_atstring · date-timerequired
reasonstringrequired
ref_idstring
ref_typestring
tenant_idTenantIdrequired
Top-level tenancy: an organization / customer.
next_cursorstring
curl -X GET https://api.opennozzle.com/v1/billing/credits \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s
get/v1/billing/entitlement

Read your own plan entitlement.

billing:read

Response · 200

custom_overridesobjectrequired
planPlanrequired
activebooleanrequired
created_atstring · date-timerequired
currencystringrequired
featuresobjectrequired
idstringrequired
max_concurrent_instancesinteger · int32required
max_model_params_bnumber · doublerequired
monthly_credits_centsinteger · int64required
namestringrequired
per_day_limitinteger · int32
per_minute_limitinteger · int32
G13 — burst protection ceilings. `None` means "unlimited" (the `effective_ceiling` short-circuit returns Some(v) from the custom_override JSON before falling through to these, so the operator can still tighten an enterprise tenant via override). Stock plans seed values per tier in migration 0014b.
price_cents_monthlyinteger · int64required
tenant_idTenantIdrequired
Top-level tenancy: an organization / customer.
valid_fromstring · date-timerequired
valid_tostring · date-time
curl -X GET https://api.opennozzle.com/v1/billing/entitlement \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s
get/v1/billing/plans

List available billing plans.

no auth

Response · 200

activebooleanrequired
created_atstring · date-timerequired
currencystringrequired
featuresobjectrequired
idstringrequired
max_concurrent_instancesinteger · int32required
max_model_params_bnumber · doublerequired
monthly_credits_centsinteger · int64required
namestringrequired
per_day_limitinteger · int32
per_minute_limitinteger · int32
G13 — burst protection ceilings. `None` means "unlimited" (the `effective_ceiling` short-circuit returns Some(v) from the custom_override JSON before falling through to these, so the operator can still tighten an enterprise tenant via override). Stock plans seed values per tier in migration 0014b.
price_cents_monthlyinteger · int64required
curl -X GET https://api.opennozzle.com/v1/billing/plans \
  -s
post/v1/billing/reconcile

Re-apply recent Stripe events to the credit ledger (idempotent).

admin:billing:manageIdempotency-Key

Request body

object

Response · 200

object

curl -X POST https://api.opennozzle.com/v1/billing/reconcile \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{}'
get/v1/tenants/{tenant_id}/billing/balance

Current credit balance for the tenant.

billing:read

Parameters

tenant_idpath · stringrequired

Response · 200

balance_centsinteger · int64required
currencystringrequired
tenant_idTenantIdrequired
Top-level tenancy: an organization / customer.
curl -X GET https://api.opennozzle.com/v1/tenants/<tenant_id>/billing/balance \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s
post/v1/tenants/{tenant_id}/billing/checkout

Open a Stripe Checkout session for a plan.

billing:writeIdempotency-Key

Parameters

tenant_idpath · stringrequired

Request body

cancel_urlstringrequired
plan_idstringrequired
success_urlstringrequired

Response · 200

session_urlstringrequired
curl -X POST https://api.opennozzle.com/v1/tenants/<tenant_id>/billing/checkout \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "cancel_url": "string",
  "plan_id": "string",
  "success_url": "string"
}'
get/v1/tenants/{tenant_id}/billing/costs

Page through the tenant's cost ledger, newest first, with filters.

billing:read

Parameters

tenant_idpath · stringrequired
cursorquery · string
Opaque cursor from a previous page's `X-Nozzle-Next-Cursor` header.
fromquery · date-time
Inclusive lower bound on `occurred_at` (RFC 3339).
key_idquery · uuid
Virtual key that incurred the cost.
kindquery · string
Ledger kind, e.g. `inference.chat`, `inference.embed`, `instance_tick`.
limitquery · uint32
Rows per page, 1–1000. Default 200, the size this route always answered.
modelquery · string
Model the row was billed for.
project_idquery · uuid
Project the cost was attributed to.
providerquery · string
Provider that served the call (rows written from 2026-09-22 on).
toquery · date-time
Exclusive upper bound on `occurred_at` (RFC 3339).

Response · 200

cached_tokensinteger · int64
completion_tokensinteger · int64
cost_centsinteger · int64required
Whole cents, rounded once at the edge. Kept because it shipped; a typical inference call is well under one cent and reads `0` here, so reconcile on `cost_micro_cents`.
cost_micro_centsinteger · int64required
The exact figure — the same integer the `X-Nozzle-Cost-Micro-Cents` response header carried for `request_id`.
currencystringrequired
estimatedbooleanrequired
`true` when the token counts were counted locally because the upstream returned no usage block; the amount is then an estimate.
idstring · uuidrequired
kindstringrequired
occurred_atstring · date-timerequired
project_idProjectId | null
prompt_tokensinteger · int64
providerstring
The provider that served the call — the same value the call's `X-Nozzle-Provider` header carried. `null` on rows written before 2026-09-22 and on charges no provider served.
ref_idstring
ref_typestring
request_idstring
The `X-Request-Id` of the call that produced this row; `null` on rows that are not one call (a GPU-hour tick).
tenant_idTenantIdrequired
Top-level tenancy: an organization / customer.
virtual_key_idstring · uuid
The virtual key that incurred this cost; `null` for dashboard-session calls and for charges no caller made (a GPU-hour tick).
X-Nozzle-Next-Cursor
Opaque cursor for the next page; send it back as `cursor`. Absent on the last page.
curl -X GET https://api.opennozzle.com/v1/tenants/<tenant_id>/billing/costs \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s
get/v1/tenants/{tenant_id}/billing/costs/{request_id}

Every ledger row one call produced, by its X-Request-Id.

billing:read

Parameters

tenant_idpath · stringrequired
request_idpath · stringrequired

Response · 200

cached_tokensinteger · int64
completion_tokensinteger · int64
cost_centsinteger · int64required
Whole cents, rounded once at the edge. Kept because it shipped; a typical inference call is well under one cent and reads `0` here, so reconcile on `cost_micro_cents`.
cost_micro_centsinteger · int64required
The exact figure — the same integer the `X-Nozzle-Cost-Micro-Cents` response header carried for `request_id`.
currencystringrequired
estimatedbooleanrequired
`true` when the token counts were counted locally because the upstream returned no usage block; the amount is then an estimate.
idstring · uuidrequired
kindstringrequired
occurred_atstring · date-timerequired
project_idProjectId | null
prompt_tokensinteger · int64
providerstring
The provider that served the call — the same value the call's `X-Nozzle-Provider` header carried. `null` on rows written before 2026-09-22 and on charges no provider served.
ref_idstring
ref_typestring
request_idstring
The `X-Request-Id` of the call that produced this row; `null` on rows that are not one call (a GPU-hour tick).
tenant_idTenantIdrequired
Top-level tenancy: an organization / customer.
virtual_key_idstring · uuid
The virtual key that incurred this cost; `null` for dashboard-session calls and for charges no caller made (a GPU-hour tick).
curl -X GET https://api.opennozzle.com/v1/tenants/<tenant_id>/billing/costs/<request_id> \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s
get/v1/tenants/{tenant_id}/billing/credits

Paginated credits ledger for the tenant.

billing:read

Parameters

tenant_idpath · stringrequired

Response · 200

has_morebooleanrequired
itemsCreditEntryPublic[]required
currencystringrequired
delta_centsinteger · int64required
idstring · uuidrequired
occurred_atstring · date-timerequired
reasonstringrequired
ref_idstring
ref_typestring
tenant_idTenantIdrequired
Top-level tenancy: an organization / customer.
next_cursorstring
curl -X GET https://api.opennozzle.com/v1/tenants/<tenant_id>/billing/credits \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s
get/v1/tenants/{tenant_id}/billing/entitlement

Get the tenant's active entitlement (plan + overrides).

billing:read

Parameters

tenant_idpath · stringrequired

Response · 200

custom_overridesobjectrequired
planPlanrequired
activebooleanrequired
created_atstring · date-timerequired
currencystringrequired
featuresobjectrequired
idstringrequired
max_concurrent_instancesinteger · int32required
max_model_params_bnumber · doublerequired
monthly_credits_centsinteger · int64required
namestringrequired
per_day_limitinteger · int32
per_minute_limitinteger · int32
G13 — burst protection ceilings. `None` means "unlimited" (the `effective_ceiling` short-circuit returns Some(v) from the custom_override JSON before falling through to these, so the operator can still tighten an enterprise tenant via override). Stock plans seed values per tier in migration 0014b.
price_cents_monthlyinteger · int64required
tenant_idTenantIdrequired
Top-level tenancy: an organization / customer.
valid_fromstring · date-timerequired
valid_tostring · date-time
curl -X GET https://api.opennozzle.com/v1/tenants/<tenant_id>/billing/entitlement \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s
post/v1/tenants/{tenant_id}/billing/entitlement/change-plan

Switch the tenant to a different plan.

billing:writeIdempotency-Key

Parameters

tenant_idpath · stringrequired

Request body

plan_idstringrequired

Response · 200

custom_overridesobjectrequired
planPlanrequired
activebooleanrequired
created_atstring · date-timerequired
currencystringrequired
featuresobjectrequired
idstringrequired
max_concurrent_instancesinteger · int32required
max_model_params_bnumber · doublerequired
monthly_credits_centsinteger · int64required
namestringrequired
per_day_limitinteger · int32
per_minute_limitinteger · int32
G13 — burst protection ceilings. `None` means "unlimited" (the `effective_ceiling` short-circuit returns Some(v) from the custom_override JSON before falling through to these, so the operator can still tighten an enterprise tenant via override). Stock plans seed values per tier in migration 0014b.
price_cents_monthlyinteger · int64required
tenant_idTenantIdrequired
Top-level tenancy: an organization / customer.
valid_fromstring · date-timerequired
valid_tostring · date-time
curl -X POST https://api.opennozzle.com/v1/tenants/<tenant_id>/billing/entitlement/change-plan \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "plan_id": "string"
}'

Quotas

2 operations
get/v1/quotas

Read your own quota usage and ceilings.

billing:read

Response · 200

plan_idstringrequired
slotsQuotaSlot[]required
ceilinginteger · int64
The ceiling in `unit`. `null` when — and only when — `unlimited`.
enforcedbooleanrequired
`true` when at least one declared operation enforces this kind. A kind no route declares is reported, not hidden, and this says it is inert.
kindstringrequired
measureQuotaMeasurerequired
What `value` measures. A spend is summed from the ledger, a gauge is counted live, a counter is incremented per event, and `ceiling_only` says the kind bounds a request property rather than accumulating anything — its `value` is always zero and is not a measurement.
period_keystringrequired
sourcestringrequired
The table or gauge `value` is read from — the same one the enforcer reads, by construction.
unitQuotaUnitrequired
The unit a slot's `value` and `ceiling` are BOTH denominated in. Stated on the wire because the 2026-09-19 digest compared a request count against a cents ceiling inside one slot; a reader could not tell. A slot now carries one unit and both numbers are in it.
unlimitedbooleanrequired
`true` when no ceiling applies (plan column NULL or an explicit `null` override). Stated rather than left to be inferred from a null `ceiling`, so "unlimited" and "unknown" can never be confused.
updated_atstring · date-timerequired
valueinteger · int64required
Current usage in `unit`. Zero and not a measurement when `measure` is `ceiling_only`.
tenant_idstring · uuidrequired
curl -X GET https://api.opennozzle.com/v1/quotas \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s
get/v1/tenants/{tenant_id}/quotas

Read the tenant's current quota usage and ceilings.

billing:read

Parameters

tenant_idpath · stringrequired

Response · 200

plan_idstringrequired
slotsQuotaSlot[]required
ceilinginteger · int64
The ceiling in `unit`. `null` when — and only when — `unlimited`.
enforcedbooleanrequired
`true` when at least one declared operation enforces this kind. A kind no route declares is reported, not hidden, and this says it is inert.
kindstringrequired
measureQuotaMeasurerequired
What `value` measures. A spend is summed from the ledger, a gauge is counted live, a counter is incremented per event, and `ceiling_only` says the kind bounds a request property rather than accumulating anything — its `value` is always zero and is not a measurement.
period_keystringrequired
sourcestringrequired
The table or gauge `value` is read from — the same one the enforcer reads, by construction.
unitQuotaUnitrequired
The unit a slot's `value` and `ceiling` are BOTH denominated in. Stated on the wire because the 2026-09-19 digest compared a request count against a cents ceiling inside one slot; a reader could not tell. A slot now carries one unit and both numbers are in it.
unlimitedbooleanrequired
`true` when no ceiling applies (plan column NULL or an explicit `null` override). Stated rather than left to be inferred from a null `ceiling`, so "unlimited" and "unknown" can never be confused.
updated_atstring · date-timerequired
valueinteger · int64required
Current usage in `unit`. Zero and not a measurement when `measure` is `ceiling_only`.
tenant_idstring · uuidrequired
curl -X GET https://api.opennozzle.com/v1/tenants/<tenant_id>/quotas \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s

Analytics

6 operations
get/v1/analytics/cost

Your own cost per day.

usage:read

Response · 200

object

curl -X GET https://api.opennozzle.com/v1/analytics/cost \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s
get/v1/analytics/instances

Your own instance lifetime rollups.

usage:read

Response · 200

object

curl -X GET https://api.opennozzle.com/v1/analytics/instances \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s
get/v1/analytics/margin

Your own margin per day.

usage:read

Response · 200

object

curl -X GET https://api.opennozzle.com/v1/analytics/margin \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s
get/v1/tenants/{tenant_id}/analytics/cost

Daily cost breakdown (inference / instance / training) for a tenant.

usage:read

Parameters

tenant_idpath · stringrequired

Response · 200

object

curl -X GET https://api.opennozzle.com/v1/tenants/<tenant_id>/analytics/cost \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s
get/v1/tenants/{tenant_id}/analytics/instances

Per-Instance lifetime and spend for a tenant.

usage:read

Parameters

tenant_idpath · stringrequired

Response · 200

object

curl -X GET https://api.opennozzle.com/v1/tenants/<tenant_id>/analytics/instances \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s
get/v1/tenants/{tenant_id}/analytics/margin

Daily inference-versus-compute margin series for a tenant.

usage:read

Parameters

tenant_idpath · stringrequired

Response · 200

object

curl -X GET https://api.opennozzle.com/v1/tenants/<tenant_id>/analytics/margin \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s

Playground

7 operations
get/v1/playground/prompts

List saved playground prompts, newest edit first. Filters: project_id, mode, limit.

inference:call

Response · 200

bodyobjectrequired
The request exactly as the playground would send it (messages, parameters, the model list for a compare).
created_atstring · date-timerequired
created_by_user_idstring · uuid
idstring · uuidrequired
modePlaygroundModerequired
The console surface a prompt or run belongs to. Closed so the console can branch on it and the database CHECK can mirror it exactly.
modelstring
namestringrequired
project_idstring · uuid
updated_atstring · date-timerequired
curl -X GET https://api.opennozzle.com/v1/playground/prompts \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s
post/v1/playground/prompts

Save a playground prompt (the request body as the playground would send it).

inference:callIdempotency-Key

Request body

bodyobjectrequired
modePlaygroundModerequired
The console surface a prompt or run belongs to. Closed so the console can branch on it and the database CHECK can mirror it exactly.
modelstring
namestringrequired
project_idstring · uuid

Response · 201

bodyobjectrequired
The request exactly as the playground would send it (messages, parameters, the model list for a compare).
created_atstring · date-timerequired
created_by_user_idstring · uuid
idstring · uuidrequired
modePlaygroundModerequired
The console surface a prompt or run belongs to. Closed so the console can branch on it and the database CHECK can mirror it exactly.
modelstring
namestringrequired
project_idstring · uuid
updated_atstring · date-timerequired
curl -X POST https://api.opennozzle.com/v1/playground/prompts \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "body": {},
  "mode": "chat",
  "model": null,
  "name": "string",
  "project_id": null
}'
get/v1/playground/prompts/{id}

Read one saved playground prompt.

inference:call

Parameters

idpath · stringrequired

Response · 200

bodyobjectrequired
The request exactly as the playground would send it (messages, parameters, the model list for a compare).
created_atstring · date-timerequired
created_by_user_idstring · uuid
idstring · uuidrequired
modePlaygroundModerequired
The console surface a prompt or run belongs to. Closed so the console can branch on it and the database CHECK can mirror it exactly.
modelstring
namestringrequired
project_idstring · uuid
updated_atstring · date-timerequired
curl -X GET https://api.opennozzle.com/v1/playground/prompts/<id> \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s
patch/v1/playground/prompts/{id}

Rename a saved prompt or replace its model or body.

inference:callIdempotency-Key

Parameters

idpath · stringrequired

Request body

bodyobject
modelstring
namestring

Response · 200

bodyobjectrequired
The request exactly as the playground would send it (messages, parameters, the model list for a compare).
created_atstring · date-timerequired
created_by_user_idstring · uuid
idstring · uuidrequired
modePlaygroundModerequired
The console surface a prompt or run belongs to. Closed so the console can branch on it and the database CHECK can mirror it exactly.
modelstring
namestringrequired
project_idstring · uuid
updated_atstring · date-timerequired
curl -X PATCH https://api.opennozzle.com/v1/playground/prompts/<id> \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "body": null,
  "model": null,
  "name": null
}'
delete/v1/playground/prompts/{id}

Delete a saved playground prompt; runs that used it keep their record.

inference:callIdempotency-Key

Parameters

idpath · stringrequired

Response · 204

Success. No response body.

curl -X DELETE https://api.opennozzle.com/v1/playground/prompts/<id> \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -s
get/v1/playground/runs

List playground runs, newest first. Filters: project_id, mode, limit, before (keyset).

inference:call

Response · 200

created_atstring · date-timerequired
created_by_user_idstring · uuid
idstring · uuidrequired
modePlaygroundModerequired
The console surface a prompt or run belongs to. Closed so the console can branch on it and the database CHECK can mirror it exactly.
outcomesRunOutcome[]required
cost_micro_centsinteger · int64
error_codestring
first_token_msinteger · uint64
latency_msinteger · uint64
modelstringrequired
previewstring
The first few hundred characters of the answer, for the history list.
request_idstring
winnerboolean
project_idstring · uuid
prompt_idstring · uuid
requestobjectrequired
curl -X GET https://api.opennozzle.com/v1/playground/runs \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s
post/v1/playground/runs

Record a playground run: the request and what each model returned, keyed by request id.

inference:callIdempotency-Key

Request body

modePlaygroundModerequired
The console surface a prompt or run belongs to. Closed so the console can branch on it and the database CHECK can mirror it exactly.
outcomesRunOutcome[]required
cost_micro_centsinteger · int64
error_codestring
first_token_msinteger · uint64
latency_msinteger · uint64
modelstringrequired
previewstring
The first few hundred characters of the answer, for the history list.
request_idstring
winnerboolean
project_idstring · uuid
prompt_idstring · uuid
requestobjectrequired

Response · 200

created_atstring · date-timerequired
created_by_user_idstring · uuid
idstring · uuidrequired
modePlaygroundModerequired
The console surface a prompt or run belongs to. Closed so the console can branch on it and the database CHECK can mirror it exactly.
outcomesRunOutcome[]required
cost_micro_centsinteger · int64
error_codestring
first_token_msinteger · uint64
latency_msinteger · uint64
modelstringrequired
previewstring
The first few hundred characters of the answer, for the history list.
request_idstring
winnerboolean
project_idstring · uuid
prompt_idstring · uuid
requestobjectrequired
curl -X POST https://api.opennozzle.com/v1/playground/runs \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "mode": "chat",
  "outcomes": [
    {
      "model": "string"
    }
  ],
  "project_id": null,
  "prompt_id": null,
  "request": {}
}'

Compute

11 operations
get/v1/blueprints

List the deployable Blueprints and the hardware each requires.

catalog:read

Response · 200

object

curl -X GET https://api.opennozzle.com/v1/blueprints \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s
get/v1/blueprints/{name}

Read one deployable Blueprint by name.

catalog:read

Parameters

namepath · stringrequired

Response · 200

object

curl -X GET https://api.opennozzle.com/v1/blueprints/<name> \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s
get/v1/gpu-offerings

List purchasable GPU configurations with last-scraped hourly pricing.

catalog:read

Response · 200

object

curl -X GET https://api.opennozzle.com/v1/gpu-offerings \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s
get/v1/instances

List the caller's compute Instances.

instances:read

Response · 200

object

curl -X GET https://api.opennozzle.com/v1/instances \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s
post/v1/instances

Enqueue a new compute Instance launch.

instances:writeIdempotency-Keyemits instance.create_requested

Request body

object

Response · 201

object

curl -X POST https://api.opennozzle.com/v1/instances \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{}'
get/v1/instances/{id}

Read one compute Instance.

instances:read

Parameters

idpath · stringrequired

Response · 200

object

curl -X GET https://api.opennozzle.com/v1/instances/<id> \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s
delete/v1/instances/{id}

Hard terminate a compute Instance (no drain).

instances:writeIdempotency-Keyemits instance.terminate_requested

Parameters

idpath · stringrequired

Request body

object

Response · 200

object

curl -X DELETE https://api.opennozzle.com/v1/instances/<id> \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{}'
get/v1/instances/{id}/diagnostics

Get typed diagnostic envelope for a compute Instance.

instances:read

Parameters

idpath · stringrequired

Response · 200

object

curl -X GET https://api.opennozzle.com/v1/instances/<id>/diagnostics \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s
get/v1/instances/{id}/logs

Get the launch/lifecycle log timeline for a compute Instance.

instances:read

Parameters

idpath · stringrequired

Response · 200

object

curl -X GET https://api.opennozzle.com/v1/instances/<id>/logs \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s
post/v1/instances/{id}/stop

Graceful drain → stop on a running Instance.

instances:writeIdempotency-Keyemits instance.stop_requested

Parameters

idpath · stringrequired

Request body

object

Response · 200

object

curl -X POST https://api.opennozzle.com/v1/instances/<id>/stop \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{}'
get/v1/launch-estimate

Hourly cost and measured cold-start for a Blueprint on a given GPU.

catalog:read

Response · 200

object

curl -X GET https://api.opennozzle.com/v1/launch-estimate \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s

Workspaces, orgs & projects

23 operations
delete/v1/invitations/{invitation_id}

Revoke a pending invitation.

tenancy:writeIdempotency-Keyemits invitation.revoked

Parameters

invitation_idpath · stringrequired

Response · 204

Success. No response body.

curl -X DELETE https://api.opennozzle.com/v1/invitations/<invitation_id> \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -s
post/v1/invitations/accept

Accept an invitation token and join the target organization.

identity:writeIdempotency-Keyemits invitation.accepted

Request body

tokenstringrequired

Response · 200

avatar_urlstring
display_namestring
emailstring
The person, on the members list. Absent where a membership is returned on its own (accepting an invitation).
joined_atstring · date-timerequired
organization_idOrganizationIdrequired
Organization within a tenant.
roleRolerequired
Organization member role. Ordered by privilege: `Owner` ≥ `Admin` ≥ `Developer` ≥ `Viewer`. The ordering is what enables checks like `role >= Role::Admin`.
user_idUserIdrequired
End-user identifier (dashboard login).
curl -X POST https://api.opennozzle.com/v1/invitations/accept \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "token": "string"
}'
get/v1/me/organizations

List organizations the authenticated user belongs to.

identity:read

Response · 200

organizationOrganizationPublicrequired
created_atstring · date-timerequired
idOrganizationIdrequired
Organization within a tenant.
namestringrequired
owner_user_idUserIdrequired
End-user identifier (dashboard login).
slugSlugrequired
A URL-safe identifier: lowercase alphanumerics and single dashes, 1–64 characters, no leading/trailing dash and no double dash. A small set of reserved words is additionally refused at runtime.
tenant_idTenantIdrequired
Top-level tenancy: an organization / customer.
roleRolerequired
Organization member role. Ordered by privilege: `Owner` ≥ `Admin` ≥ `Developer` ≥ `Viewer`. The ordering is what enables checks like `role >= Role::Admin`.
curl -X GET https://api.opennozzle.com/v1/me/organizations \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s
get/v1/organizations/{organization_id}

Get an organization by id.

identity:read

Parameters

organization_idpath · stringrequired

Response · 200

created_atstring · date-timerequired
idOrganizationIdrequired
Organization within a tenant.
namestringrequired
owner_user_idUserIdrequired
End-user identifier (dashboard login).
slugSlugrequired
A URL-safe identifier: lowercase alphanumerics and single dashes, 1–64 characters, no leading/trailing dash and no double dash. A small set of reserved words is additionally refused at runtime.
tenant_idTenantIdrequired
Top-level tenancy: an organization / customer.
curl -X GET https://api.opennozzle.com/v1/organizations/<organization_id> \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s
patch/v1/organizations/{organization_id}

Rename an organization. Its slug never changes.

tenancy:writeIdempotency-Keyemits organization.renamed

Parameters

organization_idpath · stringrequired

Request body

namestringrequired

Response · 200

created_atstring · date-timerequired
idOrganizationIdrequired
Organization within a tenant.
namestringrequired
owner_user_idUserIdrequired
End-user identifier (dashboard login).
slugSlugrequired
A URL-safe identifier: lowercase alphanumerics and single dashes, 1–64 characters, no leading/trailing dash and no double dash. A small set of reserved words is additionally refused at runtime.
tenant_idTenantIdrequired
Top-level tenancy: an organization / customer.
curl -X PATCH https://api.opennozzle.com/v1/organizations/<organization_id> \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "string"
}'
get/v1/organizations/{organization_id}/invitations

List pending invitations for an organization.

identity:read

Parameters

organization_idpath · stringrequired

Response · 200

created_atstring · date-timerequired
emailstringrequired
email_deliveryDelivery | null
Whether the invitation email went out — present on create only.
expires_atstring · date-timerequired
idstring · uuidrequired
invited_byUserIdrequired
End-user identifier (dashboard login).
organization_idOrganizationIdrequired
Organization within a tenant.
roleRolerequired
Organization member role. Ordered by privilege: `Owner` ≥ `Admin` ≥ `Developer` ≥ `Viewer`. The ordering is what enables checks like `role >= Role::Admin`.
statusInvitationStatusrequired
curl -X GET https://api.opennozzle.com/v1/organizations/<organization_id>/invitations \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s
post/v1/organizations/{organization_id}/invitations

Invite an email address to join the organization.

tenancy:writeIdempotency-Keyemits invitation.sent

Parameters

organization_idpath · stringrequired

Request body

emailEmailAddressrequired
An email address, normalized to lowercase and trimmed. Must contain exactly one `@`, a non-empty local part, and a domain containing a dot. Max 320 bytes (RFC 5321).
roleRolerequired
Organization member role. Ordered by privilege: `Owner` ≥ `Admin` ≥ `Developer` ≥ `Viewer`. The ordering is what enables checks like `role >= Role::Admin`.

Response · 201

created_atstring · date-timerequired
emailstringrequired
email_deliveryDelivery | null
Whether the invitation email went out — present on create only.
expires_atstring · date-timerequired
idstring · uuidrequired
invited_byUserIdrequired
End-user identifier (dashboard login).
organization_idOrganizationIdrequired
Organization within a tenant.
roleRolerequired
Organization member role. Ordered by privilege: `Owner` ≥ `Admin` ≥ `Developer` ≥ `Viewer`. The ordering is what enables checks like `role >= Role::Admin`.
statusInvitationStatusrequired
curl -X POST https://api.opennozzle.com/v1/organizations/<organization_id>/invitations \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "email": "you@example.com",
  "role": "viewer"
}'
get/v1/organizations/{organization_id}/members

List members of an organization.

identity:read

Parameters

organization_idpath · stringrequired

Response · 200

avatar_urlstring
display_namestring
emailstring
The person, on the members list. Absent where a membership is returned on its own (accepting an invitation).
joined_atstring · date-timerequired
organization_idOrganizationIdrequired
Organization within a tenant.
roleRolerequired
Organization member role. Ordered by privilege: `Owner` ≥ `Admin` ≥ `Developer` ≥ `Viewer`. The ordering is what enables checks like `role >= Role::Admin`.
user_idUserIdrequired
End-user identifier (dashboard login).
curl -X GET https://api.opennozzle.com/v1/organizations/<organization_id>/members \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s
put/v1/organizations/{organization_id}/members/{user_id}

Change a member's role in the organization.

tenancy:writeIdempotency-Keyemits member.role_updated

Parameters

organization_idpath · stringrequired
user_idpath · stringrequired

Request body

roleRolerequired
Organization member role. Ordered by privilege: `Owner` ≥ `Admin` ≥ `Developer` ≥ `Viewer`. The ordering is what enables checks like `role >= Role::Admin`.

Response · 200

avatar_urlstring
display_namestring
emailstring
The person, on the members list. Absent where a membership is returned on its own (accepting an invitation).
joined_atstring · date-timerequired
organization_idOrganizationIdrequired
Organization within a tenant.
roleRolerequired
Organization member role. Ordered by privilege: `Owner` ≥ `Admin` ≥ `Developer` ≥ `Viewer`. The ordering is what enables checks like `role >= Role::Admin`.
user_idUserIdrequired
End-user identifier (dashboard login).
curl -X PUT https://api.opennozzle.com/v1/organizations/<organization_id>/members/<user_id> \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "role": "viewer"
}'
delete/v1/organizations/{organization_id}/members/{user_id}

Remove a member from the organization.

tenancy:writeIdempotency-Keyemits member.removed

Parameters

organization_idpath · stringrequired
user_idpath · stringrequired

Response · 204

Success. No response body.

curl -X DELETE https://api.opennozzle.com/v1/organizations/<organization_id>/members/<user_id> \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -s
get/v1/organizations/{organization_id}/projects

List projects within an organization.

identity:read

Parameters

organization_idpath · stringrequired

Response · 200

created_atstring · date-timerequired
environmentProjectEnvironmentrequired
idProjectIdrequired
Project within an organization — the unit virtual keys belong to.
namestringrequired
organization_idOrganizationIdrequired
Organization within a tenant.
slugSlugrequired
A URL-safe identifier: lowercase alphanumerics and single dashes, 1–64 characters, no leading/trailing dash and no double dash. A small set of reserved words is additionally refused at runtime.
spend_capSpendCap | null
The project-wide spend ceiling, or `null` when uncapped.
curl -X GET https://api.opennozzle.com/v1/organizations/<organization_id>/projects \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s
post/v1/organizations/{organization_id}/projects

Create a project within an organization.

tenancy:writeIdempotency-Keyemits project.created

Parameters

organization_idpath · stringrequired

Request body

environmentProjectEnvironmentrequired
namestringrequired
slugSlugrequired
A URL-safe identifier: lowercase alphanumerics and single dashes, 1–64 characters, no leading/trailing dash and no double dash. A small set of reserved words is additionally refused at runtime.

Response · 201

created_atstring · date-timerequired
environmentProjectEnvironmentrequired
idProjectIdrequired
Project within an organization — the unit virtual keys belong to.
namestringrequired
organization_idOrganizationIdrequired
Organization within a tenant.
slugSlugrequired
A URL-safe identifier: lowercase alphanumerics and single dashes, 1–64 characters, no leading/trailing dash and no double dash. A small set of reserved words is additionally refused at runtime.
spend_capSpendCap | null
The project-wide spend ceiling, or `null` when uncapped.
curl -X POST https://api.opennozzle.com/v1/organizations/<organization_id>/projects \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "environment": "production",
  "name": "string",
  "slug": "string"
}'
post/v1/organizations/{organization_id}/transfer-ownership

Make another member the owner; you become an admin.

tenancy:writeIdempotency-Keyemits organization.ownership_transferred

Parameters

organization_idpath · stringrequired

Request body

user_idUserIdrequired
End-user identifier (dashboard login).

Response · 204

Success. No response body.

curl -X POST https://api.opennozzle.com/v1/organizations/<organization_id>/transfer-ownership \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "user_id": "01a0c96e-d51d-7213-9ab2-c2d969f9966a"
}'
get/v1/projects/{project_id}

Get a project by id.

identity:read

Parameters

project_idpath · stringrequired

Response · 200

created_atstring · date-timerequired
environmentProjectEnvironmentrequired
idProjectIdrequired
Project within an organization — the unit virtual keys belong to.
namestringrequired
organization_idOrganizationIdrequired
Organization within a tenant.
slugSlugrequired
A URL-safe identifier: lowercase alphanumerics and single dashes, 1–64 characters, no leading/trailing dash and no double dash. A small set of reserved words is additionally refused at runtime.
spend_capSpendCap | null
The project-wide spend ceiling, or `null` when uncapped.
curl -X GET https://api.opennozzle.com/v1/projects/<project_id> \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s
patch/v1/projects/{project_id}

Rename a project. Its slug never changes.

tenancy:writeIdempotency-Keyemits project.renamed

Parameters

project_idpath · stringrequired

Request body

namestringrequired

Response · 200

created_atstring · date-timerequired
environmentProjectEnvironmentrequired
idProjectIdrequired
Project within an organization — the unit virtual keys belong to.
namestringrequired
organization_idOrganizationIdrequired
Organization within a tenant.
slugSlugrequired
A URL-safe identifier: lowercase alphanumerics and single dashes, 1–64 characters, no leading/trailing dash and no double dash. A small set of reserved words is additionally refused at runtime.
spend_capSpendCap | null
The project-wide spend ceiling, or `null` when uncapped.
curl -X PATCH https://api.opennozzle.com/v1/projects/<project_id> \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "string"
}'
delete/v1/projects/{project_id}

Delete a project and revoke every key minted under it.

tenancy:writeIdempotency-Keyemits project.deleted

Parameters

project_idpath · stringrequired

Response · 200

revoked_keysinteger · uint64required
curl -X DELETE https://api.opennozzle.com/v1/projects/<project_id> \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -s
put/v1/projects/{project_id}/budget

Set or lift the project-wide spend ceiling across all its keys.

tenancy:writeIdempotency-Keyemits project.budget_set

Parameters

project_idpath · stringrequired

Request body

spend_capSpendCap | null

Response · 200

created_atstring · date-timerequired
environmentProjectEnvironmentrequired
idProjectIdrequired
Project within an organization — the unit virtual keys belong to.
namestringrequired
organization_idOrganizationIdrequired
Organization within a tenant.
slugSlugrequired
A URL-safe identifier: lowercase alphanumerics and single dashes, 1–64 characters, no leading/trailing dash and no double dash. A small set of reserved words is additionally refused at runtime.
spend_capSpendCap | null
The project-wide spend ceiling, or `null` when uncapped.
curl -X PUT https://api.opennozzle.com/v1/projects/<project_id>/budget \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "spend_cap": {
    "budget_window": "daily",
    "max_budget_micro_cents": 0
  }
}'
post/v1/tenants

Create a tenant with its first organization and project, owned by you.

tenancy:writeIdempotency-Keyemits organization.created

Request body

namestringrequired
Display name for the tenant — your company, or whatever you call the billing boundary. The slug is derived from it unless you supply one.
organization_namestring
First organization's name. Defaults to the tenant name — the common case is one company, one organization, and asking twice for the same answer is a worse first experience than assuming it.
project_environmentProjectEnvironment | null
First project's environment. Defaults to production: a first project is overwhelmingly where real traffic goes, and a caller who wanted staging will say so.
project_namestring
First project's name. Defaults to `default`.
slugSlug | null
Optional explicit slug. Supply it when the derived one would be ugly, or when the name has no derivable slug at all (all punctuation, all emoji). Collisions are resolved automatically with a random suffix.

Response · 200

organizationOrganizationPublicrequired
created_atstring · date-timerequired
idOrganizationIdrequired
Organization within a tenant.
namestringrequired
owner_user_idUserIdrequired
End-user identifier (dashboard login).
slugSlugrequired
A URL-safe identifier: lowercase alphanumerics and single dashes, 1–64 characters, no leading/trailing dash and no double dash. A small set of reserved words is additionally refused at runtime.
tenant_idTenantIdrequired
Top-level tenancy: an organization / customer.
projectProjectPublicrequired
created_atstring · date-timerequired
environmentProjectEnvironmentrequired
idProjectIdrequired
Project within an organization — the unit virtual keys belong to.
namestringrequired
organization_idOrganizationIdrequired
Organization within a tenant.
slugSlugrequired
A URL-safe identifier: lowercase alphanumerics and single dashes, 1–64 characters, no leading/trailing dash and no double dash. A small set of reserved words is additionally refused at runtime.
spend_capSpendCap | null
The project-wide spend ceiling, or `null` when uncapped.
tenantTenantPublicrequired
created_atstring · date-timerequired
idTenantIdrequired
Top-level tenancy: an organization / customer.
namestringrequired
regionstringrequired
slugSlugrequired
A URL-safe identifier: lowercase alphanumerics and single dashes, 1–64 characters, no leading/trailing dash and no double dash. A small set of reserved words is additionally refused at runtime.
statusTenantStatusrequired
curl -X POST https://api.opennozzle.com/v1/tenants \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "string",
  "organization_name": null,
  "project_environment": null,
  "project_name": null,
  "slug": null
}'
get/v1/tenants/{tenant_id}

Get a tenant by id.

identity:read

Parameters

tenant_idpath · stringrequired

Response · 200

created_atstring · date-timerequired
idTenantIdrequired
Top-level tenancy: an organization / customer.
namestringrequired
regionstringrequired
slugSlugrequired
A URL-safe identifier: lowercase alphanumerics and single dashes, 1–64 characters, no leading/trailing dash and no double dash. A small set of reserved words is additionally refused at runtime.
statusTenantStatusrequired
curl -X GET https://api.opennozzle.com/v1/tenants/<tenant_id> \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s
get/v1/tenants/{tenant_id}/organizations

List organizations within a tenant.

identity:read

Parameters

tenant_idpath · stringrequired

Response · 200

created_atstring · date-timerequired
idOrganizationIdrequired
Organization within a tenant.
namestringrequired
owner_user_idUserIdrequired
End-user identifier (dashboard login).
slugSlugrequired
A URL-safe identifier: lowercase alphanumerics and single dashes, 1–64 characters, no leading/trailing dash and no double dash. A small set of reserved words is additionally refused at runtime.
tenant_idTenantIdrequired
Top-level tenancy: an organization / customer.
curl -X GET https://api.opennozzle.com/v1/tenants/<tenant_id>/organizations \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s
post/v1/tenants/{tenant_id}/organizations

Create an organization within a tenant.

tenancy:writeIdempotency-Keyemits organization.created

Parameters

tenant_idpath · stringrequired

Request body

namestringrequired
slugSlugrequired
A URL-safe identifier: lowercase alphanumerics and single dashes, 1–64 characters, no leading/trailing dash and no double dash. A small set of reserved words is additionally refused at runtime.

Response · 201

created_atstring · date-timerequired
idOrganizationIdrequired
Organization within a tenant.
namestringrequired
owner_user_idUserIdrequired
End-user identifier (dashboard login).
slugSlugrequired
A URL-safe identifier: lowercase alphanumerics and single dashes, 1–64 characters, no leading/trailing dash and no double dash. A small set of reserved words is additionally refused at runtime.
tenant_idTenantIdrequired
Top-level tenancy: an organization / customer.
curl -X POST https://api.opennozzle.com/v1/tenants/<tenant_id>/organizations \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "string",
  "slug": "string"
}'
get/v1/tenants/{tenant_id}/usage

Get a tenant's cost rollup over 24h / 7d / 30d / all-time, plus per-kind breakdown.

usage:read

Parameters

tenant_idpath · stringrequired

Response · 200

all_time_centsinteger · int64required
last_24h_centsinteger · int64required
last_30d_by_kindUsageByKind[]required
cost_centsinteger · int64required
kindstringrequired
row_countinteger · int64required
last_30d_centsinteger · int64required
last_7d_centsinteger · int64required
tenant_idstring · uuidrequired
curl -X GET https://api.opennozzle.com/v1/tenants/<tenant_id>/usage \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s
get/v1/usage

Read your own usage rollup.

usage:read

Response · 200

all_time_centsinteger · int64required
last_24h_centsinteger · int64required
last_30d_by_kindUsageByKind[]required
cost_centsinteger · int64required
kindstringrequired
row_countinteger · int64required
last_30d_centsinteger · int64required
last_7d_centsinteger · int64required
tenant_idstring · uuidrequired
curl -X GET https://api.opennozzle.com/v1/usage \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s

Accounts & sessions

18 operations
post/v1/auth/email/verify

Consume an email-verification token and mark the email verified.

no authIdempotency-Keyemits user.email_verified

Request body

tokenstringrequired

Response · 204

Success. No response body.

curl -X POST https://api.opennozzle.com/v1/auth/email/verify \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "token": "string"
}'
post/v1/auth/email/verify/resend

Send a fresh email-verification link to the authenticated user's address.

identity:writeIdempotency-Keyemits user.email_verification_resent

Response · 204

Success. No response body.

curl -X POST https://api.opennozzle.com/v1/auth/email/verify/resend \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -s
post/v1/auth/login

Exchange email + password (+ MFA) for an access + refresh token pair.

no authIdempotency-Keyemits session.opened

Request body

emailEmailAddressrequired
An email address, normalized to lowercase and trimmed. Must contain exactly one `@`, a non-empty local part, and a domain containing a dot. Max 320 bytes (RFC 5321).
mfa_codeMfaCode | null
passwordPlaintextPasswordrequired
A plaintext password. Accepted on request bodies only — never present in any response. Held in memory as a zeroizing secret and dropped once hashed or verified.

Response · 200

access_expires_atstring · date-timerequired
access_tokenstringrequired
refresh_expires_atstring · date-timerequired
refresh_tokenstringrequired
userUserPublicrequired
The non-secret view of a User. This is what every endpoint that returns user info emits — `email_verified` instead of `email_verified_at`, no audit timestamps, no `mfa_required` flag (it's a security signal).
avatar_urlstring
created_atstring · date-timerequired
display_nameDisplayNamerequired
A display name. Trimmed on receipt; 1–128 characters; control characters are refused.
emailEmailAddressrequired
An email address, normalized to lowercase and trimmed. Must contain exactly one `@`, a non-empty local part, and a domain containing a dot. Max 320 bytes (RFC 5321).
email_verifiedbooleanrequired
idUserIdrequired
End-user identifier (dashboard login).
statusUserStatusrequired
curl -X POST https://api.opennozzle.com/v1/auth/login \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "email": "you@example.com",
  "mfa_code": "string",
  "password": "string"
}'
post/v1/auth/logout

Revoke the current session.

identity:writeIdempotency-Keyemits session.closed

Response · 204

Success. No response body.

curl -X POST https://api.opennozzle.com/v1/auth/logout \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -s
post/v1/auth/password/reset-confirm

Consume a reset token and set a new password.

no authIdempotency-Keyemits user.password_reset

Request body

new_passwordPlaintextPasswordrequired
A plaintext password. Accepted on request bodies only — never present in any response. Held in memory as a zeroizing secret and dropped once hashed or verified.
tokenstringrequired

Response · 204

Success. No response body.

curl -X POST https://api.opennozzle.com/v1/auth/password/reset-confirm \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "new_password": "string",
  "token": "string"
}'
post/v1/auth/password/reset-request

Request a password-reset email. Always 204 — never reveals account existence.

no authIdempotency-Keyemits user.password_reset_requested

Request body

emailEmailAddressrequired
An email address, normalized to lowercase and trimmed. Must contain exactly one `@`, a non-empty local part, and a domain containing a dot. Max 320 bytes (RFC 5321).

Response · 204

Success. No response body.

curl -X POST https://api.opennozzle.com/v1/auth/password/reset-request \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "email": "you@example.com"
}'
post/v1/auth/refresh

Rotate a refresh token, yielding a new access + refresh pair.

no authIdempotency-Key

Request body

refresh_tokenstring

Response · 200

access_expires_atstring · date-timerequired
access_tokenstringrequired
refresh_expires_atstring · date-timerequired
refresh_tokenstringrequired
userUserPublicrequired
The non-secret view of a User. This is what every endpoint that returns user info emits — `email_verified` instead of `email_verified_at`, no audit timestamps, no `mfa_required` flag (it's a security signal).
avatar_urlstring
created_atstring · date-timerequired
display_nameDisplayNamerequired
A display name. Trimmed on receipt; 1–128 characters; control characters are refused.
emailEmailAddressrequired
An email address, normalized to lowercase and trimmed. Must contain exactly one `@`, a non-empty local part, and a domain containing a dot. Max 320 bytes (RFC 5321).
email_verifiedbooleanrequired
idUserIdrequired
End-user identifier (dashboard login).
statusUserStatusrequired
curl -X POST https://api.opennozzle.com/v1/auth/refresh \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "refresh_token": null
}'
post/v1/auth/signup

Create an account with email + password and start a session.

no authIdempotency-Keyemits user.signed_up

Request body

display_nameDisplayNamerequired
A display name. Trimmed on receipt; 1–128 characters; control characters are refused.
emailEmailAddressrequired
An email address, normalized to lowercase and trimmed. Must contain exactly one `@`, a non-empty local part, and a domain containing a dot. Max 320 bytes (RFC 5321).
passwordPlaintextPasswordrequired
A plaintext password. Accepted on request bodies only — never present in any response. Held in memory as a zeroizing secret and dropped once hashed or verified.

Response · 200

access_expires_atstring · date-timerequired
access_tokenstringrequired
refresh_expires_atstring · date-timerequired
refresh_tokenstringrequired
userUserPublicrequired
The non-secret view of a User. This is what every endpoint that returns user info emits — `email_verified` instead of `email_verified_at`, no audit timestamps, no `mfa_required` flag (it's a security signal).
avatar_urlstring
created_atstring · date-timerequired
display_nameDisplayNamerequired
A display name. Trimmed on receipt; 1–128 characters; control characters are refused.
emailEmailAddressrequired
An email address, normalized to lowercase and trimmed. Must contain exactly one `@`, a non-empty local part, and a domain containing a dot. Max 320 bytes (RFC 5321).
email_verifiedbooleanrequired
idUserIdrequired
End-user identifier (dashboard login).
statusUserStatusrequired
curl -X POST https://api.opennozzle.com/v1/auth/signup \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "display_name": "string",
  "email": "you@example.com",
  "password": "string"
}'
get/v1/me

Return the authenticated user.

identity:read

Response · 200

avatar_urlstring
created_atstring · date-timerequired
display_nameDisplayNamerequired
A display name. Trimmed on receipt; 1–128 characters; control characters are refused.
emailEmailAddressrequired
An email address, normalized to lowercase and trimmed. Must contain exactly one `@`, a non-empty local part, and a domain containing a dot. Max 320 bytes (RFC 5321).
email_verifiedbooleanrequired
idUserIdrequired
End-user identifier (dashboard login).
statusUserStatusrequired
curl -X GET https://api.opennozzle.com/v1/me \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s
patch/v1/me

Update the authenticated user's display name or avatar.

identity:writeIdempotency-Keyemits user.profile_updated

Request body

avatar_urlstring
display_nameDisplayName | null

Response · 200

avatar_urlstring
created_atstring · date-timerequired
display_nameDisplayNamerequired
A display name. Trimmed on receipt; 1–128 characters; control characters are refused.
emailEmailAddressrequired
An email address, normalized to lowercase and trimmed. Must contain exactly one `@`, a non-empty local part, and a domain containing a dot. Max 320 bytes (RFC 5321).
email_verifiedbooleanrequired
idUserIdrequired
End-user identifier (dashboard login).
statusUserStatusrequired
curl -X PATCH https://api.opennozzle.com/v1/me \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "avatar_url": null,
  "display_name": null
}'
post/v1/me/email

Send a confirmation link to a new address; the account moves only when it is followed.

identity:writeIdempotency-Keyemits user.email_change_requested

Request body

current_passwordPlaintextPasswordrequired
A plaintext password. Accepted on request bodies only — never present in any response. Held in memory as a zeroizing secret and dropped once hashed or verified.
new_emailEmailAddressrequired
An email address, normalized to lowercase and trimmed. Must contain exactly one `@`, a non-empty local part, and a domain containing a dot. Max 320 bytes (RFC 5321).

Response · 204

Success. No response body.

curl -X POST https://api.opennozzle.com/v1/me/email \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "current_password": "string",
  "new_email": "you@example.com"
}'
post/v1/me/mfa/recovery-codes/generate

Generate one-time recovery codes for MFA fallback.

identity:writeIdempotency-Keyemits user.mfa_recovery_generated

Response · 200

codesstring[]required
Plaintext codes. Display once; never recoverable.
factor_idstring · uuidrequired
curl -X POST https://api.opennozzle.com/v1/me/mfa/recovery-codes/generate \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -s
post/v1/me/mfa/totp/confirm

Confirm TOTP enrollment by submitting a current code.

identity:writeIdempotency-Keyemits user.mfa_totp_confirmed

Request body

codeMfaCoderequired
A second-factor code: either a 6-digit TOTP code or a recovery code. Trimmed on receipt.
factor_idstring · uuidrequired

Response · 204

Success. No response body.

curl -X POST https://api.opennozzle.com/v1/me/mfa/totp/confirm \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "code": "string",
  "factor_id": "01a0c96e-d51d-7213-9ab2-c2d969f9966a"
}'
post/v1/me/mfa/totp/enroll

Begin TOTP enrollment; returns the shared secret and provisioning URI.

identity:writeIdempotency-Keyemits user.mfa_totp_enrolled

Response · 200

factor_idstring · uuidrequired
otpauth_uristringrequired
`otpauth://...` URI for the user's authenticator app QR code.
secretstringrequired
The Base32-encoded TOTP secret. Display once; never again.
curl -X POST https://api.opennozzle.com/v1/me/mfa/totp/enroll \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -s
post/v1/me/password

Change the authenticated user's password.

identity:writeIdempotency-Keyemits user.password_changed

Request body

current_passwordPlaintextPasswordrequired
A plaintext password. Accepted on request bodies only — never present in any response. Held in memory as a zeroizing secret and dropped once hashed or verified.
new_passwordPlaintextPasswordrequired
A plaintext password. Accepted on request bodies only — never present in any response. Held in memory as a zeroizing secret and dropped once hashed or verified.

Response · 204

Success. No response body.

curl -X POST https://api.opennozzle.com/v1/me/password \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "current_password": "string",
  "new_password": "string"
}'
get/v1/me/sessions

List the authenticated user's active sessions.

identity:read

Response · 200

created_atstring · date-timerequired
currentbooleanrequired
expires_atstring · date-timerequired
idSessionIdrequired
A browser session.
ipstring
last_seen_atstring · date-timerequired
user_agentstring
curl -X GET https://api.opennozzle.com/v1/me/sessions \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s
delete/v1/me/sessions/{session_id}

Revoke one of the authenticated user's sessions.

identity:writeIdempotency-Keyemits session.revoked

Parameters

session_idpath · stringrequired

Response · 204

Success. No response body.

curl -X DELETE https://api.opennozzle.com/v1/me/sessions/<session_id> \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -s
post/v1/me/sessions/revoke-others

Revoke every active session except the current one.

identity:writeIdempotency-Keyemits user.logged_out_other_devices

Response · 200

revoked_countinteger · uint64required
curl -X POST https://api.opennozzle.com/v1/me/sessions/revoke-others \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -s

Your provider keys

4 operations
get/v1/byok/credentials

List this tenant's provider credentials (last4 only, never key material).

keys:read

Response · 200

base_url_overridestring
created_atstring · date-timerequired
idstring · uuidrequired
key_last4stringrequired
last_verified_atstring · date-time
providerstringrequired
statusstringrequired
tenant_idTenantId | null
updated_atstring · date-timerequired
curl -X GET https://api.opennozzle.com/v1/byok/credentials \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s
post/v1/byok/credentials

Upload a provider API key (validated, sealed, one per provider).

keys:writeIdempotency-Key

Request body

api_keystringrequired
The customer's plaintext provider key. Sealed immediately; never stored, logged, or echoed.
base_url_overridestring
providerstringrequired
`models.upstream_providers.name` — a typo fails the FK at INSERT.

Response · 201

base_url_overridestring
created_atstring · date-timerequired
idstring · uuidrequired
key_last4stringrequired
last_verified_atstring · date-time
providerstringrequired
statusstringrequired
tenant_idTenantId | null
updated_atstring · date-timerequired
curl -X POST https://api.opennozzle.com/v1/byok/credentials \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "api_key": "string",
  "base_url_override": null,
  "provider": "string"
}'
delete/v1/byok/credentials/{id}

Delete a provider credential (hard delete — no ciphertext remains).

keys:writeIdempotency-Key

Parameters

idpath · stringrequired

Response · 204

Success. No response body.

curl -X DELETE https://api.opennozzle.com/v1/byok/credentials/<id> \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -s
post/v1/byok/credentials/{id}/rotate

Replace a credential's key (re-validated, re-sealed on the current ring).

keys:writeIdempotency-Key

Parameters

idpath · stringrequired

Request body

api_keystringrequired
The replacement plaintext key. Same discipline as create.

Response · 200

base_url_overridestring
created_atstring · date-timerequired
idstring · uuidrequired
key_last4stringrequired
last_verified_atstring · date-time
providerstringrequired
statusstringrequired
tenant_idTenantId | null
updated_atstring · date-timerequired
curl -X POST https://api.opennozzle.com/v1/byok/credentials/<id>/rotate \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "api_key": "string"
}'

Webhooks

10 operations
get/v1/projects/{project_id}/webhooks

List webhook subscriptions in a project.

webhooks:read

Parameters

project_idpath · stringrequired

Response · 200

activebooleanrequired
created_atstring · date-timerequired
descriptionstring
disabled_atstring · date-time
event_typesstring[]required
idWebhookSubscriptionIdrequired
A tenant's outbound-webhook subscription.
project_idProjectIdrequired
Project within an organization — the unit virtual keys belong to.
tenant_idTenantIdrequired
Top-level tenancy: an organization / customer.
updated_atstring · date-timerequired
urlstringrequired
curl -X GET https://api.opennozzle.com/v1/projects/<project_id>/webhooks \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s
post/v1/projects/{project_id}/webhooks

Create an outbound webhook subscription in a project.

webhooks:writeIdempotency-Key

Parameters

project_idpath · stringrequired

Request body

descriptionstring
event_typesstring[]required
Customer-namespace event types only — System events are refused.
urlstringrequired

Response · 201

activebooleanrequired
created_atstring · date-timerequired
descriptionstring
disabled_atstring · date-time
event_typesstring[]required
idWebhookSubscriptionIdrequired
A tenant's outbound-webhook subscription.
project_idProjectIdrequired
Project within an organization — the unit virtual keys belong to.
tenant_idTenantIdrequired
Top-level tenancy: an organization / customer.
updated_atstring · date-timerequired
urlstringrequired
curl -X POST https://api.opennozzle.com/v1/projects/<project_id>/webhooks \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "description": null,
  "event_types": [
    "string"
  ],
  "url": "string"
}'
get/v1/webhooks/{webhook_id}

Get a webhook subscription (no signing secret).

webhooks:read

Parameters

webhook_idpath · stringrequired

Response · 200

activebooleanrequired
created_atstring · date-timerequired
descriptionstring
disabled_atstring · date-time
event_typesstring[]required
idWebhookSubscriptionIdrequired
A tenant's outbound-webhook subscription.
project_idProjectIdrequired
Project within an organization — the unit virtual keys belong to.
tenant_idTenantIdrequired
Top-level tenancy: an organization / customer.
updated_atstring · date-timerequired
urlstringrequired
curl -X GET https://api.opennozzle.com/v1/webhooks/<webhook_id> \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s
patch/v1/webhooks/{webhook_id}

Update a webhook subscription (url, events, active).

webhooks:writeIdempotency-Key

Parameters

webhook_idpath · stringrequired

Request body

activeboolean
descriptionstring
event_typesarray
urlstring

Response · 200

activebooleanrequired
created_atstring · date-timerequired
descriptionstring
disabled_atstring · date-time
event_typesstring[]required
idWebhookSubscriptionIdrequired
A tenant's outbound-webhook subscription.
project_idProjectIdrequired
Project within an organization — the unit virtual keys belong to.
tenant_idTenantIdrequired
Top-level tenancy: an organization / customer.
updated_atstring · date-timerequired
urlstringrequired
curl -X PATCH https://api.opennozzle.com/v1/webhooks/<webhook_id> \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "active": null,
  "description": null,
  "event_types": null,
  "url": null
}'
delete/v1/webhooks/{webhook_id}

Delete a webhook subscription.

webhooks:writeIdempotency-Key

Parameters

webhook_idpath · stringrequired

Response · 204

Success. No response body.

curl -X DELETE https://api.opennozzle.com/v1/webhooks/<webhook_id> \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -s
get/v1/webhooks/{webhook_id}/deliveries

List recent delivery attempts for a subscription.

webhooks:read

Parameters

webhook_idpath · stringrequired

Response · 200

attemptinteger · uint32required
created_atstring · date-timerequired
delivered_atstring · date-time
event_idWebhookEventIdrequired
One fired event in api.webhook_event_log.
event_typestringrequired
idWebhookDeliveryIdrequired
One (event, subscription) delivery attempt-chain.
last_errorstring
last_status_codeinteger · int32
max_attemptsinteger · uint32required
next_attempt_atstring · date-timerequired
stateDeliveryStaterequired
The lifecycle state of one delivery attempt-chain.
subscription_idWebhookSubscriptionIdrequired
A tenant's outbound-webhook subscription.
curl -X GET https://api.opennozzle.com/v1/webhooks/<webhook_id>/deliveries \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s
post/v1/webhooks/{webhook_id}/rotate-secret

Rotate a subscription's signing secret.

webhooks:writeIdempotency-Key

Parameters

webhook_idpath · stringrequired

Response · 200

idWebhookSubscriptionIdrequired
A tenant's outbound-webhook subscription.
signing_secretstringrequired
curl -X POST https://api.opennozzle.com/v1/webhooks/<webhook_id>/rotate-secret \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -s
post/v1/webhooks/{webhook_id}/test

Send a signed webhook.test delivery to this subscription now.

webhooks:writeIdempotency-Key

Parameters

webhook_idpath · stringrequired

Response · 200

attemptinteger · uint32required
created_atstring · date-timerequired
delivered_atstring · date-time
event_idWebhookEventIdrequired
One fired event in api.webhook_event_log.
event_typestringrequired
idWebhookDeliveryIdrequired
One (event, subscription) delivery attempt-chain.
last_errorstring
last_status_codeinteger · int32
max_attemptsinteger · uint32required
next_attempt_atstring · date-timerequired
stateDeliveryStaterequired
The lifecycle state of one delivery attempt-chain.
subscription_idWebhookSubscriptionIdrequired
A tenant's outbound-webhook subscription.
curl -X POST https://api.opennozzle.com/v1/webhooks/<webhook_id>/test \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -s
post/v1/webhooks/deliveries/{delivery_id}/replay

Replay a past delivery (creates a fresh delivery).

webhooks:writeIdempotency-Key

Parameters

delivery_idpath · stringrequired

Response · 200

attemptinteger · uint32required
created_atstring · date-timerequired
delivered_atstring · date-time
event_idWebhookEventIdrequired
One fired event in api.webhook_event_log.
event_typestringrequired
idWebhookDeliveryIdrequired
One (event, subscription) delivery attempt-chain.
last_errorstring
last_status_codeinteger · int32
max_attemptsinteger · uint32required
next_attempt_atstring · date-timerequired
stateDeliveryStaterequired
The lifecycle state of one delivery attempt-chain.
subscription_idWebhookSubscriptionIdrequired
A tenant's outbound-webhook subscription.
curl -X POST https://api.opennozzle.com/v1/webhooks/deliveries/<delivery_id>/replay \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -s
get/v1/webhooks/event-types

List the customer-subscribable webhook event types.

webhooks:read

Response · 200

event_typestringrequired
namespacestringrequired
curl -X GET https://api.opennozzle.com/v1/webhooks/event-types \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s

Notifications

8 operations
get/v1/notifications

Your workspace's notifications, newest first, with your unread count.

usage:read

Response · 200

has_morebooleanrequired
itemsInboxNotification[]required
bodystringrequired
created_atstring · date-timerequired
dataobjectrequired
idstring · uuidrequired
kindstringrequired
The event it came from, e.g. `virtual_key.revoked`.
linkstring
A console path to open, e.g. `/app/keys`.
project_idstring · uuid
readbooleanrequired
resource_idstring
resource_typestring
severityNotificationSeverityrequired
How loud a notification is. Mirrors the webhook registry's tiers so one vocabulary colours the bell, the webhook catalog and the audit log.
tenant_idstring · uuidrequired
titlestringrequired
next_cursorstring
unread_countinteger · int64required
curl -X GET https://api.opennozzle.com/v1/notifications \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s
post/v1/notifications/{id}/read

Mark one notification read for you.

usage:readIdempotency-Key

Parameters

idpath · stringrequired

Response · 204

Success. No response body.

curl -X POST https://api.opennozzle.com/v1/notifications/<id>/read \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -s
post/v1/notifications/read-all

Mark every notification read for you.

usage:readIdempotency-Key

Response · 200

read_all_beforestring · date-timerequired
Everything created at or before this instant now reads as read.
curl -X POST https://api.opennozzle.com/v1/notifications/read-all \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -s
get/v1/notifications/subscriptions

List your own notification subscriptions.

webhooks:read

Response · 200

activebooleanrequired
channelChannelrequired
created_atstring · date-timerequired
event_typestringrequired
idstring · uuidrequired
last_delivery_atstring · date-time
project_idstring · uuid
targetobjectrequired
tenant_idstring · uuidrequired
updated_atstring · date-timerequired
curl -X GET https://api.opennozzle.com/v1/notifications/subscriptions \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s
get/v1/notifications/unread-count

How many notifications you have not read.

usage:read

Response · 200

unread_countinteger · int64required
curl -X GET https://api.opennozzle.com/v1/notifications/unread-count \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s
get/v1/tenants/{tenant_id}/notifications/subscriptions

List the tenant's notification subscriptions.

webhooks:read

Parameters

tenant_idpath · stringrequired

Response · 200

activebooleanrequired
channelChannelrequired
created_atstring · date-timerequired
event_typestringrequired
idstring · uuidrequired
last_delivery_atstring · date-time
project_idstring · uuid
targetobjectrequired
tenant_idstring · uuidrequired
updated_atstring · date-timerequired
curl -X GET https://api.opennozzle.com/v1/tenants/<tenant_id>/notifications/subscriptions \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s
post/v1/tenants/{tenant_id}/notifications/subscriptions

Create a notification subscription (channel + event_type).

webhooks:writeIdempotency-Key

Parameters

tenant_idpath · stringrequired

Response · 201

activebooleanrequired
channelChannelrequired
created_atstring · date-timerequired
event_typestringrequired
idstring · uuidrequired
last_delivery_atstring · date-time
project_idstring · uuid
targetobjectrequired
tenant_idstring · uuidrequired
updated_atstring · date-timerequired
curl -X POST https://api.opennozzle.com/v1/tenants/<tenant_id>/notifications/subscriptions \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -s
delete/v1/tenants/{tenant_id}/notifications/subscriptions/{id}

Delete a notification subscription.

webhooks:writeIdempotency-Key

Parameters

tenant_idpath · stringrequired
idpath · stringrequired

Response · 204

Success. No response body.

curl -X DELETE https://api.opennozzle.com/v1/tenants/<tenant_id>/notifications/subscriptions/<id> \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -s

Live events

1 operation
get/v1/events/stream

Live tenant event stream (SSE): cost, keys, instances, notifications, webhooks, model health.

usage:read

Response · 200

Server-Sent Events. Each frame's `event:` is the kind (e.g. `cost.recorded`), `id:` is the resume token to send back as `Last-Event-ID`, and `data:` is one LiveEvent JSON object. Comment lines are keep-alives.

curl -X GET https://api.opennozzle.com/v1/events/stream \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s

Cost alerts

4 operations
get/v1/cost-alerts

Your workspace's cost alert rules, each with its spend in the current window.

billing:read

Response · 200

activebooleanrequired
created_atstring · date-timerequired
current_periodstringrequired
Spend in the current window so far — what the threshold is measured against right now.
current_spend_micro_centsinteger · int64required
idstring · uuidrequired
last_fired_atstring · date-time
last_fired_periodstring
The period this rule last fired in (`2026-09-22` / `2026-09`).
namestringrequired
tenant_idstring · uuidrequired
threshold_micro_centsinteger · int64required
updated_atstring · date-timerequired
virtual_key_idstring · uuid
`null` watches the whole workspace; set, it watches one key.
windowCostAlertWindowrequired
curl -X GET https://api.opennozzle.com/v1/cost-alerts \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s
post/v1/cost-alerts

Alert once per day or month when the workspace, or one key, spends past a threshold.

billing:writeIdempotency-Key

Request body

namestringrequired
threshold_micro_centsinteger · int64required
virtual_key_idstring · uuid
windowCostAlertWindowrequired

Response · 201

activebooleanrequired
created_atstring · date-timerequired
current_periodstringrequired
Spend in the current window so far — what the threshold is measured against right now.
current_spend_micro_centsinteger · int64required
idstring · uuidrequired
last_fired_atstring · date-time
last_fired_periodstring
The period this rule last fired in (`2026-09-22` / `2026-09`).
namestringrequired
tenant_idstring · uuidrequired
threshold_micro_centsinteger · int64required
updated_atstring · date-timerequired
virtual_key_idstring · uuid
`null` watches the whole workspace; set, it watches one key.
windowCostAlertWindowrequired
curl -X POST https://api.opennozzle.com/v1/cost-alerts \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "string",
  "threshold_micro_cents": 0,
  "virtual_key_id": null,
  "window": "day"
}'
patch/v1/cost-alerts/{id}

Rename a cost alert, change its threshold, or pause it.

billing:writeIdempotency-Key

Parameters

idpath · stringrequired

Request body

activeboolean
namestring
threshold_micro_centsinteger · int64

Response · 200

activebooleanrequired
created_atstring · date-timerequired
current_periodstringrequired
Spend in the current window so far — what the threshold is measured against right now.
current_spend_micro_centsinteger · int64required
idstring · uuidrequired
last_fired_atstring · date-time
last_fired_periodstring
The period this rule last fired in (`2026-09-22` / `2026-09`).
namestringrequired
tenant_idstring · uuidrequired
threshold_micro_centsinteger · int64required
updated_atstring · date-timerequired
virtual_key_idstring · uuid
`null` watches the whole workspace; set, it watches one key.
windowCostAlertWindowrequired
curl -X PATCH https://api.opennozzle.com/v1/cost-alerts/<id> \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "active": null,
  "name": null,
  "threshold_micro_cents": null
}'
delete/v1/cost-alerts/{id}

Delete a cost alert.

billing:writeIdempotency-Key

Parameters

idpath · stringrequired

Response · 204

Success. No response body.

curl -X DELETE https://api.opennozzle.com/v1/cost-alerts/<id> \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -s

Audit log

5 operations
get/v1/audit

List your own audit-log entries.

audit:read

Response · 200

has_morebooleanrequired
itemsAuditEntryPublic[]required
actionstringrequired
actor_idstring · uuid
actor_kindstringrequired
idAuditEntryIdrequired
One row in api.audit_log.
ipstring
methodstringrequired
occurred_atstring · date-timerequired
pathstringrequired
request_idstringrequired
resource_idstring
resource_typestring
status_codeinteger · int32required
tenant_idTenantId | null
trace_idstring
user_agentstring
next_cursorstring
curl -X GET https://api.opennozzle.com/v1/audit \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s
get/v1/audit/{audit_id}

Get one audit entry by id.

audit:read

Parameters

audit_idpath · stringrequired

Response · 200

actionstringrequired
actor_idstring · uuid
actor_kindstringrequired
idAuditEntryIdrequired
One row in api.audit_log.
ipstring
methodstringrequired
occurred_atstring · date-timerequired
pathstringrequired
request_idstringrequired
resource_idstring
resource_typestring
status_codeinteger · int32required
tenant_idTenantId | null
trace_idstring
user_agentstring
curl -X GET https://api.opennozzle.com/v1/audit/<audit_id> \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s
get/v1/audit/export

Export your own audit log as CSV.

admin:audit:export

Response · 200

object

curl -X GET https://api.opennozzle.com/v1/audit/export \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s
get/v1/tenants/{tenant_id}/audit

List audit entries for a tenant (cursor-paginated).

audit:read

Parameters

tenant_idpath · stringrequired

Response · 200

has_morebooleanrequired
itemsAuditEntryPublic[]required
actionstringrequired
actor_idstring · uuid
actor_kindstringrequired
idAuditEntryIdrequired
One row in api.audit_log.
ipstring
methodstringrequired
occurred_atstring · date-timerequired
pathstringrequired
request_idstringrequired
resource_idstring
resource_typestring
status_codeinteger · int32required
tenant_idTenantId | null
trace_idstring
user_agentstring
next_cursorstring
curl -X GET https://api.opennozzle.com/v1/tenants/<tenant_id>/audit \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s
get/v1/tenants/{tenant_id}/audit/export

Stream a tenant's audit log as CSV (capped at 10k rows).

admin:audit:export

Parameters

tenant_idpath · stringrequired

Response · 200

object

curl -X GET https://api.opennozzle.com/v1/tenants/<tenant_id>/audit/export \
  -H "Authorization: Bearer $NOZZLE_API_KEY" \
  -s

Health

3 operations
get/v1/health/liveness

Cheap probe: returns OK as long as the process is responding.

no auth

Response · 200

servicestringrequired
statusstringrequired
uptime_secondsinteger · uint64required
versionstringrequired
curl -X GET https://api.opennozzle.com/v1/health/liveness \
  -s
get/v1/health/readiness

Returns OK only when every dependency is reachable.

no auth

Response · 200

checksDependencyCheck[]required
errorstring
latency_msinteger · uint64required
namestringrequired
statusCheckStatusrequired
statusReadinessStatusrequired
curl -X GET https://api.opennozzle.com/v1/health/readiness \
  -s
get/v1/openapi.json

Get the OpenAPI 3.1 spec describing every Surface::Public route.

no auth

Response · 200

object

curl -X GET https://api.opennozzle.com/v1/openapi.json \
  -s