Subscriptions
List My Subscriptions
Lists subscriptions across every organization the caller may see, paginated: the organizations they hold a membership in, plus their personal organization (design doc §44.2 -- an organization is a shared workspace, so members see each other's subscriptions).
query Parameters
pagePage number (1-indexed). Defaults to 1.
Page number (1-indexed). Defaults to 1.
page_sizeNumber of items per page. Defaults to 20, max 100.
Number of items per page. Defaults to 20, max 100.
product_idNarrows the list to the subscriptions of one product (V-0602). Exact match; the total and the pagination describe the narrowed set. Omitted returns every product. A single id, not a list: a caller needing several products makes one call each.
Narrows the list to the subscriptions of one product (V-0602). Exact match; the total and the pagination describe the narrowed set. Omitted returns every product. A single id, not a list: a caller needing several products makes one call each.
project_idNarrows the list to one project (§34.1). Omitted returns every subscription the caller may see, including those not yet attributed to a project.
Narrows the list to one project (§34.1). Omitted returns every subscription the caller may see, including those not yet attributed to a project.
List My Subscriptions › Responses
Subscriptions
Pagination metadata included in paginated responses
Get Subscription
Gets one subscription from any organization the caller may see: the organizations they hold a membership in, plus their personal organization (design doc §44.2).
path Parameters
idGet Subscription › Responses
The subscription
anchor_atauto_renewcadence_monthsThe billing period this subscription renews on -- distinct from the
pinned Price's own cadence_months (the period its rates are quoted
per). See price.cadence_months and design doc §3.4, "cadence_months
appears on both prices and subscriptions".
created_atidorganization_idThe Price this subscription is pinned to -- what it renews at. Always the pinned Price's own stored rates, never a fresh selection: design doc §3.4.2 guard rail 1 reserves resolve_acquisition_price for a brand-new purchase, and a subscription's renewal reads its own price_id, never that resolver. The figures below are the Price's stored price_lines verbatim -- no discount, proration, or reseller multiplier is applied, so this can never show a number that does not exist in the pinned row.
product_definition_idproduct_idproject_idThe project this subscription belongs to (§34.1's
Organization -> Project -> Subscription -> Resource).
Always present. The link is NOT NULL in the schema, so there is no
"not yet attributed" case for a reader to handle.
quantitystatusactivated_atcancels_atThe hardware profile this subscription's workload runs on, by name. null under the same conditions as region.
internal_addressThe bare, human-readable Kubernetes Service name for this subscription's internal ClusterIP endpoint (design doc docs/V2Plan/111-internal-naming-and-region.md §7.2) -- e.g. postgres, never the FQDN and never the s-{uuid} form (§7.3). null is the correct, common answer, not a disabled state: it means no provisioned ClusterIpService exists yet for this subscription, or its slug does not qualify as a DNS-1035 label (a leading digit -- Slug::parse allows one, Kubernetes does not). A null must not be read as "this address is unreachable": absence here says only that there is no name to offer at all. Reachability from elsewhere is a separate, pairwise question this field does not answer by itself (§7.1) -- compare region below against the region of whatever would be connecting to it (e.g. the subscription that owns the field this value would be pasted into); the two share a Kubernetes cluster only when their regions match. Kernel does not compute or return that verdict directly, since a single subscription's own read never holds both sides of the comparison.
parent_subscription_idZC-0984: the bundle this subscription is a member of, or null for
a bundle itself and for every ordinary, standalone subscription.
The region this subscription's workload is placed in. null before a hardware profile has resolved (never yet activated, or the profile row itself no longer resolves). Compare id against another subscription's region.id to decide whether internal_address above would resolve from there -- see that field's own doc comment.
trial_converted_atWhen billing converted the trial to a paid subscription. Null until conversion.
trial_ends_atThe persisted trial deadline, or null for a subscription without a trial.
Whether this lapsed free trial can still be bought (ZC-0782). Null for anything that is not an unconverted free trial past its end -- an ordinary subscription, a running trial, or one already bought. available carries the deadline; payment_pending means a purchase invoice is open (resume paying it); closed means the three days are over and the trial is being deleted.
The tax on the next renewal, computed by kernel. Present only on the single-subscription read (getSubscription); null in listings, and when the renewal cannot be calculated (no tax code resolves, or the Price is gone).
Get Attack Summary
What Warden filtered for the caller's own services on one UTC day: episode count, mitigated time, peak rate, blocked traffic, why it was blocked, a per-service breakdown and a timeline. A quiet day answers 200 with zeros. Scoped to service instances of organizations the caller owns, exactly as the daily attack digest email is. Never carries source addresses, topology or gate names.
path Parameters
dateThe UTC day, YYYY-MM-DD.
The UTC day, YYYY-MM-DD.
Get Attack Summary › Responses
The day's summary
attacker_estimateattacksblocked_bytesblocked_packetsdateThe UTC day, YYYY-MM-DD.
mitigated_secondspeak_bits_per_secondservices_stayed_onlineAbsent when continuity cannot be stated honestly from our own measurements.
Set Subscription Cancellation
Decides whether this subscription stops at the end of the period it has already been paid for. cancel_at_period_end: true schedules the end and answers with the exact instant in cancels_at; false withdraws a scheduled end and puts the subscription back into service. Unless the staff-only effective_immediately is sent this is not an immediate cancellation, and it never moves money. The service keeps running until the scheduled moment, no invoice is raised or voided, and nothing is credited to the wallet. It also does not change auto_renew, which is returned so a client can see that for itself. Idempotent -- sending the decision already in force succeeds and answers changed: false, which a client must not render as a failure, and a repeated request never moves an existing cancels_at. Refused with a business-rule error for a subscription with no paid period to run out (pending, terminated, cancelled or failed), for one an administrator has cancelled, which the customer may not reinstate, and for a scheduled end whose moment has already passed. Answered 409 when the decision moved underneath the request, which is retryable and most often means a cancellation landed while this withdrawal was in flight. A suspended subscription cannot be cancelled at period end -- that would put a service stopped for non-payment, or an expired free trial, back into service until the period closed -- and a suspended free trial awaiting deletion cannot withdraw that deadline: both answer 409 with code subscription_suspended and change nothing. Settling what is owed lifts the suspension; staff can still end a suspended subscription with effective_immediately: true. Requires the role that may buy for this organization (Owner or Admin), not merely the authority to change what runs inside it; a restricted API token needs subscriptions.cancel on the organization (or globally), and organizations.purchase does not open it. Staff holding ManageProvisioning on an elevated session may also call it for any organization, which is how a customer's billing is stopped from the admin page; such a call is audited as staff. effective_immediately: true is the staff-only variant that ends the subscription now rather than at the close of the paid period -- 403 for anyone else, and 422 when it is sent with cancel_at_period_end: false. An immediate end cannot be withdrawn afterwards by anybody.
path Parameters
idSet Subscription Cancellation › Request Body
cancel_at_period_endtrue to stop this subscription at the end of the period already
paid for, false to withdraw a scheduled end and keep it running.
effective_immediatelyStaff only (ZC-0747). true ends the subscription now instead
of at the close of the paid period: cancels_at is written at the
present instant, which the reaper takes on its next tick.
Defaults to false, so a customer's request means exactly what it
meant before this field existed and a staff member who does not ask
for it gets the same safe answer. Sending true without the staff
system permission is 403; sending it alongside
cancel_at_period_end: false is 422, because withdrawing an end and
taking one now are contradictory instructions rather than a pair.
It is not withdrawable afterwards, by anyone. The moment has
passed by the time any later request arrives, and a passed deadline is
refused -- which is /v1's "cancelled by an administrator and cannot
be reinstated", reached through the deadline rather than the status.
Set Subscription Cancellation › Responses
The subscription's cancellation as it now stands
auto_renewThe renewal setting, untouched by this write and returned so a client can see that for itself. Scheduling an end does not turn renewal off: the billing engine skips every subscription that is not active, so the status alone already stops the next invoice, and leaving this alone is what makes withdrawing the end restore exactly the arrangement that was in force. Change it through PUT /subscriptions/{id}/renewal.
changedWhether this request is what changed the decision. false means it already said this -- a retry, or somebody else deciding the same thing first. Both are successes; a client must not render false as a failure. On a retry the existing cancels_at is returned unchanged: a repeated request never moves the customer's end date.
statusThe subscription's commercial status, which this write does move
-- unlike the renewal decision beside it. pending_termination after
scheduling, active after withdrawing.
subscription_idcancels_atWhen this subscription stops. Non-null exactly when status is pending_termination: the two are written in one statement and cannot disagree. Ordinarily it is the close of the billing period the subscription is currently in, computed from its own anchor and cadence, so it is the same instant the renewal invoice would otherwise have been raised. For a staff cancellation sent with effective_immediately it is the present instant instead. Until this moment passes the decision can be withdrawn by sending cancel_at_period_end: false; after it, it cannot.
List Database Tables
Lists every table in one database, addressed by the database's own id. The same route serves a shared database and a dedicated one: this surface does not model how the database was provisioned, only which database it is.
Each entry carries its columns, its primary key and the engine's own size estimates. row_estimate, data_length and index_length are the ENGINE'S estimates, not counts: they are what information_schema reports and can be stale or absent, so render them as approximations and never as a row count. keyset_cursor_column names the column row paging will seek on, and is null for a table that has no usable one, which is what makes listDatabaseTableRows fall back to offset paging there.
truncated is true when the database has more tables than one listing describes. There is no cursor: the engine answers the whole schema in one query, and paging it inside kernel would report a different thing than the database knows.
404 for an unknown database id, for a database belonging to somebody else, and for a database the caller deleted, which are deliberately the same answer.
path Parameters
database_idThe database's own id, whatever kind of database it is.
The database's own id, whatever kind of database it is.
List Database Tables › Responses
Every table in the database, with its columns
databaseThe database's own name on its server, which is the root a browser draws the tree under.
truncatedCreate Database Table
Creates a table from engine-agnostic column definitions (integer, decimal, float, text, boolean, date_time, date, time, json, binary, uuid), which each engine renders in its own dialect. At least one column is required. Refused with 507 when the database has used up its storage quota.
path Parameters
database_idThe database's own id, whatever kind of database it is.
The database's own id, whatever kind of database it is.
Create Database Table › Request Body
nameCreate Database Table › Responses
Created
Get Database Table
One table's schema: the same entry listDatabaseTables publishes, for a single table, so a client opening one table does not have to fetch and filter the whole schema.
404 for a table that is not there, for a database that is not there, and for one belonging to somebody else. A database with more tables than one listing describes (truncated) also answers 404 for the ones past that ceiling, which the listing has already told the client about.
path Parameters
table_nameThe table's name, exactly as listDatabaseTables reported it.
The table's name, exactly as listDatabaseTables reported it.
database_idThe database's own id, whatever kind of database it is.
The database's own id, whatever kind of database it is.
Get Database Table › Responses
The table's columns, primary key and size estimates
databaseDrop Database Table
Drops a table and all of its rows. Permanent: it cannot be undone. Always allowed, including on a database over its quota.
path Parameters
table_nameThe table's name, exactly as listDatabaseTables reported it.
The table's name, exactly as listDatabaseTables reported it.
database_idThe database's own id, whatever kind of database it is.
The database's own id, whatever kind of database it is.
Drop Database Table › Responses
Dropped
Alter Database Table
Applies a list of structural operations to one table: add, drop, rename or modify a column, or rename the table. At least one operation is required. Refused with 507 when the database has used up its storage quota.
path Parameters
table_nameThe table's name, exactly as listDatabaseTables reported it.
The table's name, exactly as listDatabaseTables reported it.
database_idThe database's own id, whatever kind of database it is.
The database's own id, whatever kind of database it is.
Alter Database Table › Request Body
Alter Database Table › Responses
Altered
List Database Table Rows
One page of one table's rows, with optional sorting and filtering.
limit defaults to 50 and is CLAMPED to 500 rather than refused, so a client asking for more gets the most it may have; the page states the limit it was actually served, and a smaller number than was sent means it was clamped. cursor is the opaque next_cursor from the previous page and is never constructed by hand.
sort is column, column:asc or column:desc. filters is a JSON-encoded array of {"column", "operator", "value"}, where operator is one of equals, not_equals, contains, starts_with, ends_with, greater_than, less_than, greater_than_or_equal, less_than_or_equal, is_null, is_not_null; the last two take no value. A sort or filters that does not parse, or that names a column the table does not have, is refused: it is never silently dropped, because an unfiltered page answering a filtered request looks like it worked.
pagination_mode says how the page was produced. keyset seeks on the table's keyset_cursor_column and is stable while rows are being written; offset is used when no such column exists and can repeat or skip a row if the table changes between pages; single_page means the whole result fitted and there is nothing to page. Use has_more and next_cursor rather than comparing the row count to limit.
This route reads; writing a row is insertDatabaseTableRow, updateDatabaseTableRow and deleteDatabaseTableRow.
path Parameters
table_nameThe table's name, exactly as listDatabaseTables reported it.
The table's name, exactly as listDatabaseTables reported it.
database_idThe database's own id, whatever kind of database it is.
The database's own id, whatever kind of database it is.
query Parameters
cursorfiltersJSON-encoded array of filter objects (operator, column, value).
JSON-encoded array of filter objects (operator, column, value).
limitRows per page. Defaults to 50, clamped to 500.
Rows per page. Defaults to 50, clamped to 500.
sortFormat: "column" (asc) or "column:asc" / "column:desc".
Format: "column" (asc) or "column:asc" / "column:desc".
List Database Table Rows › Responses
One page of rows
databaseInsert Database Table Row
Inserts one row. values maps column names to values; columns are validated against the table's metadata, so a name the table does not have is refused. Refused with 507 when the database has used up its storage quota. Requires the authority to change the organization's projects.
path Parameters
table_nameThe table's name, exactly as listDatabaseTables reported it.
The table's name, exactly as listDatabaseTables reported it.
database_idThe database's own id, whatever kind of database it is.
The database's own id, whatever kind of database it is.
Insert Database Table Row › Responses
The number of rows inserted
databaseDelete Database Table Row
Deletes one row, found by the value of the table's single-column primary key. Always allowed, including on a database over its quota: deleting is how a customer recovers.
path Parameters
table_nameThe table's name, exactly as listDatabaseTables reported it.
The table's name, exactly as listDatabaseTables reported it.
database_idThe database's own id, whatever kind of database it is.
The database's own id, whatever kind of database it is.
Delete Database Table Row › Responses
The number of rows deleted
databaseUpdate Database Table Row
Updates one row, found by the value of the table's single-column primary key. A table with no primary key, or a composite one, cannot be edited this way. Refused with 507 when the database has used up its storage quota.
path Parameters
table_nameThe table's name, exactly as listDatabaseTables reported it.
The table's name, exactly as listDatabaseTables reported it.
database_idThe database's own id, whatever kind of database it is.
The database's own id, whatever kind of database it is.
Update Database Table Row › Request Body
primary_key_valueArbitrary JSON.
Update Database Table Row › Responses
The number of rows updated
databaseGet Database Usage
How much storage the database uses against its quota: data and index bytes as the engine reports them, and the quota in bytes (null for a database that has none, such as a dedicated one). over_quota_since is set while the database is locked read-only for exceeding its quota; deleting data releases it.
The figure is cached for up to a minute and refreshed by any write made through this API.
path Parameters
database_idThe database's own id, whatever kind of database it is.
The database's own id, whatever kind of database it is.
Get Database Usage › Responses
The database's storage usage and quota
How full a database is.
databaseExecute Database SQL
Runs ONE raw SQL statement against the database, as the database's own user, so it can do anything that user can to its own database. A statement that returns rows answers {kind: "rows"} capped at 200 rows (truncated says when it was cut); any other answers {kind: "command", affected_rows}. The statement is cancelled after 15 seconds. Refused with 507 when the database has used up its storage quota, since raw SQL is not restricted to statements that shrink it. The statement is recorded in the organization's audit feed.
path Parameters
database_idThe database's own id, whatever kind of database it is.
The database's own id, whatever kind of database it is.
Execute Database SQL › Responses
The statement's result set or affected-row count
databaseList Service Endpoints
The public ports of a service: first the ones asked for at purchase that are not open yet (pending, with a pending_reason and nothing billed), then every port the service ever held, newest first, with its public address and port while it is active. A released port is kept so a month's bill can be read against it. The list also carries what an https add control needs: https_limit and https_count, domain_limit and domain_count (so the add buttons can disable themselves), and https_zone / https_host_suffix (the zone a new free host lands in, to preview <label>.<https_host_suffix>). Each https endpoint's domains carry a url, a failure code while failed, and the DNS record (dns) to create. Console only.
path Parameters
idproject_idList Service Endpoints › Responses
The service's public ports
domain_countCustomer domains attached now.
domain_limitThe most customer domains one service may hold, across all its https endpoints
(domain_limit when exceeded).
https_countHttps endpoints open now (pending purchase requests are not counted).
https_limitThe most https endpoints one service may hold open. An add button disables itself when
https_count reaches it; the add is refused with https_limit past it.
https_host_suffixWhat follows the label in a free host, zone.<zone>.zaroz.cloud: preview the address as
<label>. plus this. Present exactly when https_zone is. Before an endpoint exists the
label is optional and the endpoint's id names the host.
https_zoneThe zone the free address of a new https endpoint lands in, e.g. hel1. Absent when the
service has no placement to read yet.
Add Service Endpoint
Opens one endpoint on the service, of one of three kinds. kind: port (the default, so a request without a kind means what it always did) opens a raw TCP/UDP public port: send the container port and the protocol (tcp, udp or tcp_udp); Zaroz assigns the public address and port, which come back on the response. Ports beyond the plan's included ones are billed by the hour they are held, monthly in arrears. kind: unit opens a raw port like port but one per unit: every unit of a scaled Container gets its own public address and port for that container port, reaching that unit alone, and a new unit gets its own when it is added. The address stays the same across the unit's restarts and is released when the unit is scaled away; each is billed like a port, and removing one removes the same port from every unit. GET units lists each unit's addresses. kind: https publishes a website or API (WebSockets included): send the container port, and optionally a host label and the customer's own domains. It is served on a free platform host (https.host) with automatic TLS, the app serving plain HTTP; each domain must be one the organization has verified or a subdomain of one, exactly as for a Web App, and a domain that later loses verification stops being served. An https endpoint is free and never metered, and all or nothing: one refused domain opens nothing. A refusal names a reason code before the colon in details: not_ready (the service is not running yet), port_limit (the plan's ports are all used), port_in_use (that container port is already open with that protocol, or already has an https endpoint, or a per-unit port), no_address_available and no_port_available (nothing free right now), internal_port_out_of_range, unknown_protocol, protocol_required, invalid_host_label, host_taken, https_limit, and for a domain invalid_domain, platform_domain, domain_taken, domain_not_verified, domain_limit. Console only.
path Parameters
idproject_idAdd Service Endpoint › Request Body
internal_portThe port the service listens on inside the container, 1 to 65535.
domainshttps only: the customer's own domains to serve on this endpoint. Each must be a
domain the organization has verified, or a subdomain of one, exactly as for a Web App;
certificates are issued automatically. All or nothing: one refused domain opens
nothing. More can be added later.
kindport (the default, so a request written before kinds existed means what it always
did), unit (a raw port per unit, see Add Service Endpoint) or https.
labelhttps only: the label of the free host (<label>.zone.<zone>.zaroz.cloud), one DNS
label. Omitted, the host is named after the endpoint's id.
For port and unit: tcp, udp, or tcp_udp for one public number on both; required. For
https: omit it (always TCP, TLS ends at the platform and the app serves plain HTTP);
tcp is accepted.
Add Service Endpoint › Responses
The opened endpoint: its public address for a port, its host and domains for an https endpoint
created_atWhen the port was opened, or, while pending, when it was asked for.
idThe id to DELETE. For a pending request this is the request's id.
internal_portThe port the service listens on inside the container.
kindport (raw TCP/UDP, billed), unit (a raw port that reaches one unit, billed like a
port) or https (a host and domains, free).
protocolThe protocols one endpoint carries. TcpUdp is one endpoint, one price,
over one allocation carrying both labels ([PortProtocol::Both]).
The host and domains of an https endpoint. Absent for a port, which has the
public_* fields instead.
last_public_ipThe public address the port had, once it is closed, so a month's bill can be read against it. Absent while the port is open, while it is pending, and for a port closed before the address was kept.
last_public_portThe public port the closed port had. Present exactly when last_public_ip is.
Why the port is not open yet. Present only while state is pending.
public_ipThe public address, while the port is open.
public_portThe public port Zaroz assigned, while the port is open.
released_atWhen the port was closed.
unit_ordinalThe unit slot a unit endpoint reaches. Absent for the other kinds.
Remove Service Endpoint
Closes one endpoint. A raw port stops its billing from that moment (nothing was prepaid, so there is nothing to refund); an https endpoint takes down its host, its customer domains and their certificates. The id is the one the listing returned; for a port that was asked for at purchase and is still pending it withdraws the request. Closing a port that is already closed succeeds. An id that is not one of this service's ports, including one belonging to another service, is a 404: the same answer either way. Console only.
path Parameters
idproject_idendpoint_idRemove Service Endpoint › Responses
Removed
Add Service Endpoint Domain
Serves one more of the customer's own domains on an https endpoint, with an automatic certificate. The domain must be one the organization has verified, or a subdomain of one: the same rule and the same certificate issuance as a Web App's custom domain. Attaching a domain already attached to this endpoint returns it. Until the certificate is issued the domain reports pending; point its DNS at the platform for issuance to succeed. A raw port, a closed endpoint and another service's endpoint are a 404. A refusal names its code before the colon in details: 400 invalid_domain for a name that is not a domain, and 422 platform_domain, domain_taken, domain_not_verified, domain_limit, not_ready. Console only.
path Parameters
idproject_idendpoint_idAdd Service Endpoint Domain › Request Body
domainA domain the organization has verified, or a subdomain of one.
Add Service Endpoint Domain › Responses
The attached domain with its state
domainidThe id to DELETE .../endpoints/{endpoint_id}/domains/{id}.
Verification state of what is served on it: the domain itself was verified for the organization before it could be attached (a domain that loses verification stops being served and disappears from here); this is the route and certificate.
urlhttps:// plus domain.
The DNS record the customer creates so the domain reaches this endpoint. Present on reads of an endpoint once its free host is known; absent on the response to attaching a domain (read the endpoint again).
Why the domain is failed: a stable code and a sentence. Present only while status is
failed. certificate_failed (usually DNS not pointing at the platform yet) or
route_failed.
Remove Service Endpoint Domain
Stops serving one customer domain on an https endpoint and removes its certificate; the domain can be attached again later. The id is the one the endpoint's https.domains returned. A domain that is not on this endpoint, including one of another endpoint or service, is a 404: the same answer either way. Console only.
path Parameters
idproject_idendpoint_idroute_idThe id the endpoint's https.domains returned.
The id the endpoint's https.domains returned.
Remove Service Endpoint Domain › Responses
Removed
Set Service Endpoint Domain Paths
Replaces the ordered path routes of one customer domain on an https endpoint, so app.com can reach one service and app.com/api another. Each path names an open https endpoint of a service in the same project and whether to strip the path before the request reaches it. The longest matching path wins and the endpoint the domain is attached to answers everything else. The whole set is replaced: send an empty list to remove every path. Returns the effective routing the new set produces. A refusal names its code before the colon in details: 400 invalid_path (grammar), target_not_found (another project's, a missing and a closed endpoint answer alike); 422 path_limit, duplicate_path, target_not_http. A domain that is not on this endpoint is a 404. Console only.
path Parameters
idproject_idendpoint_idroute_idThe id the endpoint's https.domains returned.
The id the endpoint's https.domains returned.
Set Service Endpoint Domain Paths › Request Body
Set Service Endpoint Domain Paths › Responses
The domain's effective routing after the change
hostpath_limitThe most path routes one domain may carry.
In the order they are evaluated; the last is always the default.
Every service that answers some part of the domain, with the paths it serves.
Present when the request carried ?path=.
Get Service Endpoint Domain Routing
How a customer domain routes now: its rules in the order they are evaluated, each with the exact rule, priority, target service and its state, and a status (serving, starting, shadowed when another rule with the same path always wins, broken when the target cannot answer); the certificate state, which covers the whole domain; and every service that uses the domain with the paths it serves. With ?path=/api/users it also says which rule takes that request and what path the target receives. An invalid path is a 400 invalid_sample_path. Console only.
path Parameters
idproject_idendpoint_idroute_idThe id the endpoint's https.domains returned.
The id the endpoint's https.domains returned.
query Parameters
pathA request path to trace, like /api/users?x=1: which rule takes it and what the target
receives. The query string is ignored.
A request path to trace, like /api/users?x=1: which rule takes it and what the target
receives. The query string is ignored.
Get Service Endpoint Domain Routing › Responses
The domain's effective routing
hostpath_limitThe most path routes one domain may carry.
In the order they are evaluated; the last is always the default.
Every service that answers some part of the domain, with the paths it serves.
Present when the request carried ?path=.
Set Subscription Renewal
Decides whether this subscription is charged again when its current period ends. This is not a cancellation. Setting auto_renew to false stops the next invoice and nothing else: the subscription keeps its status, no end date is scheduled, and the service keeps running. A customer who wants the service to stop, rather than the billing, wants PUT /subscriptions/{id}/cancellation instead. Idempotent -- sending the value already stored succeeds and answers changed: false, which a client must not render as a failure. Refused with a business-rule error for a subscription that has no next period to decide about (already ending, terminated, cancelled or failed), and for one paid once under a lifetime price, which has no renewal at all. A suspended subscription may stop renewing but may not start again: suspension is the platform's consequence for an unpaid or disputed invoice and it turns renewal off as part of itself, so resuming it goes through lifting the suspension. Answered 409 when the setting moved underneath the request, which is retryable. Requires the role that may buy for this organization (Owner or Admin), not merely the authority to change what runs inside it; a restricted API token needs subscriptions.renewal.manage on the organization (or globally), and organizations.purchase does not open it.
path Parameters
idSet Subscription Renewal › Request Body
auto_renewtrue to be charged again when the current period ends, false to
stop after it.
Set Subscription Renewal › Responses
The subscription's renewal setting as it now stands
auto_renewchangedWhether this request is what changed the setting. false means it already said this -- a retry, or somebody else deciding the same thing first. Both are successes; a client must not render false as a failure.
statusThe subscription's commercial status, unchanged by this write.
Returned so a client can see that for itself rather than take it on
trust: turning renewal off is not a cancellation, and an Active
subscription is still Active afterwards.
subscription_idcancels_atWhen this subscription is scheduled to end. Unchanged by this route, which is why it is returned: turning renewal off is not a cancellation, and a client can see here that no end was scheduled. It is non-null only for a subscription somebody scheduled to end through PUT /subscriptions/{id}/cancellation, which is the only writer of this field.
Quote a subscription resize
Prices a shape change against the subscription's own pinned price without committing to it, and reports per dimension whether stock currently allows growing it. Writes nothing and reserves nothing -- the stock read is a live, non-reserving preview, so it can go stale by the time POST .../resize is called. Send a full target shape, not a delta: a dimension left unchanged is sent at its current value. cpu, memory and storage may all change in one request, each up or down (storage only up), within the product's own minimum and maximum. Growth is priced now; a reduction is free and reported with downsize_applies_at, the end of the current billing period.
path Parameters
idQuote a subscription resize › Request Body
The target shape a resize names, in the same units CheckoutResourcesRequest
already uses -- see that type's own doc comment. A resize always names a
full target shape, not a delta: the dimension a customer does not want
to change is simply sent at its current value. Any of the three may change
in the same request, each up or down (storage only up); a request replaces
any reduction scheduled earlier, so send a scheduled dimension at its
scheduled value to keep it.
Quote a subscription resize › Responses
What the resize would cost, and whether stock allows the growth
downsize_applies_atWhen the shrinking dimensions take effect: the end of the current billing period, right before the next renewal is priced at the smaller shape. null when nothing shrinks.
Request a subscription resize
Requests a shape change for this subscription: cpu, memory and storage together, each up or down (storage only up), within the product's own minimum and maximum. The GROWING dimensions reserve capacity for 30 minutes and raise a Pending Resize invoice for the prorated difference -- pay it through the existing invoice-id-keyed payment endpoints, and the growth applies once payment settles. The SHRINKING dimensions are never billed and never credited: they are scheduled (scheduled_downsize) and take effect at the end of the current billing period, right before the next renewal is priced at the smaller shape. A request replaces any reduction scheduled earlier. Requires the role that may buy for this organization (Owner or Admin); a restricted API token needs orders.billing_resize.manage on the organization (or globally), as every resize route does.
path Parameters
idRequest a subscription resize › Request Body
The target shape a resize names, in the same units CheckoutResourcesRequest
already uses -- see that type's own doc comment. A resize always names a
full target shape, not a delta: the dimension a customer does not want
to change is simply sent at its current value. Any of the three may change
in the same request, each up or down (storage only up); a request replaces
any reduction scheduled earlier, so send a scheduled dimension at its
scheduled value to keep it.
Request a subscription resize › Responses
The invoice to pay for a growth, and/or the scheduled reduction
Decision Table
| Variant | Matching Criteria |
|---|---|
| type = object · requires: outcome, invoice | |
| type = object · requires: outcome, scheduled_downsize |
A minimal, self-contained invoice summary for a resize response --
deliberately not the full InvoiceResponse from kernel-http-v2-billing
(a cross-crate dependency this feature crate does not otherwise carry):
enough for a client to know what it owes and pay it through the existing
invoice-id-keyed payment endpoints, nothing more.
outcomeCancel a subscription resize
Cancels this subscription's pending resize, if any. For a pending GROWTH, voids its Pending invoice and releases the capacity hold it took, in one transaction. For a scheduled DOWNSIZE, drops it; the running service is never touched, since a downsize only ever changes it at the end of the billing period. Both are cancelled when both are pending. Refuses with 409 only when the one thing pending is a growth whose invoice has already been paid, since money has moved and the growth is on its way to being applied. Idempotent: calling this when nothing is pending answers 204, the same status a successful cancel answers.
path Parameters
idCancel a subscription resize › Responses
The pending resize (if any) was cancelled, or there was none to cancel -- both answer the same way
Quote a subscription plan change
Prices a change to another of this product's own authored catalog plans (plan_id, from GET /catalog/products/{id}/plans) against the subscription's own pinned price, without committing to it -- the plan-change equivalent of resize/quote. Refused if this product's ResizePolicy does not offer a self-service plan change, or if plan_id does not name one of this product's own active, storefront-visible plans.
path Parameters
idQuote a subscription plan change › Request Body
plan_idQuote a subscription plan change › Responses
What the plan change would cost, and whether stock allows the growth
downsize_applies_atWhen the shrinking dimensions take effect: the end of the current billing period, right before the next renewal is priced at the smaller shape. null when nothing shrinks.
Request a subscription plan change
Requests a change to another of this product's own authored catalog plans (plan_id, from GET /catalog/products/{id}/plans). For a GROWTH, reserves capacity for 30 minutes and raises a Pending Resize invoice for the prorated difference, exactly like POST .../resize. Dimensions the plan makes smaller are not billed and take effect at the end of the current billing period. Refused if this product's ResizePolicy does not offer a self-service plan change, if plan_id does not name one of this product's own active, storefront-visible plans, or if the plan has less storage than the service runs today (storage only grows).
path Parameters
idRequest a subscription plan change › Request Body
plan_idRequest a subscription plan change › Responses
The invoice to pay for a growth, or the scheduled downsize record
Decision Table
| Variant | Matching Criteria |
|---|---|
| type = object · requires: outcome, invoice | |
| type = object · requires: outcome, scheduled_downsize |
A minimal, self-contained invoice summary for a resize response --
deliberately not the full InvoiceResponse from kernel-http-v2-billing
(a cross-crate dependency this feature crate does not otherwise carry):
enough for a client to know what it owes and pay it through the existing
invoice-id-keyed payment endpoints, nothing more.
outcomeBatch Service Instance Runtime Stats
Returns live uptime, CPU (millicores) and memory (bytes) for the primary workload of each requested service instance, so a page of service cards fills its runtime chips in one request. Replaces /v1's POST /orders/runtime-stats. At most 50 ids are read (the first 50, repeats dropped). An instance the caller may not see, one whose subscription is no longer served, and one the cluster could not read is omitted from the answer rather than refused, so the response never reveals which ids exist.
query Parameters
idsComma-separated service instance ids. Anything that is not a UUID is ignored, as is an id the caller may not see.
Comma-separated service instance ids. Anything that is not a UUID is ignored, as is an id the caller may not see.
Batch Service Instance Runtime Stats › Responses
Only instances the caller may see and the cluster answered for appear; an instance with no reading is absent, never zero.
List Scanner Subscriptions
Lists the subscriptions of every product scoped to the manage_zaroz_scanner permission (product_staff_scopes), newest first, paginated, each with its status, product, current billing period, organization, owning user (id, display name, email) and a display name. Requires manage_zaroz_scanner; an elevated session is NOT required, and API tokens of every kind are refused. Read-only, and carries no price or billing data.
query Parameters
pagePage number (1-indexed). Defaults to 1.
Page number (1-indexed). Defaults to 1.
page_sizeNumber of items per page. Defaults to 20, max 100.
Number of items per page. Defaults to 20, max 100.
statusNarrows the list to one commercial status. Omitted returns every status.
Narrows the list to one commercial status. Omitted returns every status.
List Scanner Subscriptions › Responses
Scanner subscriptions
Pagination metadata included in paginated responses
Get Scanner Subscription
Gets one subscription of a product scoped to manage_zaroz_scanner. A subscription of any other product answers 404, indistinguishable from one that does not exist. Same gate as the list: manage_zaroz_scanner, no elevated session, no API tokens.
path Parameters
idGet Scanner Subscription › Responses
The subscription
created_atdisplay_nameThe organization's name, with a distinct owner's name in parentheses.
idThe subscription id, which is the tenant key.
product_idproduct_slugstatusnull when the subscription is not billing (pending or ended).
null when the organization has no owner left.
List My Service Instances
Lists the signed-in customer's own service instances across every organization they may see -- the organizations they hold a membership in, plus their personal organization (same scope listMySubscriptions uses). There are no orders in /v2: this is the customer-scoped replacement for /v1's GET /api/v1/orders, keyed on subscription_id, never on an order id.
run_state and availability are read from the database, not a live cluster call: run_state folds each instance's own resources' last recorded statuses (the same fold the live status stream uses), and availability reports whether the platform can currently resolve a cluster for the instance's hardware profile, not whether that cluster answered a live health check. A cluster that cannot be resolved for one row never fails the rest of the list.
query Parameters
pagePage number (1-indexed). Defaults to 1.
Page number (1-indexed). Defaults to 1.
page_sizeNumber of items per page. Defaults to 20, max 100.
Number of items per page. Defaults to 20, max 100.
project_idNarrows the list to one project. Omitted returns every service instance the caller may see, including those not yet attributed to a project.
Narrows the list to one project. Omitted returns every service instance the caller may see, including those not yet attributed to a project.
List My Service Instances › Responses
The caller's own service instances, paginated
Pagination metadata included in paginated responses
Get Service Instance
Gets one running service the caller may see.
path Parameters
idGet Service Instance › Responses
The service instance
created_atidnameproject_idThe project this service is addressed under. Its slug is unique here, not platform-wide.
How much CPU, memory and storage this service is currently configured with (ZC-1287). The same shape MyServiceInstanceSummaryResponse carries per row, published here because until now it was carried ONLY there -- on the route that returns every service the caller owns. A client that wants one service's size had to page the caller's whole inventory to find three numbers, and that listing filters by project_id only, so there was no way to ask about one. That blocked the resize screen, whose form has to open showing what the customer already has. This is the configured shape, which is what the customer bought and what a resize names a full target against -- not a live measurement of what the workload is using. GET .../resources/{resource_id}/volume is where a measurement lives.
slugsubscription_idupdated_atSet only while the debt ladder holds this service stopped (V-0482): own_debt when its organization has an unpaid balance, restricted when it is frozen because of a debt elsewhere (contact the organization's owner). null otherwise, and always null on routes other than GET ./service-instances and GET ./service-instances/{id}. Never identifies the debtor.
operating_system_idFor a VPS, the id of the operating system it runs, as listed by GET /api/v2/catalog/products/{id}/operating-systems (V-0671). A client uses it to offer only reinstall targets with the same monthly fee. null for every other service.
This subscription's pending resize (ZC-1332), or null when there is none. GET .../service-instances/{id} is the only route that populates this -- every other route returning this same shape (rename, reprovision, ...) always answers null here rather than resolving it, since none of them has a reason to.
Update Service Instance
Renames and/or re-slugs one running service. Omitted fields are left unchanged. Renaming never moves the slug: a slug change is a separate, explicit field, because it moves every URL pointing at the service.
path Parameters
idUpdate Service Instance › Request Body
nameslugUpdate Service Instance › Responses
The instance as stored
created_atidnameproject_idThe project this service is addressed under. Its slug is unique here, not platform-wide.
How much CPU, memory and storage this service is currently configured with (ZC-1287). The same shape MyServiceInstanceSummaryResponse carries per row, published here because until now it was carried ONLY there -- on the route that returns every service the caller owns. A client that wants one service's size had to page the caller's whole inventory to find three numbers, and that listing filters by project_id only, so there was no way to ask about one. That blocked the resize screen, whose form has to open showing what the customer already has. This is the configured shape, which is what the customer bought and what a resize names a full target against -- not a live measurement of what the workload is using. GET .../resources/{resource_id}/volume is where a measurement lives.
slugsubscription_idupdated_atSet only while the debt ladder holds this service stopped (V-0482): own_debt when its organization has an unpaid balance, restricted when it is frozen because of a debt elsewhere (contact the organization's owner). null otherwise, and always null on routes other than GET ./service-instances and GET ./service-instances/{id}. Never identifies the debtor.
operating_system_idFor a VPS, the id of the operating system it runs, as listed by GET /api/v2/catalog/products/{id}/operating-systems (V-0671). A client uses it to offer only reinstall targets with the same monthly fee. null for every other service.
This subscription's pending resize (ZC-1332), or null when there is none. GET .../service-instances/{id} is the only route that populates this -- every other route returning this same shape (rename, reprovision, ...) always answers null here rather than resolving it, since none of them has a reason to.
Get Service Instance Capabilities
Lists what this running service can do: the structural capabilities read off its own resources, and the behavioural ones its product declares.
path Parameters
idGet Service Instance Capabilities › Responses
Every capability this instance exposes: the structural ones derived from its own resources, and the behavioural ones its product declares. Structural wins on a collision.
Decision Table
| Variant | Matching Criteria |
|---|---|
| type = object · requires: capability | |
| type = object · requires: capability | |
| type = object · requires: capability | |
| type = object · requires: capability | |
| type = object · requires: capability | |
| type = object · requires: capability, root_path | |
| type = object · requires: capability | |
| type = object · requires: capability | |
| type = object · requires: capability, mount_path, resource_id | |
| type = object · requires: capability | |
| type = object · requires: capability | |
| type = object · requires: capability, verbs | |
| type = object · requires: capability | |
| type = object · requires: capability | |
| type = object · requires: capability, id, url +1 more | |
| type = object · requires: capability, url, resource_id +1 more | |
| type = object · requires: capability, secrets_allowed | |
| type = object · requires: capability | |
| type = object · requires: capability | |
| type = object · requires: capability | |
| type = object · requires: capability | |
| type = object · requires: capability | |
| type = object · requires: capability | |
| type = object · requires: capability |
capabilityGet Service Instance Features
Lists the product features this running service's product declares: what only the product understands, such as a game's player roster, as opposed to the platform capabilities listed by the sibling capabilities route. Ids only; a client keys its own panels and copy off them. Grants nothing: each feature's own route enforces its own access.
path Parameters
idGet Service Instance Features › Responses
The features this instance's product declares, possibly none.
Get Service Instance Minecraft Inventory
Lists the jars currently in this Minecraft instance's mods/ or plugins/ folder, merged against kernel's own background-resolved cache. The listing never waits on a hash or on Modrinth: a jar kernel has not resolved yet is returned immediately with state: "resolving", and reappears already resolved (or unresolved, with a reason) on a later read once the background resolver has caught up. Read-only -- installing a mod or plugin still goes through the Files capability. 404 when the product does not declare a matching mods/plugins feature, or when the stored loader has no jar-based inventory at all (Vanilla), the same answer a service belonging to somebody else gives.
path Parameters
idGet Service Instance Minecraft Inventory › Responses
Every jar currently in the folder, with whatever kernel knows about it.
Unordered, matching DirectoryListingResponse::entries's own
contract: sorting is the panel's.
kindWhich inventory this is. Mirrors [InventoryKind]'s own two values; a
third, "none", never reaches the wire because the route answers 404
instead (see the controller).
Start Service Instance
Starts the workloads this service owns. Explicit rather than a /v1-style toggle(active): a boolean states what the caller believes the current state to be, so two concurrent callers who both read "running" are indistinguishable from one stopping and another starting. Refused with 404 when the owning subscription is suspended, cancelled, terminated or failed -- notably a suspended subscription, which only a payment can lift. It is an opaque 404 rather than a business-rule 422 on purpose (R7), and it is decided after authorization so it cannot tell a stranger an instance exists. A subscription that is merely Pending gets the business-rule 422 instead, from the domain. Refused with 409 operation-in-progress while another operation holds this service, or 409 workload-busy when the service's units are being converged by another pass and the wait ran out (retry shortly); the response names which operation and when it started, so a caller can tell "a restore is running" from "something is broken". While a backup is being restored the code is restore-in-progress instead, and the service status reports the restore as its in-flight operation until it finishes.
path Parameters
idStart Service Instance › Responses
The verb that ran, and for each workload it acted on the recorded status it left from and the one it is heading to. Intent, not observation: whether the workload got there, and every later transition, arrives on GET /service-instances/{id}/status/stream.
actionThe verb that ran. Echoed so a client holding several in-flight answers, or a log of them, needs no request to interpret one.
Every workload the verb acted on, in the order it acted. Never empty: an instance with nothing to act on is refused with a 422 instead. More than one entry only when a product's blueprint produces several switchable primaries, all of which a lifecycle verb switches together.
service_instance_idStop Service Instance
Stops the workloads this service owns. Data volumes are untouched -- this powers the service off, it does not cancel or delete anything. Refused with 404 when the subscription is suspended, cancelled, terminated or failed -- the same opaque answer every other route gives for those, so it cannot tell a stranger an instance exists. Note this route is narrower than the domain rule behind it: a suspended subscription MAY be stopped in principle, and the admin route still does, but a customer suspended for non-payment is refused every lifecycle verb here. Refused with 409 operation-in-progress while another operation holds this service; the response names which operation and when it started, so a caller can tell "a restore is running" from "something is broken". While a backup is being restored the code is restore-in-progress instead, and the service status reports the restore as its in-flight operation until it finishes.
path Parameters
idStop Service Instance › Responses
The verb that ran, and for each workload it acted on the recorded status it left from and the one it is heading to. Intent, not observation: whether the workload got there, and every later transition, arrives on GET /service-instances/{id}/status/stream.
actionThe verb that ran. Echoed so a client holding several in-flight answers, or a log of them, needs no request to interpret one.
Every workload the verb acted on, in the order it acted. Never empty: an instance with nothing to act on is refused with a 422 instead. More than one entry only when a product's blueprint produces several switchable primaries, all of which a lifecycle verb switches together.
service_instance_idRestart Service Instance
Restarts the workloads this service owns in place, without passing through a stopped state a client has to observe. /v1 has no restart at all, so a customer wanting one sends stop and then start and races whatever runs in between; this is the whole reason the /v2 surface is three verbs rather than a toggle. Leaves the recorded desired state alone: a restart does not turn a stopped service on. Refused with 409 operation-in-progress while another operation holds this service, or 409 workload-busy when the service's units are being converged by another pass and the wait ran out (retry shortly); the response names which operation and when it started, so a caller can tell "a restore is running" from "something is broken". While a backup is being restored the code is restore-in-progress instead, and the service status reports the restore as its in-flight operation until it finishes.
path Parameters
idRestart Service Instance › Responses
The verb that ran, and for each workload it acted on the recorded status it left from and the one it is heading to. Intent, not observation: whether the workload got there, and every later transition, arrives on GET /service-instances/{id}/status/stream.
actionThe verb that ran. Echoed so a client holding several in-flight answers, or a log of them, needs no request to interpret one.
Every workload the verb acted on, in the order it acted. Never empty: an instance with nothing to act on is refused with a 422 instead. More than one entry only when a product's blueprint produces several switchable primaries, all of which a lifecycle verb switches together.
service_instance_idReprovision Service Instance
Queues a teardown and re-render of every Kubernetes object this service owns, from the configuration currently saved on it. keep_data: true keeps the data volume(s) and re-attaches them; keep_data: false deletes and re-creates them empty.
keep_data: false destroys this service's data volumes and cannot be undone. Nothing in kernel can bring them back; only an offsite backup taken beforehand can. The field is required rather than defaulted precisely so that a request which lost it in transit is a 400 and not a wipe.
Public endpoints survive the teardown: External Services, their port allocations and their datapath entries are retained, because an ip:port is something the customer has already handed out -- to players, to a DNS record, to a webhook provider.
This is not POST /api/v2/service-instances/{id}/deployments. That route re-renders over what is already running and has no destructive arm; this one deletes first.
Answers 202 with an operation id, not the outcome. The rebuild runs on a durable queue so it survives a kernel restart mid-rebuild; poll GET /api/v2/service-instances/{id}/operations/{operation_id} with the id this response carries until status leaves pending/processing. The underlying rebuild still takes an exclusive lease over the service's power state, data volume and specification, so a queued reprovision waits its turn behind a backup, a restore, a deployment or another rebuild already holding this service rather than being refused outright.
path Parameters
idReprovision Service Instance › Request Body
keep_datatrue keeps the volumes and rebuilds everything around them. false
destroys this service's data volumes and cannot be undone -- only
an offsite backup taken beforehand can bring them back.
Required. See this type's doc comment for why it has no default.
Reprovision Service Instance › Responses
The queued operation's id, for polling its status
operation_idThe queued row's id. Poll GET .../operations/{operation_id} with
it until status leaves pending/processing.
service_instance_idGet Service Instance Operation
Reads one queued operation's current status -- today, only ever a reprovision queued by POST .../reprovision. status starts pending, moves to processing while a worker holds it, and settles at completed or dead_letter (the retry budget spent). dead_letter still means the underlying rebuild may have partially applied; last_error carries a fixed step code, never a provider or database error string. A read only -- it never extends or steals a worker's lease, so polling this on an interval is always safe.
path Parameters
idoperation_idGet Service Instance Operation › Responses
The operation's current status
attemptskindThe operation's own wire kind, e.g. "service_instance_reprovision".
A plain string rather than a closed response enum: this route is
generic over every kind the Provisioning queue ever carries, not
reprovision-specific, and a new kind must not need a new response
type to be readable through it.
max_attemptsoperation_idservice_instance_idstatusMirrors kernel_domain::domain::operations::OperationStatus 1:1, kept as
its own /v2 response type for the reason every other mirrored enum in
this file is: a rename on the domain enum must not silently change a wire
value.
completed_atSet once status reaches completed. Still None for
dead_letter: exhausting the retry budget is not a completion, and a
client polling for a timestamp here would wait forever on a row that
has already stopped trying.
last_errorA fixed step code ("unroutable:keep_data", "provision", ...),
never a provider or database error string -- see
ProcessOperationError::step (kernel-tasks), which is what writes
this column. None while the operation has never failed an attempt.
List Service Instance Activity
Lists what happened to this service, most recent first. A member of the owning organization reads it; a service-share holder needs the activity permission. Platform-internal events are excluded structurally, and so are the per-open console and file-session tickets: only what the owner did to the service is listed, and the pagination total counts that same set. A Zaroz staff member's action is flagged actor_is_staff and carries no staff identity.
path Parameters
idquery Parameters
actionExact match on the action name, e.g. service.restarted.
Exact match on the action name, e.g. service.restarted.
pagePage number (1-indexed). Defaults to 1.
Page number (1-indexed). Defaults to 1.
page_sizeNumber of items per page. Defaults to 20, max 100.
Number of items per page. Defaults to 20, max 100.
List Service Instance Activity › Responses
Activity entries
Pagination metadata included in paginated responses
List Service Shares
The live shares of this service: who it is shared with (the address the owner typed, plus status pending or accepted, and the member's username and avatar_asset_id once the grantee has accepted) and what each may do. Owner or Admin of the owning organization only; anyone else who can see the service gets 403, anyone who cannot gets 404.
path Parameters
idList Service Shares › Responses
The live shares, oldest first, and the per-service limit
limitHow many live shares one service may carry.
Share Service
Shares this service with one person, by email, with a list of permissions (console, files, power, settings, databases, database_browse, database_rows, database_schema, external_access, schedules, billing; seeing the service is implied). billing reads this subscription's invoices, resizes it and withdraws a scheduled cancellation, never cancels, renews or pays. An address an account has verified gets access at once, any other waits until an account verifies it; either way the answer is the same pending share with no member details, and it turns accepted in the list once the grantee opens Shared with me. A share never makes anyone a member of the organization, never shows its members or other services, and cannot be re-shared. Owner or Admin of the owning organization only, on a product that offers sharing (shareable in the service's capabilities; otherwise 404). 409 already_shared when the address already has a live share here, 409 share_limit_reached past the per-service limit, 429 past 20 new shares an hour per service or 60 per user, 422 cannot_share_with_self for the caller's own address.
path Parameters
idShare Service › Request Body
emailThe person's email address. An address an account has verified is shared with that account at once, any other waits until an account verifies it and opens "Shared with me".
What the person may do, besides seeing the service: any of console, files,
power, settings. Empty is allowed and means "may see it is up".
Share Service › Responses
The new share
created_atemailidservice_instance_idstatuspending until the grantee opens the share in their own list, then accepted.
updated_atavatar_asset_idThe member's avatar asset (/assets/{id}); null until accepted or when they have none.
usernameThe member's username; null until the share is accepted.
Revoke Service Share
Revokes a share. The grantee's very next request is refused, including any new console, terminal, logs, framebuffer or files ticket; a ticket already minted lives out its own short validity (seconds to a few minutes), and a terminal already attached stays open until it disconnects. Owner or Admin of the owning organization only.
path Parameters
idshare_idRevoke Service Share › Responses
Revoked
Update Service Share
Replaces what a share permits. Takes effect on the grantee's next request. Owner or Admin of the owning organization only; 404 for a share that is not a live share of this service.
path Parameters
idshare_idUpdate Service Share › Request Body
The complete new set, replacing the old one.
Update Service Share › Responses
The share
created_atemailidservice_instance_idstatuspending until the grantee opens the share in their own list, then accepted.
updated_atavatar_asset_idThe member's avatar asset (/assets/{id}); null until accepted or when they have none.
usernameThe member's username; null until the share is accepted.
List Services Shared With Me
The services shared with the caller, each with its granted permissions and the owner's display name, and nothing else about the owner. Also claims any share addressed to the caller's verified email that was waiting for an account, so a person who signs up after being shared with finds it here. A service that has ended is not listed. Each row carries the service's live resources (id, kind, role, status) that the console, files, logs and metrics routes are addressed by. Open one through the ordinary /service-instances/{id}/... routes, within its permissions.
List Services Shared With Me › Responses
The caller's live shares
Get Service Instance Setup
Whether provisioning is still waiting for this service to be configured. awaiting_configuration is true while the service has been paid for and provisioning is still waiting for its ServiceConfiguration to be written -- through PUT .../source for a product that needs one. Retired: this route used to also return the product's authored setup schema and the customer's redacted answers, and accepted a PUT submitting them; both are gone.
path Parameters
idGet Service Instance Setup › Responses
Whether this service is still awaiting configuration
awaiting_configurationTrue while provisioning is still waiting for a configuration. A service in this state has been paid for and has no workload running.
service_instance_idGet Service Instance Setup Steps
Lists this service's declared post-checkout setup steps, in the product's own declaration order, each with its own TYPED params (tagged by step, {"step": "none"} for a step that reads none) and its stored answers (null when unanswered). A product declaring no steps answers with an empty steps list and awaiting_configuration: false, not a 404. awaiting_configuration is true while at least one declared step has never been answered -- the same gate provisioning itself checks before it will render this service's workload for the first time. 404 for a service belonging to somebody else, the same answer an invented id gives.
path Parameters
idGet Service Instance Setup Steps › Responses
Every declared step, its params, and its answers if any
awaiting_configurationWhether provisioning is still waiting on at least one of these steps. A product declaring no steps is never awaiting one.
Answer Service Instance Setup Step
Answers one setup step this service's product declares. The body's own step tag must match the path segment, or the request is refused with a 400. Refused with 404 for a step the product does not declare, the same answer a service belonging to somebody else gives. apply is kernel's verdict about what landing this answer costs the running service: live when the submitted answers are unchanged from what is already stored, in which case nothing is saved and nothing rolls out; otherwise restart. Answering the LAST unanswered step a product declares is what starts this service's first provisioning -- until then, saving is all a write can do, because a product still missing an answer has nothing coherent to render. Once every declared step is answered, this same route re-renders an already-running service exactly the way a capability configuration write does elsewhere, and takes the same configuration-change lease so the two cannot collide; it is refused with 409 while another such operation holds this service. pending is true when the answer was saved but the (re)provisioning attempt itself failed -- the value is still stored, and a later read or another answer can still succeed. The audit entry names the step and the verdict, never the answers. For server_passwords, answers.passwords maps each password's id to either {"generate": true} (kernel mints it; refused for a password the product marked non-generatable) or {"value": "..."} (a supplied value, checked and encrypted before it is stored); the id may be a subset of the product's declared passwords, leaving the rest untouched. The response never contains a value or a ciphertext for this step, only which ids are now set -- reveal it with its own request. For minecraft_software, every network-checkable value (the Minecraft version and, for Forge/NeoForge, the loader version; the Modrinth project id; the FTB pack id) is checked against the same providers GET .../setup/steps/{step}/options/{field} renders, and refused with a 400 naming the value when it is confirmed not to exist. An upstream outage never refuses the save -- it is accepted and logged instead, the same way a value this route cannot check (a custom loader jar/URL) always was. For app_runtime, the request names only runtime, variant, and start_command; the product's own runtime table resolves and freezes image and install_command at this moment, and neither is ever settable by the caller -- a later edit to the table changes nothing for this answer until it is saved again. For vm_access, the response never contains the password, only password_set: true; ssh_authorized_keys is raw multi-line OpenSSH text on the way in and a normalised list on the way out; Windows always overwrites username to Administrator and ignores every SSH/timezone field regardless of what is submitted, and a Linux answer that would leave the guest with no way in (ssh_password_auth: false with no keys) is refused with a 400. Refused with 409 for a step whose params lock after the first answer once one is already stored (app_admin's install_only; no step in this slice locks yet).
path Parameters
idstepAnswer Service Instance Setup Step › Request Body
Decision Table
| Variant | Matching Criteria |
|---|---|
| type = object · requires: step, answers | |
| type = object · requires: step, answers | |
| type = object · requires: step, answers | |
| type = object · requires: step, answers | |
| type = object · requires: step, answers | |
| type = object · requires: step, answers | |
| type = object · requires: step, answers | |
| type = object · requires: step, answers | |
| type = object · requires: step, answers | |
| type = object · requires: step, answers | |
| type = object · requires: step, answers | |
| type = object · requires: step, answers | |
| type = object · requires: step, answers |
SetupStepId::MinecraftSoftware's
answers.
stepAnswer Service Instance Setup Step › Responses
The stored answers for this step, and what landing them cost
One step's answers as a RESPONSE (GET .../setup/steps,
PUT .../setup/steps/{step}'s own echo). Same tag shape as
[SetupStepAnswersDto] for the three Minecraft steps, whose answers hold
nothing secret and so render identically either direction; NEVER the
same shape for [Self::ServerPasswords], which reports only which ids
are set, never a value or a ciphertext -- see
[ServerPasswordsResponseDto].
What landing this answer cost the running service. live when the
submitted answers matched what was already stored.
awaiting_configurationWhether provisioning is still waiting on at least one declared step after this write.
pendingTrue when this answer completed the product's declared steps and (re)provisioning was started, but the attempt itself failed. The answer is still saved; a later read or retry can still succeed.
The closed vocabulary of setup steps kernel knows how to ask, validate and
render. Adding a member is a reviewed code change here, in the dashboard's
step registry, and in whichever product template starts reading its
variables -- the same "closed set, matched code change" discipline
[crate::domain::product_definitions::capabilities::CapabilityId] uses,
for the same reason: a step nothing implements is a claim the platform
cannot back.
Ord is derived so this can key a BTreeMap
([StepAnswersDocument::steps]): declaration order becomes iteration
order there, which is incidental (the document is always looked up by
key, never walked in order) but harmless.
List Service Instance Setup Step Options
Renders one setup-step field's OPTIONS -- what a customer may pick from -- separate from what they submit (PUT .../setup/steps/{step}; see that route's own admission behaviour). Only minecraft_software's version, loader_version, modrinth_project and ftb_pack_id fields, and fivem_server's artifact_channel (the fivem_builds provider: recommended, optional and latest, each with its current build as detail; custom is a typed build id, not an option), have a provider today; every other field (and any step or field this product does not declare) is refused with 404, the same answer a service belonging to somebody else gives. loader_version's options require loader (forge or neoforge) and version (the Minecraft version already chosen) as query parameters; missing or unsupported values are a 400. q searches Modrinth/FTB modpacks (trimmed, at most 64 characters) and is rate-limited per caller, since every request fans out to a third party we do not control; the other two fields read an already-cached manifest and are not. degraded is true when the upstream this field depends on (Mojang, Forge, NeoForge, Modrinth, FTB, or Cfx.re) could not be reached and options is stale or empty -- informational only, and never a reason by itself to refuse a later save.
path Parameters
fieldidstepquery Parameters
loaderforge or neoforge. Required for loader_version's options;
ignored by every other field.
forge or neoforge. Required for loader_version's options;
ignored by every other field.
qSearch text for the two search-shaped providers (Modrinth, FTB). Trimmed and capped at 64 characters; ignored by every other provider.
Search text for the two search-shaped providers (Modrinth, FTB). Trimmed and capped at 64 characters; ignored by every other provider.
snapshotsWhether version's options include snapshot builds. Defaults to
false (stable releases only); ignored by every other field.
Whether version's options include snapshot builds. Defaults to
false (stable releases only); ignored by every other field.
versionThe Minecraft version already chosen. Required for
loader_version's options; ignored by every other field.
The Minecraft version already chosen. Required for
loader_version's options; ignored by every other field.
List Service Instance Setup Step Options › Responses
The field's renderable options
degradedTrue when the upstream this field's provider depends on (Mojang,
Forge, NeoForge, Modrinth, or FTB) could not be reached and options
is either stale or empty. Never a reason by itself to refuse a save
-- see [AnswerSetupStepResponse]'s own admission behaviour.
cached_atWhen the underlying data was last fetched from the upstream, or
null when nothing could be served at all (a fully degraded, empty
result).
Reveal Service Instance Setup Password
Returns one server_passwords password's plaintext, once, and records that it was read. Its own request rather than folded into the setup-steps read, so the ordinary read stays structurally incapable of leaking a value and so the audit entry covers exactly the act that needs it. Gated on the same access as answering a setup step, not on the access to read one: an ordinary member who may see this service's setup answers may not read a password back. 404 for a service belonging to somebody else, a product that does not declare server_passwords, or a password id with no stored answer -- the same answer an invented id gives. 409 for a password the product marked "revealable": false (its own internal credential, never meant to be read back).
path Parameters
idpassword_idReveal Service Instance Setup Password › Responses
The password's plaintext
idvalueRotate Service Instance Setup Password
Rotates one server_passwords password to a freshly kernel-generated value and (re)renders the running service under it, the same configuration-change lease every other setup-step write takes; refused with 409 while another such operation holds this service, and also with 409 for a password the product marked "rotatable": false (kernel-generated but owned by the application afterwards -- rotating it here would desynchronize kernel's stored value from what the application actually has). Refused with 400 for a password the product marked non-generatable -- rotating a customer-supplied value would silently replace what they typed. Never returns the new value; read it back with the reveal request. 404 for a service belonging to somebody else, a product that does not declare server_passwords, or a password id with no stored answer.
path Parameters
idpassword_idRotate Service Instance Setup Password › Responses
What landing the rotation cost the running service
What landing the rotation cost the running service. Always restart
in slice 1c (see [kernel_core::domain::setup_steps::apply_mode]'s
own doc comment: any change to any setup step's answers is
Restart), carried as the same typed value the other setup-step
responses use rather than hardcoding the string here.
idpendingTrue when the rotation was saved but the reprovision attempt itself
failed. The same pending vocabulary every other setup-step and
capability write already uses.
Get Subscription Bucket
Gets the subscription's bucket: its S3 endpoint and bucket name, cap, public-read setting, the access the data plane allows right now (open, read_only over the cap, suspended, deleted) and the latest measured size. 404 when the subscription has no bucket.
path Parameters
idGet Subscription Bucket › Responses
The bucket
Create Subscription Bucket
Creates the subscription's bucket in a region with a storage cap (default 100 GiB, 1 GiB to 100 TiB). One bucket per subscription: a second is refused with 409. Only an active subscription may create (422). region_id defaults to the region of the subscription's price. Requires the same authority as buying a subscription for this organization.
path Parameters
idCreate Subscription Bucket › Request Body
cap_bytesStorage cap in bytes, 1 GiB to 100 TiB. Absent takes 100 GiB. Above the cap the keys turn read-only until usage falls or the cap is raised.
labelDisplay name. Blank or absent becomes "Bucket".
region_idWhere the bucket lives. Defaults to the region of the subscription's price; when the price names a region this must match it.
Create Subscription Bucket › Responses
The created bucket
Delete Subscription Bucket
Deletes the subscription's bucket. Its keys stop working at once and the slot frees immediately, but the data stays for a recovery window (seven days) before a background task purges it for good. Requires the same authority as buying a subscription for this organization.
path Parameters
idDelete Subscription Bucket › Responses
Scheduled for deletion
Update Subscription Bucket
Updates the bucket's label, storage cap or public-read setting; absent fields are left alone. A cap change and a public-read change reach the data plane at once. Not allowed once the bucket is scheduled for deletion (422). Requires the same authority as buying a subscription for this organization.
path Parameters
idUpdate Subscription Bucket › Request Body
cap_byteslabelpublic_readServe the bucket's objects to anonymous readers.
Update Subscription Bucket › Responses
The updated bucket
List Subscription Bucket Keys
Lists the bucket's active access keys, oldest first. Secrets are never returned after creation.
path Parameters
idList Subscription Bucket Keys › Responses
The active keys
Create Subscription Bucket Key
Creates a named access key, read_only or read_write. The secret is in this response only: it is never stored in readable form and cannot be shown again. At most twenty active keys per bucket (429). A key created while the bucket is suspended is inert until service resumes. Requires the same authority as buying a subscription for this organization.
path Parameters
idCreate Subscription Bucket Key › Request Body
scoperead_only or read_write.
nameDisplay name. Blank or absent becomes "Key".
Create Subscription Bucket Key › Responses
The key and its one-time secret
secret_access_keyRevoke Subscription Bucket Key
Revokes one access key: it stops working at once, along with every presigned URL signed with it. Another bucket's key, an unknown id and an already revoked key all answer 404. Requires the same authority as buying a subscription for this organization.
path Parameters
key_ididRevoke Subscription Bucket Key › Responses
Revoked
Get Subscription Bucket Usage
The bucket's measured usage over a window (default: this month so far, at most 93 days): hourly stored-byte and traffic samples, the window's average stored size in GiB-months and the bytes sent out, which are the two billed meters.
path Parameters
idquery Parameters
fromStart of the window, inclusive. Defaults to the start of this month.
Start of the window, inclusive. Defaults to the start of this month.
toEnd of the window, exclusive. Defaults to now.
End of the window, exclusive. Defaults to now.
Get Subscription Bucket Usage › Responses
The usage
Get Subscription Registry
Gets the subscription's container registry: its login host, namespace and image prefix, cap, the access it allows right now (open, read_only over the cap, suspended, deleted) and the latest measured size. 404 when the subscription has no registry.
path Parameters
idGet Subscription Registry › Responses
The registry
Create Subscription Registry
Creates the subscription's container registry in a region with a spend cap (default 100 GiB, 1 GiB to 100 TiB). One registry per subscription: a second is refused with 409. Only an active subscription may create (422). region_id defaults to the region of the subscription's price. Requires the same authority as buying a subscription for this organization.
path Parameters
idCreate Subscription Registry › Request Body
cap_bytesSpend cap in bytes of stored images, 1 GiB to 100 TiB. Absent takes 100 GiB. Above it pushes are refused until usage falls or the cap is raised; pulls and deletes keep working.
labelDisplay name. Blank or absent becomes "Registry".
region_idWhere the registry lives. Defaults to the region of the subscription's price; when the price names a region this must match it.
Create Subscription Registry › Responses
The created registry
Delete Subscription Registry
Deletes the subscription's registry. Its credentials stop minting tokens at once and the slot frees immediately, but the images stay for a recovery window (seven days) before a background task purges them for good. Requires the same authority as buying a subscription for this organization.
path Parameters
idDelete Subscription Registry › Responses
Scheduled for deletion
Update Subscription Registry
Updates the registry's label or spend cap; absent fields are left alone. A cap change takes effect at the next token request. Not allowed once the registry is scheduled for deletion (422). Requires the same authority as buying a subscription for this organization.
path Parameters
idUpdate Subscription Registry › Request Body
cap_byteslabelUpdate Subscription Registry › Responses
The updated registry
List Subscription Registry Credentials
Lists the registry's active credentials, oldest first. Secrets are never returned after creation.
path Parameters
idList Subscription Registry Credentials › Responses
The active credentials
Create Subscription Registry Credential
Creates a named robot credential: pull, push (pull and push) or admin (pull, push and delete). The secret is in this response only: it is never stored in readable form and cannot be shown again. At most twenty active credentials per registry (429). Requires the same authority as buying a subscription for this organization.
path Parameters
idCreate Subscription Registry Credential › Request Body
scopepull, push (pull and push) or admin (pull, push and delete).
nameDisplay name. Blank or absent becomes "Credential".
Create Subscription Registry Credential › Responses
The credential and its one-time secret
secretThe password to log in with.
Revoke Subscription Registry Credential
Revokes one credential: it mints no further tokens, and a token already issued lapses within five minutes. Another registry's credential, an unknown id and an already revoked credential all answer 404. Requires the same authority as buying a subscription for this organization.
path Parameters
credential_ididRevoke Subscription Registry Credential › Responses
Revoked
List Subscription Registry Repositories
Lists the repositories under the registry's namespace, as the data plane reports them.
path Parameters
idList Subscription Registry Repositories › Responses
The repositories
Delete Subscription Registry Repository
Deletes one repository (every tag) by its path below the registry's namespace; the storage is reclaimed by the data plane's garbage collection. A path that is not a valid repository path is refused with 422. Requires the same authority as buying a subscription for this organization.
path Parameters
idquery Parameters
pathThe repository path below the registry's namespace, e.g. app/web.
The repository path below the registry's namespace, e.g. app/web.
Delete Subscription Registry Repository › Responses
Deleted
Get Subscription Registry Usage
The registry's measured usage over a window (default: this month so far, at most 93 days): hourly stored-byte samples (logical bytes), the window's average stored size in GiB-months and the bytes served out, which are the billed meters.
path Parameters
idquery Parameters
fromStart of the window, inclusive. Defaults to the start of this month.
Start of the window, inclusive. Defaults to the start of this month.
toEnd of the window, exclusive. Defaults to now.
End of the window, exclusive. Defaults to now.
Get Subscription Registry Usage › Responses
The usage
List Subscription Shared Databases
Lists this subscription's active shared databases, oldest first. Each entry carries its own connection details and credentials -- this is the screen a customer copies them from. Ten free 64 MiB databases per subscription (owner ruling ZC-0006); an empty list is normal. Dashboard only.
path Parameters
idList Subscription Shared Databases › Responses
The subscription's active shared databases
Create Subscription Shared Database
Creates one shared database on the subscription's entitlement, with a 64 MiB quota. Refused with 429 (quota-exceeded) once the subscription already holds ten -- see GET .../entitlement to check first. region_id is strict when given: a region with no enabled host for the chosen engine is refused (503) rather than placed elsewhere; omit it to place on the least-loaded host for that engine anywhere. Only an active subscription may create (422 otherwise). Requires the same authority as buying a subscription for this organization.
path Parameters
idCreate Subscription Shared Database › Request Body
enginemariadb or postgres; see GET .../shared-databases/engines for
which are available right now.
display_nameThe customer's own label. Blank or absent becomes "Database N".
region_idPlace it in this region. Strict when given: a region with no enabled
host for engine is refused rather than silently placed elsewhere.
Absent places it on the least-loaded host for engine.
Create Subscription Shared Database › Responses
The created shared database, with its credentials
Get Subscription Shared Database Entitlement
Reports where this subscription stands against its shared-database entitlement: how many of its ten free 64 MiB databases it holds now, and how many remain. held is a real count, never assumed from the limit.
path Parameters
idGet Subscription Shared Database Entitlement › Responses
Usage against the entitlement
heldActive databases the subscription holds now. A real count.
limitThe entitlement: 10.
quota_bytes_eachEach database's quota in bytes: 67108864 (64 MiB).
remaininglimit - held, never below zero.
List Subscription Shared Database Engines
Lists the shared database engines with at least one enabled host right now -- what POST .../shared-databases will accept as engine. Gated on being able to read this subscription even though the answer is platform-wide, so a client can fetch it alongside the create form without a second authorization surface.
path Parameters
idList Subscription Shared Database Engines › Responses
Available engines
enginesList Subscription Shared Database Regions
Lists the enabled region and engine pairs with at least one enabled host right now -- what POST .../shared-databases will accept as region_id for a given engine. Gated on being able to read this subscription even though the answer is platform-wide, for the same reason GET .../engines is.
path Parameters
idList Subscription Shared Database Regions › Responses
Available region and engine pairs
Delete Subscription Shared Database
Deletes one of the subscription's shared databases. Its entitlement slot frees at once; the database itself lingers on its host for a short recovery window before a background task drops it. Another subscription's database, or an unknown id, both answer 404 -- the two are deliberately indistinguishable. Requires the same authority as buying a subscription for this organization.
path Parameters
database_ididDelete Subscription Shared Database › Responses
Deleted
Rotate Subscription Shared Database Credentials
Replaces one shared database's password on its host, then in its stored credentials, and returns it with the new password. The username and connection addresses do not change. Another subscription's database, or an unknown id, both answer 404. Requires the same authority as buying a subscription for this organization.
path Parameters
database_ididRotate Subscription Shared Database Credentials › Responses
The database with its new credentials
Start Shared Database Export
Queues an export of this shared database's data to a JSON dump. Postgres only today (422 for mariadb) -- see crates/domain/operations/src/domain/shared_databases/transfer.rs for why. Answers 202 with an operation id, not the outcome. Poll GET .../transfers/{operation_id} with it until status leaves pending/processing, then GET .../transfers/{operation_id}/download for the bytes. The dump carries row data only, never CREATE TABLE DDL -- restoring it with POST .../transfers/import requires the destination's tables to already exist. Requires the same authority as buying a subscription for this organization.
path Parameters
database_ididStart Shared Database Export › Responses
The queued export's operation id, for polling its status
allocation_idoperation_idStart Shared Database Import
Queues an import of a previously completed export's dump into this shared database. source_operation_id must name a completed export queued for a database on THIS SAME subscription (404 otherwise, indistinguishable from an invented id) -- possibly a different database than this one, which is how this route implements "transfer": export one shared database, then import into another. The destination's tables must already exist with the same names and columns the export recorded; a row for a table that does not exist fails the whole operation. Answers 202 with an operation id, not the outcome. Poll GET .../transfers/{operation_id} with it. Requires the same authority as buying a subscription for this organization.
path Parameters
database_ididStart Shared Database Import › Request Body
source_operation_idStart Shared Database Import › Responses
The queued import's operation id, for polling its status
allocation_idoperation_idUpload Shared Database Dump
Queues an import of an uploaded SQL dump into this shared database, as /v1 did. The request body is the raw file (plain SQL, or gzipped SQL as .sql.gz; PostgreSQL pg_dump --format=plain including COPY .. FROM stdin blocks, or mysqldump). It is streamed to storage, never held in memory, and capped at 256 MiB (422 over it). The format is checked from the file's first bytes: an empty file, a binary file, a pg_dump -Fc archive or a Zaroz JSON export (import those by operation id instead) is a 422. The database must have storage left (507 when it is locked over quota; the import also stops, failed, if it fills the quota while restoring). Statements run as the database's own user, in order, stopping at the first error, so a failed import can leave the statements before it applied. USE, CREATE|DROP|ALTER DATABASE and PostgreSQL ALTER .. OWNER TO statements are skipped; DELIMITER lines (stored routines and triggers) are honoured. Answers 202 with an operation id, not the outcome. Poll GET .../transfers/{operation_id}. Requires the same authority as buying a subscription for this organization.
path Parameters
database_ididUpload Shared Database Dump › Responses
The queued import's operation id, for polling its status
allocation_idoperation_idGet Shared Database Transfer Operation
Reads one queued export or import's current status. status starts pending, moves to processing while a worker holds it, and settles at completed or dead_letter (the retry budget spent). A read only -- it never extends or steals a worker's lease, so polling this on an interval is always safe.
path Parameters
database_ididoperation_idGet Shared Database Transfer Operation › Responses
The operation's current status
allocation_idattemptskind"shared_database_export" or "shared_database_import".
max_attemptsoperation_idstatusMirrors kernel_domain::domain::operations::OperationStatus 1:1, kept as
its own /v2 response type for the reason every other mirrored enum in
this file is: a rename on the domain enum must not silently change a wire
value.
completed_atlast_errorDownload Shared Database Transfer
Streams a completed export's JSON dump. Refused with 422 (business-rule-violation) while the export has not finished yet -- poll GET .../transfers/{operation_id} first. An import's operation id, another subscription's operation, or an invented id all answer the same 404.
path Parameters
database_ididoperation_idDownload Shared Database Transfer › Responses
no content
Stream Service Instance Status
Holds a text/event-stream open for one service instance the caller may see, so a workspace shows its live state without polling. Replaces /v1's GET /orders/{id}/status/stream. Answers 404 for an instance the caller does not reach, and equally for one whose subscription is suspended, terminated, cancelled or failed: this route reads the cluster, and a service that is no longer being served has no live state to report. Four frames, addressed by the SSE event: name. status carries the whole picture -- the aggregate run state, which of the product's declared lifecycle verbs make sense to click right now, the operation kernel is currently carrying out against the service (a deploy, a restart, a reprovision, ...) when one is in flight, every visible resource with its live usage, container statuses and memory pressure, the in-guest readiness gate where the product has one, and crash or startup-failure detail while the service is in those states. It is sent on connect, whenever a resource's status changes, and on a five-second tick, because usage and container statuses are live cluster reads that no event announces. network_metrics and resource_metrics carry one sample each, pushed as the collector records it; they are a live tail, not a history, and the resource metrics read is what a chart should backfill from. vm_progress reports a virtual machine's bring-up phase while one is being built. The server closes the connection after fifteen minutes and the first frame sets the reconnect interval, so a browser EventSource re-opens it by itself; the caller's access is also re-checked periodically while the connection is held.
path Parameters
idStream Service Instance Status › Responses
An open event stream. The schema describes the data: payload of one status frame, not a single JSON response body, and not the two metrics frames or the vm_progress frame, which carry their own shapes.
Which of the product's declared [Capability::Lifecycle] verbs make
sense to click right now (ZC-1154): the console renders that
static list as its full set of buttons (a stopped container still
offers Stop, greyed, because the workload kind supports it), and
this is the subset that should render live. It never adds a verb the
static list omits.
The intersection of three independent answers, all required:
- the product's declared
Capability::Lifecycleverb list (what the workload kind supports at all, structural, read off its own resources); - [
kernel_core::domain::provisions::ServiceRuntimeState::permits_lifecycle_verb] (whether the verb does something sensible given the workload's live condition --stateabove, converted); and - [
SubscriptionStatus::permits_lifecycle_verb] (whether the customer is commercially entitled to ask for it right now).
A verb missing from any one of the three is not permitted. This is
deliberately a new field and state is unchanged: the frontend
entitlement decision console/components/apps/bg-status-vocabulary.ts
tried to own client-side is a decision this list now makes instead,
but console still needs both fields -- one to render the full,
disabled set, one to know which of them are live -- and adding a
field to an SSE payload is backward compatible where removing state
would not be.
The instance's visible resources. Empty is normal: a per-seat licence
provisions none (design doc §8.1), and so does an instance whose
workloads have not been applied yet, which is what state: NotProvisioned says.
stateOne word for the whole service, folded from its primary workloads' statuses (or, when it declares none, from all of them).
Live crash detail while state is CrashLooping. Absent otherwise,
and absent while crash looping if the cluster could not be reached
inside the bounded timeout.
Live startup-failure detail while state is Failed because the
workload never started (e.g. an image whose declared user cannot be
verified non-root). Carries the kubelet's own reason and message so a
customer is told why rather than left on a perpetual "Starting".
The in-guest first-boot gate, where the product has one (a Windows
VPS). null means there is no gate, not that the guest is not
ready: a consumer treating absence as "not ready" would never show a
Linux service as usable.
The operation kernel is currently carrying out against this service,
if any (ZC-1162). null is the common case: nothing is happening.
This is the field that answers "is a deploy happening right now",
which state cannot: state: Provisioning does not distinguish a
first-time bring-up from an in-place redeploy or reprovision, and a
rolling update leaves the old pods serving, so state stays Running
for the whole deployment and never signals anything happened at all
(found while building ZC-1154). Kernel already tracks this fact as a
typed, leased operation (kernel_core::domain::service_operations);
this is that fact surfaced, not a new one invented for the stream.
A new field, like permitted_lifecycle_verbs above and for the
same reason: adding a field to an SSE payload is backward compatible,
changing state is not.
Purchase Subscription Trial
Buys a free trial. A trial still running is bought as an upgrade: the free period ends at payment and the paid period starts then, on the same running service, with nothing stopped or reprovisioned (the remaining free days are given up). A trial that ended without being kept is suspended with its data intact and deleted three days after it ended; until then it is bought as a restore, which brings the same service back. Price it first with GET /subscriptions/{id}/trial/purchase/quote. It moves no money: pay the returned invoice with POST /billing/invoices/{id}/pay-with-wallet or a card checkout on that invoice. Once the payment settles the subscription is active and paid from that moment and renewal is turned on; a restored trial's workload is started again, an upgraded one's keeps running untouched. If the trial ends before an upgrade invoice is paid it stays payable as a restore, unless the trial converts on renewal, which cancels it. Idempotent -- while the invoice is unpaid a repeated request answers 200 with the same invoice and created: false; the first answers 201. An invoice whose checkout failed or expired is replaced by a new one. Answered 409 with code trial_purchase_window_closed once the three days are over (no invoice is raised), trial_already_converted for a trial already bought, and trial_purchase_already_paid while a paid purchase is completing; 409 without those codes when another purchase request for the same subscription is in flight, which is retryable. 422 for a subscription that is not a buyable free trial. Requires the authority to pay this organization's invoices by card: its purchase role or its Billing role. Returns 404 for a subscription the caller cannot see.
path Parameters
idPurchase Subscription Trial › Responses
The purchase invoice an earlier request raised, still unpaid
amount_centsPre-tax amount, in cents.
createdtrue when this request raised the invoice (201), false when it handed back the invoice an earlier request raised (200). Both are success; a client must not render the second as a failure.
currencydeadlineThe moment the trial is handed over for deletion. Payment must be settled before it; a payment already in progress is honoured for a bounded time past it.
invoice_idThe one payable purchase invoice for this trial.
upgrade for a trial still running (the paid period starts at
payment, on the same running service), restore for a lapsed one.
subscription_idtotal_amount_centsAmount including tax, in cents -- what the customer pays.
Quote Subscription Trial Purchase
Prices buying this free trial without raising anything: an upgrade of a trial still running (the free period ends at payment and the paid period starts then, on the same running service) or a restore of a lapsed one. One period of the trial's pinned price at the caller's own price, tax included, computed by the same code POST /subscriptions/{id}/trial/purchase raises its invoice with. Promotional credit is applied only when that invoice is issued and can only lower it. While a purchase invoice is open this answers that invoice exactly and names it in open_invoice_id. Readable by anybody who can see the subscription; buying needs the organization's purchase or billing role. The same refusals as the purchase: 409 trial_purchase_window_closed, trial_already_converted, trial_purchase_already_paid, and 422 for a subscription that is not a buyable free trial. Returns 404 for a subscription the caller cannot see.
path Parameters
idQuote Subscription Trial Purchase › Responses
What the purchase charges
amount_centsPre-tax amount, in cents.
currencydeadlineWhen the offer lapses: the trial's own end for an upgrade, the moment the trial is handed over for deletion for a restore.
Which way a free trial is bought (V-0153).
subscription_idtax_amount_centsTax, in cents.
total_amount_centsAmount including tax, in cents -- what the purchase charges.
open_invoice_idThe purchase invoice already raised and still payable, whose figures these are; null when buying would raise a new one.
tax_labeltax_rateThe tax rate applied, as a fraction (0.21), when there is one.
List Unit Logs
A page of the stored output of this service's units, read from the log store: all units merged by instant, or one with unit_id (live or scaled away, so a gone unit's logs stay readable, and a stopped service's too). Lines are kept 30 days.
direction=backward (default) is newest first and is how a panel opens and scrolls back; direction=forward with the last follow_cursor is how a follow polls (every poll_after_ms). lines are always oldest first. cursor is opaque and resumes exactly, without a duplicate or a gap; follow_cursor is the one that follows the newest line of the page, which is how a follow starts after the first page. search is a case-insensitive substring run on the server.
Each line has an id that is the same for the same line on the live stream. markers are lifecycle facts in the span this page covers, with the kernel's sentence in text: a pod started, was replaced, stopped, lost or removed, a container restarted (with its reason and exit code), or lines the rate cap moved to the archive (an overflow marker with from, to and count). A marker has a stable id; a poll that meets one twice draws it once. coverage is the kernel's sentence about what was read.
503 log-store-unavailable when the store does not answer; live tail is not affected. Needs the LogStream capability and the same access as reading a service's logs. Console only.
path Parameters
idproject_idquery Parameters
containerOne container name.
One container name.
cursorA next_cursor from an earlier response. Opaque; hand back exactly what was given.
A next_cursor from an earlier response. Opaque; hand back exactly what was given.
directionbackward (default) or forward.
backward (default) or forward.
fromStart of the window, RFC 3339. Clamped to the 30 days logs are kept.
Start of the window, RFC 3339. Clamped to the 30 days logs are kept.
include_agentInclude the unit agent's own lines (container zaroz-agent). Hidden by default;
naming that container in container shows them too.
Include the unit agent's own lines (container zaroz-agent). Hidden by default;
naming that container in container shows them too.
limitLines per page: 500 by default, at most 2000.
Lines per page: 500 by default, at most 2000.
searchCase-insensitive substring, at most 200 characters. Not a regular expression.
Case-insensitive substring, at most 200 characters. Not a regular expression.
toEnd of the window, RFC 3339. Defaults to now.
End of the window, RFC 3339. Defaults to now.
unit_idOne unit, live or gone. Absent reads every unit of the service. A unit that is not one of this service's is a 404.
One unit, live or gone. Absent reads every unit of the service. A unit that is not one of this service's is a 404.
List Unit Logs › Responses
The page
coverageThe kernel's sentence about what this read covered.
The same, as separate facts a client may word itself.
Oldest first, whatever the direction read.
Lifecycle facts in the span this page owns, oldest first.
poll_after_msHow long a follow polls for, in milliseconds, so a client never hard-codes it.
truncatedMore lines exist in the direction read.
follow_cursorThe cursor that follows the newest line of this page: how a follow starts after the first (newest) page of a backward read, and where the next poll continues from after a forward one. Null for an empty page read backward.
next_cursorWhere to continue in the direction read. Reading backward it is null once the retention edge is reached; reading forward it is the cursor to poll with next.
Download Unit Logs
The same filters as listUnitLogs (without a cursor or a limit), streamed oldest first as a gzip file, as text (one line per log line: instant, u<slot>/<pod>, container, stream, text) or as ndjson (the fields of the list route). At most one download runs per organization at a time (429 otherwise), and one request carries at most 1 GiB of raw output: past that the file ends with a line saying it was cut and the instant to resume from. Console only.
path Parameters
idproject_idquery Parameters
containerformattext (default) or ndjson.
text (default) or ndjson.
frominclude_agentInclude the unit agent's own lines, as on the list route.
Include the unit agent's own lines, as on the list route.
searchtounit_idDownload Unit Logs › Responses
The gzip file
Create Unit Log Stream Ticket
Mints a short-lived signed URL for following one container of one running unit live, through the cluster's own edge gateway (a WebSocket, valid for a minute, re-minted by whoever keeps reading). since resumes from an instant, normally the at of the newest line on screen; the line id is the same here as in listUnitLogs, so a line seen in both is drawn once. 409 unit-not-running when the unit has no running pod (scaled away, stopped, or not started yet): its stored history is still readable. Live tail never touches the log store. The grant is recorded in the organization's audit feed. Console only.
path Parameters
unit_idThe unit to follow.
The unit to follow.
idproject_idquery Parameters
containerWhich container the ticket is minted for. May be omitted when the pod runs exactly one.
Which container the ticket is minted for. May be omitted when the pod runs exactly one.
sinceRFC 3339 instant to resume the stream from, normally the at of the last line already
on screen.
RFC 3339 instant to resume the stream from, normally the at of the last line already
on screen.
Create Unit Log Stream Ticket › Responses
A signed, short-lived URL for one container's live output
containerThe container the ticket is minted for. The gateway refuses any other, so a client switching containers mints a new ticket.
expires_atWhen the ticket stops being accepted. A client re-mints on expiry; the short life is what makes a leaked URL harmless.
urlThe gateway URL to open a WebSocket against. Carries the signed ticket in its query string and is single-purpose: it grants a read of exactly one container's output and nothing else.
Get Unit Metrics
CPU, memory and network of a service's units over 1h, 6h, 24h, 7d or 30d, each as 120 buckets (30 s, 3 min, 12 min, 84 min or 6 h wide) bucketed by the metrics store. series is a comma-separated list of cpu, memory, network_in, network_out, log_lines_archived (the lines a container wrote above the log rate cap, which are moved to the archive and not dropped) and restarts (container terminations per bucket, counted from the kernel's termination records, zero where none ended); it defaults to all. Without unit_id each series has one aggregate line (the units summed) and a line per unit for at most ten units (the ten with the highest mean over the window), with omitted_units counting the rest; with unit_id it has that unit's line only and its ceiling as limit. A bucket with no sample is null, never zero. Each line carries latest, mean and max of its buckets, computed by the kernel. available_windows lists the windows worth offering for the service's age. coverage is the kernel's sentence about what was read, with coverage_code and coverage_params for a client that words it in another language. 503 metrics_store_unavailable when the metrics store does not answer. Console only.
path Parameters
idproject_idquery Parameters
seriesComma-separated, any of cpu, memory, network_in, network_out,
log_lines_archived and restarts. Absent means all of them.
Comma-separated, any of cpu, memory, network_in, network_out,
log_lines_archived and restarts. Absent means all of them.
unit_idNarrows the read to one unit of this service.
Narrows the read to one unit of this service.
window1h (the default), 6h, 24h, 7d or 30d, each answered as 120 buckets.
1h (the default), 6h, 24h, 7d or 30d, each answered as 120 buckets.
Get Unit Metrics › Responses
The requested series over the window
available_windowsThe windows worth offering for this service: a service created an hour ago has no use
for 30d.
bucket_countHow many buckets every points array holds.
coverageThe kernel's sentence about what was read, shown beside the charts as given.
coverage_codeWhich sentence coverage is: metrics_shown or metrics_none_recorded.
The facts in it: window and to (RFC 3339), for a client that words it itself.
fromStart of the first bucket.
omitted_unitsUnits that wrote samples in the window beyond the ones drawn.
step_secondstoEnd of the window.
windowA window a customer may ask for.
unit_idGet Unit Count Series
How many units a service ran over 1h, 6h, 24h, 7d or 30d, in 120 buckets: running is integrated from the same pod intervals the bill is metered from (the most and fewest units running at one instant in each bucket, and the most billed as extra), desired is the count the platform wanted at the end of each bucket (absent for a service with no scaling policy and no scaling history), included is the plan's included units, the billing boundary, and markers are the scaling decisions inside the window (scale up, scale down, refused, rollout paused) each with the kernel's sentence (summary, plus summary_code and summary_params for a client that words it itself). Console only.
path Parameters
idproject_idquery Parameters
windowA window a customer may ask for.
Get Unit Count Series › Responses
Units over time
fromincludedThe units the plan includes: units beyond this are billed as extra. Drawn as a threshold.
step_secondstowindowA window a customer may ask for.
Absent for a service that has no scaling policy and no scaling history.
List Unit Terminations
The times a container of one unit was restarted, newest first, kept 30 days: the container, the kubelet's restart count, the reason (OOMKilled, Error, Completed, ... or unknown) and the exit code. from and to bound the observation time; page with cursor from next_cursor. A unit that is gone is still listed while its history is kept; a unit of another service is a 404. Console only.
path Parameters
idproject_idunit_idquery Parameters
cursorThe next_cursor of the previous page.
The next_cursor of the previous page.
fromEarliest observation, inclusive. Defaults to, and is held to, the 30 days kept.
Earliest observation, inclusive. Defaults to, and is held to, the 30 days kept.
limitRows per page, 1 to 200. Defaults to 50.
Rows per page, 1 to 200. Defaults to 50.
toLatest observation, inclusive. Defaults to now.
Latest observation, inclusive. Defaults to now.
List Unit Terminations › Responses
One page of terminations
next_cursorPass as cursor for the next page; absent on the last.
List Unit Pods
Every pod one unit has had, newest first: its incarnation (1, 2, 3, ...), name, whether the plan covered it (billing_class), when it started and ended, why it ended (end_reason: replaced, stopped, torn_down or lost; absent while it runs), how many container restarts it had and how its last container ended (reason and exit code). Page with cursor from next_cursor. A unit that is gone is still listed while its history is kept; a unit of another service and an invented id are the same 404. Console only.
path Parameters
idproject_idunit_idquery Parameters
cursorThe next_cursor of the previous page.
The next_cursor of the previous page.
limitRows per page, 1 to 200. Defaults to 50.
Rows per page, 1 to 200. Defaults to 50.
List Unit Pods › Responses
One page of pods
next_cursorPass as cursor for the next page; absent on the last.
List Service Units
The units this service runs, lowest slot first: each unit's id (the key of its logs), slot, state, whether it is covered by the plan (included) or billed as an extra unit, its current pod and when that pod started, its restarts in the last 24 hours, how its latest container ended, and its latest sampled load with the sample time. include_gone=true also lists the units scaled away within the 30 days their logs are kept, so those logs stay reachable (deleted_at says they are gone, kept_until when they age out).
Around the list: scalable (the product allows more than one unit), max_units (the product's maximum capped by the organization's limit), included_units, volume_locked (a shared volume holds the service to one unit) and multi_unit_in_use (more than one unit now, or an autoscaled policy), restarts_24h (container terminations of the whole service in the last 24 hours, gone units included) and desired_state (stopped when every live unit is meant to be stopped). organization_limits is the organization's live units and pod starts in the last hour, each with its limit and a level (ok, near from 80 percent, at_limit), and nearing for the console's notice that points to support; at the limit growth is refused and running units are never removed. A service that does not run as units, or has not been provisioned, has an empty list.
Besides a person who may see the service, a service principal may call this with a units.read or units.control grant on the service; to a principal, a service it holds no grant on is absent (404). Each unit has a key (its stable name: u{slot} for a unit the policy made), its labels and its origin. Narrow the list with label=key:value (repeat it to require several, at most 8, all must match), origin= and key_prefix=. The list leaves each unit's user_data out; include=user_data adds it. Console only.
path Parameters
idproject_idquery Parameters
includeuser_data returns each unit's user_data too. The list leaves it out by default
to stay small; GET .../units/{key} always has it.
user_data returns each unit's user_data too. The list leaves it out by default
to stay small; GET .../units/{key} always has it.
include_goneAlso list the units scaled away within the 30 days their logs are kept, after the live ones of their slot, so their logs stay reachable. Off by default.
Also list the units scaled away within the 30 days their logs are kept, after the live ones of their slot, so their logs stay reachable. Off by default.
key_prefixOnly units whose key starts with this text (lowercase letters, digits, hyphens).
Only units whose key starts with this text (lowercase letters, digits, hyphens).
labelOnly units with this label, label=key:value. Repeat it to require several (all
must match, at most 8). A value may contain colons.
Only units with this label, label=key:value. Repeat it to require several (all
must match, at most 8). A value may contain colons.
originOnly units of this origin: policy, code or warm.
Only units of this origin: policy, code or warm.
List Service Units › Responses
The units
desired_stateWhat the service as a whole is meant to be doing: stopped when it has live units and
none is meant to run, else running.
included_unitsHow many units the plan's price covers; units above it are billed as extras.
max_unitsThe most units this service may run: the product's maximum capped by the organization's limit.
multi_unit_in_useThe service runs more than one unit now, or its policy is autoscaled.
restarts_24hContainer terminations across every unit of the service in the last 24 hours, gone units included. Computed by the kernel; clients do not sum the units.
scalableThe product allows more than one unit.
volume_lockedA shared volume holds the service to exactly one unit, whatever the product allows.
The organization's units and pod starts against its limits, which the console's near-limit notice reads. Absent for a service that does not run as units.
Create Service Unit
Creates a unit by its key for the program that controls this service's units (policy mode code), starting it unless start is false (a unit created stopped holds no slot and costs nothing). Idempotent on the key: a live unit with that key is returned with created: false and 200; when it is stopped and start is true it is started, its labels and user_data replaced by the ones given (the call that wakes a stopped unit). A running unit given other labels or user_data is refused 409 unit_input_differs: a running unit's input changes only by allocate or by PATCH of its labels. A new unit answers 201 with created: true.
Before any pod is created the call checks the service's maximum (container_unit_limit), the organization's unit limit (org_unit_limit) and start rate (429 start_rate), and the spend cap (spend_cap); a unit created stopped checks the stopped-unit cap (stopped_unit_limit). Outside code mode the answer is 409 policy_not_code. Every refusal has a stable code and a docs_url. Besides a person who may change the service, a service principal with a units.control grant on it may call this; to a principal, a service it holds no such grant on is absent (404). Console only.
path Parameters
idproject_idCreate Service Unit › Request Body
key1 to 40 lowercase letters, digits or hyphens, starting and ending with a letter
or digit. Never changes. u followed by digits, keys starting w- or zaroz,
and the words the units routes use (allocate, events, policy, ...) are
reserved.
At most 16 pairs; replaced whole. Absent means none for a new unit.
What the unit does when its process exits. Defaults to the policy's
default_on_exit.
startfalse creates the unit stopped: it holds no slot and costs nothing until it
starts. Defaults to true.
user_dataAny JSON value up to 64 KiB, at most 32 levels deep. Not a secret store.
Create Service Unit › Responses
The live unit with that key (created: false)
createdtrue only when this call made the unit.
The unit, with its user_data.
Get Service Unit
One live unit by its key: everything the list shows for it plus its user_data (null when it has none). user_data is not a secret store, every reader of the unit sees it. A key the service has no unit under, an invented one and another service's answer the same 404. Besides a person who may see the service, a service principal with a units.read or units.control grant on it may read it. Console only.
path Parameters
idkeyThe unit's key, GET .../units lists it.
The unit's key, GET .../units lists it.
project_idGet Service Unit › Responses
The unit
desired_staterunning when the platform wants the unit's pod to exist, stopped
when it wants it gone.
keyThe unit's stable name and the first label of its private name: u{ordinal} for a
unit the policy made, the customer's own key otherwise. Addresses the unit in
.../units/{key}.
The unit's labels, {} when it has none. Filter the list with label=key:value.
Who made the unit.
The public addresses that reach this unit alone, one per per-unit port (kind: unit
endpoints). Held for as long as the unit's slot exists, so each survives every pod
restart of the unit. Empty when the service has no per-unit port.
restarts_24hContainer terminations in the last 24 hours.
What the unit's pod says, or what its desired state implies when it has
no pod. A unit that is gone reads as suspended; deleted_at says it is gone.
unit_idThe unit's id, the key of its logs. A slot can have had several units over time.
user_dataWhat the unit was given as input. Present only when asked for (include=user_data
on the list, always on GET .../units/{key}); null means the unit has none. Not a
secret store: every reader of the unit sees it.
Set once allocate handed the unit to a caller (Units phase 2); null while it
has not been. An allocation is never undone: the unit ends by its exit, a stop
or a destroy.
Whether the unit's pod is covered by the plan's price (included) or
billed as an extra unit (extra). Absent while the unit has no pod.
current_incarnationThe newest pod this unit has had, running or not. Present for a stopped or gone unit too.
deleted_atWhen the unit was scaled away. Only listed with include_gone=true.
incarnationHow many pods this unit has had, counting the current one. Absent while it has no pod.
kept_untilWhen a gone unit's logs, pods and terminations age out and are no longer listed.
Present exactly when deleted_at is.
Absent for a unit never sampled, a gone one, or while samples cannot be read.
ordinalThe slot, 1..N, held while the unit can run. Null for a stopped unit of the customer's code or the warm buffer, which gives its slot back (Units phase 2).
pod_nameprivate_nameThe name another service in the same project resolves to reach this unit
alone, <key>.<service slug> (for example u2.worker). The service's slug
by itself reaches every ready unit. Absent when the service has no private name.
started_atWhen the current pod was created.
Destroy Service Unit
Drains the unit, then destroys it, running or stopped. Final: the key answers 404 afterwards, and may be used again by a later create. code mode only (409 policy_not_code). A service principal with units.control on the service may call this. Console only.
path Parameters
idkeyThe unit's key, GET .../units lists it.
The unit's key, GET .../units lists it.
project_idDestroy Service Unit › Responses
Destroyed
Update Service Unit Labels
Replaces the unit's labels whole: {} clears them. At most 16 pairs; a key is 1 to 32 lowercase letters, digits, dots, underscores or hyphens, a value at most 64 characters without control characters, and the whole map at most 2 KiB. A refusal names its code before the colon in details. Works in every policy mode. Returns the unit. Besides a person who may change the service, a service principal with a units.control grant on it may call this. Console only.
path Parameters
idkeyThe unit's key, GET .../units lists it.
The unit's key, GET .../units lists it.
project_idUpdate Service Unit Labels › Request Body
At most 16 pairs. A key is 1 to 32 lowercase letters, digits, dots, underscores or hyphens; a value is at most 64 characters without control characters; the whole map at most 2 KiB serialized.
Update Service Unit Labels › Responses
The unit as stored
desired_staterunning when the platform wants the unit's pod to exist, stopped
when it wants it gone.
keyThe unit's stable name and the first label of its private name: u{ordinal} for a
unit the policy made, the customer's own key otherwise. Addresses the unit in
.../units/{key}.
The unit's labels, {} when it has none. Filter the list with label=key:value.
Who made the unit.
The public addresses that reach this unit alone, one per per-unit port (kind: unit
endpoints). Held for as long as the unit's slot exists, so each survives every pod
restart of the unit. Empty when the service has no per-unit port.
restarts_24hContainer terminations in the last 24 hours.
What the unit's pod says, or what its desired state implies when it has
no pod. A unit that is gone reads as suspended; deleted_at says it is gone.
unit_idThe unit's id, the key of its logs. A slot can have had several units over time.
user_dataWhat the unit was given as input. Present only when asked for (include=user_data
on the list, always on GET .../units/{key}); null means the unit has none. Not a
secret store: every reader of the unit sees it.
Set once allocate handed the unit to a caller (Units phase 2); null while it
has not been. An allocation is never undone: the unit ends by its exit, a stop
or a destroy.
Whether the unit's pod is covered by the plan's price (included) or
billed as an extra unit (extra). Absent while the unit has no pod.
current_incarnationThe newest pod this unit has had, running or not. Present for a stopped or gone unit too.
deleted_atWhen the unit was scaled away. Only listed with include_gone=true.
incarnationHow many pods this unit has had, counting the current one. Absent while it has no pod.
kept_untilWhen a gone unit's logs, pods and terminations age out and are no longer listed.
Present exactly when deleted_at is.
Absent for a unit never sampled, a gone one, or while samples cannot be read.
ordinalThe slot, 1..N, held while the unit can run. Null for a stopped unit of the customer's code or the warm buffer, which gives its slot back (Units phase 2).
pod_nameprivate_nameThe name another service in the same project resolves to reach this unit
alone, <key>.<service slug> (for example u2.worker). The service's slug
by itself reaches every ready unit. Absent when the service has no private name.
started_atWhen the current pod was created.
Get Scaling Policy
The scaling policy in force. A service that was never given one is fixed at one unit, with updated_at the service's creation. While a template change is still reaching the units, rollout_status says how: the strategy, the target_template, how many stale_units still run an older one and how many are replaced_units, and under replace_idle the units it waiting_on (allocated ones are replaced when they end, busy ones at their next idle). Console only.
path Parameters
idproject_idGet Scaling Policy › Responses
The policy in force
contract_versioncode: what a unit does when its process exits, unless it was created with
its own. Always restart in the other modes.
destroy_stopped_after_daysA stopped unit of the customer's code is destroyed after this many days.
max_unitsmin_unitsWhether the number of units is a constant or follows load and the clock. Stored as text and constrained in SQL to the same two words.
auto: the phase-1 readiness; signal: Ready only once the unit signals it.
ready_timeout_secondsA unit not Ready this long after its pod started is failed (units that carry the agent only).
How a template change reaches the units. Phase 1 has rolling; phase 2 adds
replace_idle and next_start (plan 3.5), whose selection rules are P2-K8's:
until it lands they are stored and validated, and roll as rolling does.
scale_down_stabilisation_secondsscale_up_cooldown_secondsBounds overrides that take effect when their cron expression fires and hold until the next rule fires.
updated_atcpu_target_percentdrain_idle_after_secondsautoscaled: a unit idle this long may be drained while above the minimum.
code: what happens to a unit idle for idle_after_seconds.
idle_after_secondskeep_acceptingautoscaled: keep this many units accepting beside the ones that say they
are full.
memory_target_percentPresent while a template change is still reaching the units; absent once every
running unit is on the current template. Only GET reads it.
spend_cap_centsThe most, in cents, the extra units may cost in a month before scaling refuses to grow. Absent means the worst case the maximum allows.
warm_unitscode: ready, unallocated warm units kept on top of the others. Absent in
the other modes.
Update Scaling Policy
Changes the scaling policy. Omitted fields keep their value; nullable fields take null to clear. A fixed policy is one count (min_units equals max_units; giving only one of them sets both) and applies immediately, adding or removing units. An autoscaled policy needs a CPU target, a memory target or a schedule rule and is acted on by the autoscaler within its bounds. max_units cannot exceed the service's unit limit, and a service with a shared volume runs exactly one unit. A code policy hands the count to the customer's program: its minimum is 0, it has no load targets or schedule, and warm_units ready units are kept on top; idle_action, default_on_exit, destroy_stopped_after_days and ready_timeout_seconds govern its units. keep_accepting and drain_idle_after_seconds are autoscaled signal rules. Leaving code mode answers 409 code_units_exist while units the program owns remain. A refusal names a reason code before the colon in details. 503 with count_not_applied means the policy is saved but the units could not be changed yet: send the same update again. Console only.
path Parameters
idproject_idUpdate Scaling Policy › Request Body
contract_versioncpu_target_percentdestroy_stopped_after_daysdrain_idle_after_secondsidle_after_secondskeep_acceptingmax_unitsmemory_target_percentmin_unitsready_timeout_secondsscale_down_stabilisation_secondsscale_up_cooldown_secondsspend_cap_centswarm_unitsUpdate Scaling Policy › Responses
The policy as stored
contract_versioncode: what a unit does when its process exits, unless it was created with
its own. Always restart in the other modes.
destroy_stopped_after_daysA stopped unit of the customer's code is destroyed after this many days.
max_unitsmin_unitsWhether the number of units is a constant or follows load and the clock. Stored as text and constrained in SQL to the same two words.
auto: the phase-1 readiness; signal: Ready only once the unit signals it.
ready_timeout_secondsA unit not Ready this long after its pod started is failed (units that carry the agent only).
How a template change reaches the units. Phase 1 has rolling; phase 2 adds
replace_idle and next_start (plan 3.5), whose selection rules are P2-K8's:
until it lands they are stored and validated, and roll as rolling does.
scale_down_stabilisation_secondsscale_up_cooldown_secondsBounds overrides that take effect when their cron expression fires and hold until the next rule fires.
updated_atcpu_target_percentdrain_idle_after_secondsautoscaled: a unit idle this long may be drained while above the minimum.
code: what happens to a unit idle for idle_after_seconds.
idle_after_secondskeep_acceptingautoscaled: keep this many units accepting beside the ones that say they
are full.
memory_target_percentPresent while a template change is still reaching the units; absent once every
running unit is on the current template. Only GET reads it.
spend_cap_centsThe most, in cents, the extra units may cost in a month before scaling refuses to grow. Absent means the worst case the maximum allows.
warm_unitscode: ready, unallocated warm units kept on top of the others. Absent in
the other modes.
Quote Scaling Policy
What a proposed policy can cost in a month, without saving it. Takes the body of PATCH .../units/policy and is refused for the same reasons (a reason code before the colon in details; not_provisioned for a fixed policy on a service with no cluster yet). monthly_cents is the worst case: every unit above the plan's included ones running every hour of the longest month at the Price's extra_unit_hours rate, held to the policy's spend_cap_cents (cap_binds says the cap is what limits it). Each extra unit start bills at least minimum_billed_seconds; that minimum is shown but never changes the worst case. A Price with no extra_unit_hours line is metered: false and every amount is zero. Whether the wallet can hold the amount is the save's check, not the quote's. Console only.
path Parameters
idproject_idQuote Scaling Policy › Request Body
contract_versioncpu_target_percentdestroy_stopped_after_daysdrain_idle_after_secondsidle_after_secondskeep_acceptingmax_unitsmemory_target_percentmin_unitsready_timeout_secondsscale_down_stabilisation_secondsscale_up_cooldown_secondsspend_cap_centswarm_unitsQuote Scaling Policy › Responses
The quote
cap_bindsThe spend cap is what limits monthly_cents.
extra_unitsUnits above the plan's included ones, at the policy's ceiling.
hourly_centsWhat one extra unit costs for one hour, in cents.
meteredThe Price meters extra units. When false every amount is zero.
minimum_billed_secondsEach extra unit start bills at least this long.
minimum_start_centsWhat one extra unit start bills at that minimum, in cents.
monthly_centsThe most the policy can cost in a month, in cents: the worst case held to the cap.
worst_case_centsEvery extra unit running all month, before the spend cap, in cents.
worst_case_hoursHours of extra-unit time the worst case bills (every extra unit, the longest month).
List Unit Events
The Container's unit events, oldest first: every unit transition (unit.created, unit.starting, unit.ready, unit.stopped, unit.exited, unit.failed, unit.destroyed, ...) and every scaling change (units.scaled), each as the contract-v1 envelope with a per-Container, gapless seq. Read with a cursor: after is the last seq you saw and next_after the one to send next. With wait (0 to 30 seconds) and nothing new, the request is held and returns as soon as an event arrives (long-poll). types keeps only the listed types, unit_key and label (key:value, matched against the labels the unit had when the event was written) keep only events about that unit, limit caps the page (500). To open on the latest, send newest=N (or before=<seq> for the page before a cursor): the answer is newest first, with has_earlier and next_before to load earlier and next_after to follow live; a backwards read does not wait and never answers 410. Events are kept 30 days; a cursor older than the oldest kept event answers 410 with code cursor_expired and resume_after, the cursor to read from the oldest kept event. A service principal with a units.read or units.control grant on the service may read events too; to a principal, a service it holds no grant on is absent (404). Console only.
path Parameters
idproject_idquery Parameters
afterThe last seq already seen; events after it are returned. Default 0 (from
the oldest retained). A cursor older than the oldest retained event
answers 410 cursor_expired.
The last seq already seen; events after it are returned. Default 0 (from
the oldest retained). A cursor older than the oldest retained event
answers 410 cursor_expired.
beforeRead backwards: events with a seq lower than this, newest first. Send
next_before from the last page to "load earlier". Not with after,
newest or wait; a backwards read never answers 410.
Read backwards: events with a seq lower than this, newest first. Send
next_before from the last page to "load earlier". Not with after,
newest or wait; a backwards read never answers 410.
labelOnly events about a unit that carried this label when the event was
written, label=key:value (one; a value may contain colons).
Only events about a unit that carried this label when the event was
written, label=key:value (one; a value may contain colons).
limitAt most this many events, 1 to 500. Default 100.
At most this many events, 1 to 500. Default 100.
newestRead backwards from the head: the newest this many events (1 to 500),
newest first. Takes the place of limit. Not with after, before
or wait. next_after of the answer follows the log live.
Read backwards from the head: the newest this many events (1 to 500),
newest first. Takes the place of limit. Not with after, before
or wait. next_after of the answer follows the log live.
typesComma-separated event types to keep (for example unit.ready,unit.exited).
Default every type.
Comma-separated event types to keep (for example unit.ready,unit.exited).
Default every type.
unit_keyOnly events about the unit with this key. Events about the Container
itself (units.scaled, rollout.*) have no unit and are left out.
after reads stay gap-free: the cursor still moves only past events
returned.
Only events about the unit with this key. Events about the Container
itself (units.scaled, rollout.*) have no unit and are left out.
after reads stay gap-free: the cursor still moves only past events
returned.
waitWith nothing new, hold the request up to this many seconds (0 to 30) and return as soon as an event arrives. Default 0.
With nothing new, hold the request up to this many seconds (0 to 30) and return as soon as an event arrives. Default 0.
List Unit Events › Responses
A page of events
Oldest first; newest first for a read with before or newest.
has_earlierBackwards reads only: whether events matching the filters exist before
this page. Always false for a forward read.
next_afterPass this as after next: the last returned seq, or the one you sent
when nothing was new. After a backwards read it is the highest seq
returned, so the view follows live from the page it opened on.
oldest_retained_seqThe oldest seq still kept (events are kept 30 days).
next_beforeBackwards reads only: pass this as before to load earlier events (the
lowest seq returned); null for a forward read or an empty page.
List Scaling Decisions
The scaling decision log, newest first, kept 30 days. Consecutive identical decisions are one entry: at is the first, last_at the latest and repeat_count how many. from and to keep the entries whose run overlaps that range and action keeps one action; every entry carries summary, the kernel's sentence for it. Console only.
path Parameters
idproject_idquery Parameters
actionOnly decisions with this action.
Only decisions with this action.
fromOnly decisions whose run (at to last_at) reaches this instant or later.
Only decisions whose run (at to last_at) reaches this instant or later.
pagePage number (1-indexed). Defaults to 1.
Page number (1-indexed). Defaults to 1.
page_sizeNumber of items per page. Defaults to 20, max 100.
Number of items per page. Defaults to 20, max 100.
toOnly decisions made at or before this instant.
Only decisions made at or before this instant.
List Scaling Decisions › Responses
One page of the log
Pagination metadata included in paginated responses
Allocate Service Unit
Hands you one warm unit that is ready, accepting, not allocated and not draining, preferring units on the current template and then the longest ready, and sets its labels and user_data when given (the match's roster). Atomic: two calls never receive the same unit. The warm buffer refills behind it. The unit's agent writes /zaroz/allocation.json and /zaroz/user-data.json and acknowledges; the answer comes as soon as the allocation is on its way, with unit.allocation.delivered_at null, and ?wait=delivered holds it until the agent acknowledges or 10 seconds pass. A delivery not acknowledged in 10 seconds is the event unit.allocation_undelivered; the unit stays allocated. An allocation is never undone: the unit ends by its exit, a stop or a destroy.
Idempotency-Key (optional header, up to 64 characters): the same key returns the same unit while it lives (replayed: true, 200); without one every call allocates another unit. With no warm unit ready, if_none: fail (the default) answers 409 no_warm_unit with warm_ready, warm_starting and retry_after_seconds; if_none: create cold-starts a warm unit already allocated to you and answers 202 with it starting, after the same limit and spend checks as a create. When the unit's region cannot be reached the allocation is undone and the answer is 503 region_unreachable. code mode only (409 policy_not_code). Every refusal has a stable code and a docs_url. A service principal with units.control on the service may call this. Console only.
path Parameters
idproject_idquery Parameters
waitHeaders
Idempotency-KeyOptional, 1 to 64 printable ASCII characters. The same key returns the same unit while it lives, instead of allocating another.
Allocate Service Unit › Request Body
fail (default) answers 409 no_warm_unit when no warm unit is ready;
create cold-starts a new one already allocated to you (202).
Replaces the allocated unit's labels whole when given.
user_dataReplaces the allocated unit's user_data whole when given: the match's
roster, map, mode.
Allocate Service Unit › Responses
Allocated, or the unit this Idempotency-Key already allocated
createdtrue when if_none: create cold-started the unit: it is still starting.
replayedtrue when this Idempotency-Key had already allocated the unit.
The unit, with its user_data and allocation (delivered_at is null until
its agent has the files).
Start Service Unit
Starts a stopped unit, its labels and user_data replaced by the ones given (send {} to keep them). A running unit is left as it is (200). Checks the same limits and spend cap as a create that starts. code mode only (409 policy_not_code). A service principal with units.control on the service may call this. Console only.
path Parameters
idkeyThe unit's key, GET .../units lists it.
The unit's key, GET .../units lists it.
project_idStart Service Unit › Request Body
Replaces the unit's labels whole when given.
user_dataReplaces the unit's user_data whole when given.
Start Service Unit › Responses
The unit
createdtrue only when this call made the unit.
The unit, with its user_data.
Stop Service Unit
Drains the unit, then stops it: it keeps its key, labels and user_data, gives its slot back, and costs nothing while stopped. A stopped unit is left as it is (200). Past the service's stopped-unit cap the answer is 409 stopped_unit_limit. code mode only (409 policy_not_code). A service principal with units.control on the service may call this. Console only.
path Parameters
idkeyThe unit's key, GET .../units lists it.
The unit's key, GET .../units lists it.
project_idStop Service Unit › Responses
The unit
createdtrue only when this call made the unit.
The unit, with its user_data.
List Unit Webhooks
The service's webhooks, oldest first: where its unit events are delivered, which types, and how delivery is going (state, the acknowledged cursor_seq, the current run of failures). Never a secret. People with manage access only. Console only.
path Parameters
idproject_idList Unit Webhooks › Responses
The webhooks
Create Unit Webhook
Delivers this service's unit events to url: ordered batches (at most 50 events or 256 KiB) POSTed as {webhook_id, delivery_id, events}, the next batch only after a 2xx within 10 seconds, at least once (deduplicate on seq). A new webhook starts with the events after now. url is https:// and a public host; a host that resolves to a private, loopback, link-local, shared or platform address is refused (address_not_allowed), and is checked again on every delivery; redirects are not followed. event_types empty means every type. At most 5 per service (too_many_webhooks).
The response carries the signing secret this once. Each POST has Zaroz-Signature: v1=<hex HMAC-SHA256(secret, "{Zaroz-Timestamp}.{raw body}")> (the whole secret string is the key), Zaroz-Timestamp (Unix seconds; refuse one more than 5 minutes off), Zaroz-Webhook-Id and Zaroz-Delivery-Id. Failed deliveries are retried after 5 s, 30 s, 2 min, 10 min, 30 min, 1 h and then hourly; after 72 hours of failure the webhook is disabled and the organization is notified. Console only.
path Parameters
idproject_idCreate Unit Webhook › Request Body
urlhttps:// and a public host; at most 2048 characters, no user name or
password.
event_typesEvent types to deliver (for example unit.ready); empty or absent for
every type.
Create Unit Webhook › Responses
Created; the secret is shown this once
secretwhsec_ and 43 characters. Sign check: Zaroz-Signature carries
v1=<hex HMAC-SHA256(secret, "{Zaroz-Timestamp}.{raw body}")>, with the
whole secret string as the key.
A webhook, never its secret.
Get Unit Webhook
One webhook of the service, never its secret. An id that is not one of this service's webhooks is a 404. Console only.
path Parameters
idproject_idwebhook_idGet Unit Webhook › Responses
The webhook
attemptConsecutive failed attempts of the current batch.
created_atcursor_seqThe last event seq the receiver acknowledged.
event_typesEmpty means every type.
idnext_attempt_atWhen the next attempt is due.
stateactive, failing (retrying the same batch) or disabled.
updated_aturldisabled_reasonWhy it is disabled: failing_72h. null unless disabled.
failing_sinceWhen the current run of failures began. null when the last attempt
succeeded.
previous_secret_expires_atUntil when the previous secret still signs beside the current one after
a rotation; null when only one secret signs.
Delete Unit Webhook
Stops delivering to this webhook and deletes it with its delivery log. Console only.
path Parameters
idproject_idwebhook_idDelete Unit Webhook › Responses
Deleted
Update Unit Webhook
Changes the URL and/or the event types; an absent field is left as it is, event_types: [] means every type. The URL is refused for the same reasons as on create. Delivery continues from the same cursor. Console only.
path Parameters
idproject_idwebhook_idUpdate Unit Webhook › Request Body
event_typesEmpty for every type.
urlUpdate Unit Webhook › Responses
The webhook as stored
attemptConsecutive failed attempts of the current batch.
created_atcursor_seqThe last event seq the receiver acknowledged.
event_typesEmpty means every type.
idnext_attempt_atWhen the next attempt is due.
stateactive, failing (retrying the same batch) or disabled.
updated_aturldisabled_reasonWhy it is disabled: failing_72h. null unless disabled.
failing_sinceWhen the current run of failures began. null when the last attempt
succeeded.
previous_secret_expires_atUntil when the previous secret still signs beside the current one after
a rotation; null when only one secret signs.
Rotate Unit Webhook Secret
Mints a new signing secret, shown in this response only. For 24 hours (previous_secret_expires_at) every delivery is signed with both, the new one first (Zaroz-Signature: v1=<new>,v1=<old>), so the receiver can switch without missing a delivery. Rotating again within those 24 hours drops the oldest. Console only.
path Parameters
idproject_idwebhook_idRotate Unit Webhook Secret › Responses
Rotated; the new secret is shown this once
secretwhsec_ and 43 characters. Sign check: Zaroz-Signature carries
v1=<hex HMAC-SHA256(secret, "{Zaroz-Timestamp}.{raw body}")>, with the
whole secret string as the key.
A webhook, never its secret.
Test Unit Webhook
Sends one signed webhook.ping event now and answers with the attempt (status, latency, error, the first 4 KiB of the answer), which also goes into the delivery log. The ping's seq is the webhook's cursor_seq, an event the receiver already has. Works in every state, a disabled webhook included, and changes neither the cursor nor the retries. At most 6 a minute per webhook (429 beyond). Console only.
path Parameters
idproject_idwebhook_idTest Unit Webhook › Responses
The attempt
attemptThe attempt's number for this batch, from 1.
attempted_atduration_msidkindevents (a batch) or ping (a test).
errorWhy it failed: address_not_allowed, dns, connect, timeout,
http_status, redirect_not_followed, invalid_url, transport.
null for a 2xx.
from_seqThe first and last event seq of a batch; null for a ping.
next_attempt_atWhen the batch is tried again; null unless a batch failed and will be
retried.
response_excerptThe first 4 KiB of the receiver's answer.
status_codeThe receiver's status; null when it never answered.
to_seqEnable Unit Webhook
Makes the webhook active and due at once, with no failures counted, from its cursor. If events after the cursor were already removed (they are kept 30 days), delivery resumes from the oldest kept one and the first batch opens with an events.gap event (data: {from_seq, to_seq}) naming what was missed. On a failing webhook it retries now. Console only.
path Parameters
idproject_idwebhook_idEnable Unit Webhook › Responses
The webhook
attemptConsecutive failed attempts of the current batch.
created_atcursor_seqThe last event seq the receiver acknowledged.
event_typesEmpty means every type.
idnext_attempt_atWhen the next attempt is due.
stateactive, failing (retrying the same batch) or disabled.
updated_aturldisabled_reasonWhy it is disabled: failing_72h. null unless disabled.
failing_sinceWhen the current run of failures began. null when the last attempt
succeeded.
previous_secret_expires_atUntil when the previous secret still signs beside the current one after
a rotation; null when only one secret signs.
List Unit Webhook Deliveries
The webhook's delivery log, newest first, kept 30 days: each attempt's time, the event range it carried (null for a test ping), its number for that batch, the receiver's status or the error code, the latency, the first 4 KiB of the answer and, for a failed batch, when it is tried again. limit 1 to 100 (default 50); before pages back from the last attempted_at seen. Console only.
path Parameters
idproject_idwebhook_idquery Parameters
beforeOnly attempts older than this (the last attempted_at of the previous
page).
Only attempts older than this (the last attempted_at of the previous
page).
limit1 to 100. Default 50.
1 to 100. Default 50.
List Unit Webhook Deliveries › Responses
One page of the log
Get Service API Access
The service's principal (its own identity for code that calls the Zaroz API) and its grants on the project's services, plus copies_total, copies_with_key and copies (per live copy, carries_key): which copies already run the pod template that mounts the key, since a change applies as copies restart. 404 with no_principal when the service has none. People with manage access only. Console only.
path Parameters
idproject_idGet Service API Access › Responses
The principal and its grants
Each live copy, lowest slot first.
copies_totalHow many live copies the service has.
copies_with_keyHow many of them carry the mounted key already.
created_atidservice_instance_idThe service the principal is the identity of.
Enable Service API Access
Lets code in this service use the Zaroz API: creates the service's principal, or returns the one it has (idempotent; 201 when created, 200 when it existed). The kernel mounts a short-lived token into every unit of the service at /zaroz/credentials/token and sets ZAROZ_API_URL; this applies as the units restart, by the service's rollout rule. A new principal holds no grant. Console only.
path Parameters
idproject_idEnable Service API Access › Responses
The service already had one
Each live copy, lowest slot first.
copies_totalHow many live copies the service has.
copies_with_keyHow many of them carry the mounted key already.
created_atidservice_instance_idThe service the principal is the identity of.
Disable Service API Access
Revokes the service's principal: every token it holds (mounted and external) stops working at once and the mounted token is removed from the service. Its grants go with it. A later enable creates a new principal with no grants. 404 with no_principal when the service has none. Console only.
path Parameters
idproject_idDisable Service API Access › Responses
Revoked
Replace Service API Grants
Replaces what the service's principal may do: each grant names a service of the same project (the service itself included) and units.read (read its units) or units.control (also start, stop and create them). You must be able to manage every service you name. The list replaces the old one whole; an empty list removes every grant; at most 64. A grant naming a service that is not in this project, that you cannot manage or that is no longer live is refused with grant_target_unavailable and nothing changes. 404 with no_principal when the service has no API access. Takes effect on the program's next request. Console only.
path Parameters
idproject_idReplace Service API Grants › Request Body
Replace Service API Grants › Responses
The principal with its new grants
Each live copy, lowest slot first.
copies_totalHow many live copies the service has.
copies_with_keyHow many of them carry the mounted key already.
created_atidservice_instance_idThe service the principal is the identity of.
List Grantable Services
The services of this project the caller may name in a grant of PUT .../principal/grants: the ones they can manage that are live, this service included. A service missing here would be refused with grant_target_unavailable, so the editor can offer only these. Works before the service has API access. People with manage access only. Console only.
path Parameters
idproject_idList Grantable Services › Responses
The services that may be granted
List Service API Credentials
The external credentials of the service's principal, for code running outside Zaroz: name, who made it (created_by, created_by_name), expiry and last use, newest first; revoked ones are not listed, expired ones are. Never the secret. 404 with no_principal when the service has no API access. Console only.
path Parameters
idproject_idList Service API Credentials › Responses
The credentials
Create Service API Credential
Mints an external credential for the service's principal, for code running outside Zaroz (a matchmaker elsewhere, CI). It acts with the principal's grants. name is 1 to 64 characters; expires_in_days is 1 to 365 and defaults to 90. The token is in this response only and cannot be read again. 404 with no_principal when the service has no API access. Console only.
path Parameters
idproject_idCreate Service API Credential › Request Body
name1 to 64 characters, so the credential can be told apart when revoking it.
expires_in_days1 to 365; 90 when omitted.
Create Service API Credential › Responses
Created; the token is shown this once
An external credential, without its secret.
tokenzaroz_sp_.... Shown once: it is stored only as a digest and cannot be
read back. Send it as Authorization: Bearer <token>.
Revoke Service API Credential
Revokes one external credential; it stops working at once. An id that is not a live credential of this service's principal (another service's, the mounted token's, or an invented one) is a 404, the same answer either way. Console only.
path Parameters
idproject_idcredential_idRevoke Service API Credential › Responses
Revoked
Quote Wallet Credit For Subscription
Quotes converting the unused time of this subscription into wallet credit. Read-only: nothing is written and the quote may be requested as often as the cancel screen refreshes. The answer is signed and valid for ten minutes. eligible: false says why in reason; below_minimum: true means the credit is under minimum_cents and redeeming would write nothing. Requires the same authority as cancelling the subscription, including the staff door.
path Parameters
idQuote Wallet Credit For Subscription › Responses
The signed quote
as_ofThe instant every figure below was computed at; redemption recomputes at exactly this instant.
below_minimumTrue when total_cents is under minimum_cents: the conversion is
not offered and redeeming this quote writes nothing.
currencyeligibleexpires_atminimum_centsperiod_remaining_secondsperiod_total_secondsquote_idOpaque and signed. Send it back unchanged to
POST /subscriptions/{id}/cancel-with-wallet-credit; an altered,
foreign or expired one is refused.
total_centsWhat the wallet would be credited, in minor units of currency.
reasonWhy the subscription is not eligible, when eligible is false: one of subscription_not_active, policy_not_prorated_to_wallet, disputed_or_charged_back_invoice, bundle_member.
Cancel Subscription With Wallet Credit
Pays the customer. Redeems a wallet-credit quote: cancels the subscription now and credits the wallet with the unused time, recomputed at the quote's own instant under the subscription, invoice and wallet locks, all in one transaction (any failure writes nothing). Refused with 422 for an invalid quote (altered, forged, or issued for another subscription), an ineligible subscription (which includes a quote already redeemed, because the subscription is then no longer active), or a credit under the minimum; refused with 409 for an expired quote, a credit that changed since the quote (request a new one), or a credit that needs staff to issue. Requires the same authority as cancelling the subscription (a restricted API token needs subscriptions.cancel), including the staff door, which is audited as staff.
path Parameters
idCancel Subscription With Wallet Credit › Request Body
quote_idThe quote_id of a quote issued for this subscription.
Cancel Subscription With Wallet Credit › Responses
The subscription was cancelled and the wallet credited
cancels_atWhen the subscription stops: the instant of this request.
credit_note_idsOne credit note per credited invoice.
statuspending_termination: the subscription now ends and the reaper tears
the service down on its next tick.
subscription_idtotal_credited_centsThe amount credited to the wallet, in minor units.
List Service Instance Deployments
This service's deployment history, newest first, and the current state of the workloads a deployment acts on. number is what a customer cites in a support ticket: unique within the service and never reused, but deliberately NOT contiguous, because it is drawn from the same per-service sequence every operation uses. status says how the operation ended and never whether the rollout worked -- nothing in the platform records a per-deployment outcome, so succeeded and failed do not exist here rather than being guessed. abandoned means the process holding the deployment died part-way; interrupted means an operator forced it open. actor is masked: a teammate is named by user id, while an operator and the platform are deliberately anonymous. workloads answers "is my new version serving" and is a statement about now rather than about any one deployment; it is empty for a service that has never been provisioned, and also when the resources could not be read, which degrades the banner rather than the panel. activeDeploymentId is kernel's answer to "is one running right now", read from this service's live operations rather than from the page above, so it is the same answer on every page and a client must not recompute it by scanning data. There are no phases and no build log, because nothing in kernel clones or builds a repository. 404 for a service whose product does not offer this capability, which is the same answer a service belonging to somebody else gives.
path Parameters
idquery Parameters
pagePage number (1-indexed). Defaults to 1.
Page number (1-indexed). Defaults to 1.
page_sizeNumber of items per page. Defaults to 20, max 100.
Number of items per page. Defaults to 20, max 100.
List Service Instance Deployments › Responses
The deployment history and the current state of this service's workloads
Newest first.
Pagination metadata included in paginated responses
The instance's workloads and their current state. Empty for a service that has never been provisioned, which is an ordinary state for one that has been paid for and not yet deployed.
active_deployment_idThe deployment happening right now, or null when nothing is.
Kernel's verdict, not a scan of data (R2,
13-deployments.md §6). It is read from the leases live on the
instance rather than from the page above, so it is the same answer on
page one and on page nine; a client that recomputed it by looking for
a running row would report "nothing deploying" for any customer who
paged back through their history.
It may name a deployment that is not in data at all, and that is
correct rather than a gap: the running one is always the newest, so it
is on page one, and a client on a later page should still show the
banner.
Start Service Instance Deployment
Puts this service's currently saved configuration into service, and records the attempt. It takes no body, deliberately: a deployment ships the source as it is already stored, so there is nowhere in this request to put configuration and no way to deploy something that was not saved first (00-program.md §8). There is no forceRebuild flag either, and it is absent rather than accepted-and-ignored, because nothing in kernel builds an image and a flag that skips a cache nobody has is a promise. Refused with a business-rule error when the service has never been told what to run, which is the state the panel renders by pointing at Source. Takes a deploy lease, so it is refused with 409 while a restore, a resize or another deployment holds this service, and the refusal names that operation and when it started. Two deployments of one service can never overlap. A rollout that cannot be applied is reported as a failure with a fixed sentence: the underlying cluster or template message is logged rather than returned, because it quotes registry hostnames and internal paths. The response's failureReason carries kernel's own closed-vocabulary cause for the same failure (never the raw message), so a client can show more than a generic retry hint without kernel ever repeating an internal hostname or path back to the caller. The response is the deployment as it now stands, with the number a customer cites in a support ticket.
path Parameters
idStart Service Instance Deployment › Responses
The deployment that was started, with its number
Who started it, masked. A customer is named by their user id; an operator and the platform are deliberately anonymous.
idnumberThe number a customer cites in a support ticket.
Unique within this service and never reused, because the lease rows
it comes from are never deleted. Not contiguous: it is drawn from
the same per-instance sequence every operation on the service uses, so
a service's deployments are #3, #7, #12. A panel renders it as an
identifier, never as a count.
started_atHow the operation ended. Not whether it worked: see this module's header.
Why it ran. A closed union with two arms: manual, somebody pressed
Deploy, and config_change, a setting was written and the workload was
re-rendered because of it. The three the fixture also carries (push,
tag_moved, rollback) each need a subsystem kernel does not have,
and are absent rather than declared and unreachable.
config_change carries a summary: kernel's own sentence about
what changed, for a client to print verbatim (R2). Do not parse it
and do not compose your own -- only kernel knows which key was
written -- and note that its wording is prose rather than a
compatibility surface.
duration_secondsWhole seconds, null whenever finishedAt is. Computed by kernel
(R2) from the two fields beside it, so it can never disagree with
them.
Why the rollout failed, when outcome is failed. Kernel's own
closed vocabulary -- never the raw cluster or template message, which
is logged rather than returned (ZC-1084).
null here is not the same statement null on outcome is. It is
null for every deployment that is not a recorded failure, for a
ConfigChange-kind deployment (not yet classified), and for a lease
released before this field existed. None of those is the unknown
word, which is a positive statement that kernel tried to classify and
could not. See
DeploymentFailureReason's
own doc for the full vocabulary and why each word is there.
finished_atnull while it is still running, and also for one that was abandoned:
the row records when the lease would have lapsed, not when the holder
stopped, and reporting the expiry would invent a duration.
image_digestThe immutable digest that was pulled, when the reference pinned one.
Almost always null, and that is honest rather than missing.
Nothing in kernel resolves a tag to a digest against a third-party
registry: both manifest clients authenticate HTTP basic only, while
ghcr.io, Docker Hub and Quay all require a Bearer-token exchange. It
is non-null only where the customer pinned a digest themselves. A
client must not derive one from imageReference.
image_referenceThe image this deployment shipped, as ${service.image} resolved when
the deployment started.
A fact about the past, not about now. It is captured when the
deployment begins, because that is the only moment it exists: the value
lives on the instance's configuration and the customer overwrites it on
their next tag change. A client comparing this with the Source
capability's current reference is comparing "what is running" with
"what is saved", which is the question 00-program.md §8 is about.
null for a deployment from before the provenance migration and for a
product whose image the customer does not choose. It is not
reconstructable, so null here means the answer is gone rather than
that it is available from another route.
Whether the rollout applied: succeeded, failed, or null.
null is "not recorded", never a failure. It is every deployment
from before the provenance migration, every one still running, and
every holder that died or was forced open before it could say. Nothing
is backfilled and nothing can be, so a panel renders null as an
absence rather than as a red badge.
Separate from status on purpose: a failed deployment is ended and
failed at once, because the handler releases its lease on its error
path too.
Get Service Instance Deployment
One deployment of this service, by id: the same row, with the same fields, that listServiceInstanceDeployments returns for it, so a panel can link to a deployment and read it back without paging the history. status says how the operation ended and outcome whether the rollout applied, and outcome is null when nothing recorded one, which is never a failure. failureReason is kernel's own closed-vocabulary cause for a failed Deploy-kind deployment (image reference invalid, hostname taken, cluster rejected the workload, and so on) -- never the raw error, which is still logged rather than returned, because it quotes registry hostnames and internal paths. failureReason is null whenever outcome is not failed, and also for a ConfigChange-kind deployment, which does not yet classify its failures. There are no phases and no build log: nothing in kernel clones or builds a repository. 404 for a deployment id that names nothing, one that belongs to a different service, and an operation on this service that is not a deployment, all identically; and 404 for a service whose product does not offer this capability, which is the same answer a service belonging to somebody else gives.
path Parameters
deployment_ididGet Service Instance Deployment › Responses
The deployment, as the history lists it
Who started it, masked. A customer is named by their user id; an operator and the platform are deliberately anonymous.
idnumberThe number a customer cites in a support ticket.
Unique within this service and never reused, because the lease rows
it comes from are never deleted. Not contiguous: it is drawn from
the same per-instance sequence every operation on the service uses, so
a service's deployments are #3, #7, #12. A panel renders it as an
identifier, never as a count.
started_atHow the operation ended. Not whether it worked: see this module's header.
Why it ran. A closed union with two arms: manual, somebody pressed
Deploy, and config_change, a setting was written and the workload was
re-rendered because of it. The three the fixture also carries (push,
tag_moved, rollback) each need a subsystem kernel does not have,
and are absent rather than declared and unreachable.
config_change carries a summary: kernel's own sentence about
what changed, for a client to print verbatim (R2). Do not parse it
and do not compose your own -- only kernel knows which key was
written -- and note that its wording is prose rather than a
compatibility surface.
duration_secondsWhole seconds, null whenever finishedAt is. Computed by kernel
(R2) from the two fields beside it, so it can never disagree with
them.
Why the rollout failed, when outcome is failed. Kernel's own
closed vocabulary -- never the raw cluster or template message, which
is logged rather than returned (ZC-1084).
null here is not the same statement null on outcome is. It is
null for every deployment that is not a recorded failure, for a
ConfigChange-kind deployment (not yet classified), and for a lease
released before this field existed. None of those is the unknown
word, which is a positive statement that kernel tried to classify and
could not. See
DeploymentFailureReason's
own doc for the full vocabulary and why each word is there.
finished_atnull while it is still running, and also for one that was abandoned:
the row records when the lease would have lapsed, not when the holder
stopped, and reporting the expiry would invent a duration.
image_digestThe immutable digest that was pulled, when the reference pinned one.
Almost always null, and that is honest rather than missing.
Nothing in kernel resolves a tag to a digest against a third-party
registry: both manifest clients authenticate HTTP basic only, while
ghcr.io, Docker Hub and Quay all require a Bearer-token exchange. It
is non-null only where the customer pinned a digest themselves. A
client must not derive one from imageReference.
image_referenceThe image this deployment shipped, as ${service.image} resolved when
the deployment started.
A fact about the past, not about now. It is captured when the
deployment begins, because that is the only moment it exists: the value
lives on the instance's configuration and the customer overwrites it on
their next tag change. A client comparing this with the Source
capability's current reference is comparing "what is running" with
"what is saved", which is the question 00-program.md §8 is about.
null for a deployment from before the provenance migration and for a
product whose image the customer does not choose. It is not
reconstructable, so null here means the answer is gone rather than
that it is available from another route.
Whether the rollout applied: succeeded, failed, or null.
null is "not recorded", never a failure. It is every deployment
from before the provenance migration, every one still running, and
every holder that died or was forced open before it could say. Nothing
is backfilled and nothing can be, so a panel renders null as an
absence rather than as a red badge.
Separate from status on purpose: a failed deployment is ended and
failed at once, because the handler releases its lease on its error
path too.
Get Service Instance Environment
Lists this service's environment variables. A secret's value is always null: the browser never holds a secret's value, and null rather than a placeholder is the only unambiguous answer, because "[redacted]" is a string a customer can also type. Use revealServiceInstanceEnvironmentSecret to read one back, which is recorded. applies is kernel's verdict about when a change reaches the running container, not the client's guess, and it is restart for every variable today because environment renders into the pod template and there is no delivery path by which a running container picks up a change without a new pod. pending says whether the running container is still on older values, compared against what was last applied to the cluster rather than against local state, so a page reload does not make the banner disappear. 404 for a service whose product does not offer this capability, which is the same answer a service belonging to somebody else gives.
path Parameters
idGet Service Instance Environment › Responses
The variables, with every secret's value masked
secrets_allowedWhether this product's customers may store secrets at all. A panel that inferred this from a product slug would be computing a verdict.
Ordered by key, so two reads of an unchanged service agree.
Whether the running container is still on older values, and which act
would pick them up. null when nothing is outstanding.
On the envelope rather than left to the client's local state, because a page reload must not make the banner disappear while the container is still running the old values.
Set Service Instance Environment Variable
Creates or replaces one environment variable, keyed on the path segment. One row at a time rather than a whole-array replace: once secrets are masked there is nothing for a client to send back for the rows it did not touch, so an array write would delete every secret it failed to re-supply. Omitting value (or sending null) means keep the stored value, and is accepted only for a secret that is already stored and is staying secret, since those are the only rows the client was never shown; anywhere else it is a 400 rather than a silently stored empty string. Moving a variable between plain and secret is this same request with a different secret, and the variable moves rather than being duplicated. ZAROZ_AUTH_TOKEN is reserved by the platform. Refused with a business-rule error when the product does not allow secrets. Takes a configuration-change lease, so it is refused with 409 while another operation holds this service, and re-renders the workload on success. A successful write appears in this service's deployment history as a config_change deployment, with a number a customer can cite and a summary naming this key. The response carries the row's own applies, so a client stops assuming the safe answer. pending says whether the re-render actually happened: saving and applying are separate acts, the commonest reason the second does not follow the first is a subscription that is not active yet, and a panel that reported the save as done would tell a customer rotating a leaked credential that the old value is gone while it is still live in the running container. The audit entry names the key and never the value.
path Parameters
keyidSet Service Instance Environment Variable › Request Body
secretMoving a variable between plain and secret is this same request with a different value here.
valueAbsent or null means keep the stored value, and is accepted only
for a secret that is already stored and is staying secret: those are
the only rows the client was never shown. Anywhere else it is a 400,
never an empty string.
Set Service Instance Environment Variable › Responses
The stored variable, with a secret's value still masked
When changing this reaches the running container. Kernel's verdict.
idStable for as long as the key is.
Derived from the key rather than stored, so renaming a variable changes its id. Good enough to key a table row and an open dialog on; not durable, and nothing should persist it.
keysecretWhether the running container is still on an older value after the
request that produced this row, and which act would pick the new one
up. null means nothing is outstanding.
Only a write answers this. In a list read every row carries null and
[EnvironmentResponse::pending] on the envelope is the verdict for
the set, because staleness is compared against the whole rendered
workload rather than row by row. A write has no envelope to put it on
and does know the answer for its own change: saving succeeded but the
re-render did not, which is the case a panel must not report as done.
valuenull when secret is true, always.
Not "[redacted]": that is a string a customer can also type, so a
client could not tell a masked value from a real one, and null is
the only unambiguous answer.
Delete Service Instance Environment Variable
Deletes one environment variable, plain or secret. A key that is not stored is a 404 on the row rather than a silent success, so a client cannot show a customer a change that did not happen. Takes a configuration-change lease and re-renders the workload, exactly as the write does, so it appears in this service's deployment history as a config_change deployment whose summary names the key that was removed. Returns the whole remaining set, because there is no row left to return. The audit entry names the key.
path Parameters
keyidDelete Service Instance Environment Variable › Responses
What remains, with every secret's value masked
secrets_allowedWhether this product's customers may store secrets at all. A panel that inferred this from a product slug would be computing a verdict.
Ordered by key, so two reads of an unchanged service agree.
Whether the running container is still on older values, and which act
would pick them up. null when nothing is outstanding.
On the envelope rather than left to the client's local state, because a page reload must not make the banner disappear while the container is still running the old values.
Reveal Service Instance Environment Secret
Returns one secret variable's plaintext, once, and records that it was read. Its own request rather than a query parameter on the list, so that the ordinary read stays structurally incapable of leaking a value and so that the audit entry covers exactly the act that needs it. A POST rather than a GET for the same reason: the entry is written before the value is handed over, and the key never lands in an access log alongside a cacheable response. Gated on the same permission as changing the service, not on the permission to see it: an ordinary member may list a service's variables and may not read its credentials back. 400 for a variable that is not a secret; 404 for one that is not stored.
path Parameters
keyidReveal Service Instance Environment Secret › Responses
The secret's plaintext
keyvalueGet Service Instance Runtime Config
How this service's container is started. entrypoint and command are the two the platform actually renders; command is one string, tokenised by kernel, because a client splitting a command line would be computing a value. null means the image's own declaration is used, and is a different answer from an empty string. imageDefaultsAvailable reports whether kernel could actually ask the image's registry this time: true and a null imageDefault means the image declares nothing there; false means the registry could not be asked (an unreachable host, an address kernel refuses to dial, or a registry -- Docker Hub and GHCR among them -- that demands a bearer-token exchange this inspector does not perform), and every imageDefault is null regardless of what the image actually declares, because reporting "the image declares nothing" when the truth is "the registry was never asked" would be a lie told in the customer's own words. workingDirectory's imageDefault is populated the same way even though its value stays refused on write below. stopSignal, stopGracePeriodSeconds, preDeployCommand and postDeployCommand are reported as unset and refused on write, because none of them has a delivery mechanism today and storing a value that changes nothing would make this panel state a falsehood: nothing renders a container workingDir override; the kubelet always sends SIGTERM and STOPSIGNAL is a property of the image rather than something a pod specification can override, which is why stopSignals is empty; the termination grace period is hardcoded to 60 seconds; and there is no post-rollout mechanism at all.
path Parameters
idGet Service Instance Runtime Config › Responses
The startup overrides, beside what the image declares
One startup value beside the one the image itself declares.
One startup value beside the one the image itself declares.
Kernel's verdict for the deploy commands, which is genuinely different: a pre-deploy command cannot be picked up by a restart, because a restart is not a deployment.
image_defaults_availableFalse when the registry could not be asked at all.
Kernel's verdict for the startup fields, which share one.
stop_signalsThe signals a customer may choose. Closed, because the platform decides, and supplied rather than hardcoded in the client for the same reason a region is never free text.
Empty today, and that is the honest answer rather than an oversight:
there is no signal the platform can deliver but SIGTERM. A panel
renders no options and therefore offers no choice, which is exactly
the state of the world.
One startup value beside the one the image itself declares.
Whether the running container is still started the old way, and which
act would pick the new configuration up. null when nothing is
outstanding.
Same meaning and same reason as
[EnvironmentVariableResponse::pending]: a save that could not be
re-rendered is still a save, and the panel has to be able to say so.
post_deploy_commandpre_deploy_commandstop_grace_period_secondsAlways null today, meaning the platform's own 60 seconds.
stop_signalAlways null: the kubelet always sends SIGTERM and a pod spec
cannot override an image's STOPSIGNAL.
Update Service Instance Runtime Config
Replaces the whole startup configuration. One PUT rather than a field at a time, because unlike the variables list this genuinely is one form with one save button and no per-row identity. null means follow the image's own declaration; an empty string is refused rather than collapsed into it, since "use the image's" and "override with nothing" are different instructions and only the first is something a container can be given. command is one string and is tokenised here, honouring single quotes, double quotes and backslash escapes; it is deliberately not wrapped in a shell, because inserting /bin/sh -c would put a process between the kubelet and the customer's program and change what receives SIGTERM. workingDirectory, stopSignal, stopGracePeriodSeconds, preDeployCommand and postDeployCommand are refused with the reason, because none of them has a delivery mechanism today and storing a value that changes nothing would make the panel state a falsehood in the customer's own words. Takes a configuration-change lease, so it is refused with 409 while another operation holds this service, and re-renders the workload on success, reporting through pending when that re-render did not happen. It appears in this service's deployment history as a config_change deployment; the summary says the run settings changed and quotes neither the entrypoint nor the command, both of which routinely carry credentials.
path Parameters
idUpdate Service Instance Runtime Config › Request Body
commandOne string, tokenised by kernel. A client splitting a command line
would be a component computing a value (R2).
entrypointpost_deploy_commandRefused when not null; there is no post-rollout mechanism at all.
pre_deploy_commandRefused when not null; nothing renders an init container from this.
stop_grace_period_secondsThe text that was typed, unparsed, so a browser that rounds or clamps
cannot decide a value the scheduler owns. Refused when not null;
the grace period is hardcoded in the Kubernetes renderer today.
stop_signalRefused when not null; see [RuntimeConfigResponse::stop_signals].
working_directoryRefused when not null; nothing renders a workingDir today.
Update Service Instance Runtime Config › Responses
The stored startup configuration
One startup value beside the one the image itself declares.
One startup value beside the one the image itself declares.
Kernel's verdict for the deploy commands, which is genuinely different: a pre-deploy command cannot be picked up by a restart, because a restart is not a deployment.
image_defaults_availableFalse when the registry could not be asked at all.
Kernel's verdict for the startup fields, which share one.
stop_signalsThe signals a customer may choose. Closed, because the platform decides, and supplied rather than hardcoded in the client for the same reason a region is never free text.
Empty today, and that is the honest answer rather than an oversight:
there is no signal the platform can deliver but SIGTERM. A panel
renders no options and therefore offers no choice, which is exactly
the state of the world.
One startup value beside the one the image itself declares.
Whether the running container is still started the old way, and which
act would pick the new configuration up. null when nothing is
outstanding.
Same meaning and same reason as
[EnvironmentVariableResponse::pending]: a save that could not be
re-rendered is still a save, and the panel has to be able to say so.
post_deploy_commandpre_deploy_commandstop_grace_period_secondsAlways null today, meaning the platform's own 60 seconds.
stop_signalAlways null: the kubelet always sends SIGTERM and a pod spec
cannot override an image's STOPSIGNAL.
Get Process Tree
Returns the live process tree (pid/ppid, %CPU, memory, uptime) inside a workload's container, from the terminal-bridge agent. Past the guard it always answers 200: status distinguishes a healthy snapshot (ok) from the workload being offline (not_running), the bridge being too old to support the call (unsupported), or a transient bridge failure (unavailable), so the page can explain instead of erroring.
path Parameters
idresource_idThe workload whose processes are wanted.
The workload whose processes are wanted.
Get Process Tree › Responses
Always a 200 with a discriminated status: a tree being unavailable is an
expected outcome the page renders an explanation for, not an HTTP error.
truncatedroot_pidList Service Instance Runs
This service's run history, newest first by when the run was due (a manual trigger, which has no due time, sorts as the most recent activity rather than to the bottom). A row exists for every DECIDED run, including one that never executed: outcome names skipped_overlap, skipped_condition or missed for those, with a skipReason explaining why. outcome is null exactly while a fired run is in flight -- decided, not yet concluded -- never a seventh status string. startedAt is when the pod started (its gap from scheduledFor is the queue delay) and finishedAt, exitCode and terminationReason (OOMKilled, DeadlineExceeded, Evicted, ...) are filled in when the run ends. Resource consumption (peakCpuMillicores, peakMemoryBytes) and captured logs are not recorded yet. 404 for a service whose product does not offer this capability, which is the same answer a service belonging to somebody else gives.
path Parameters
idquery Parameters
pagePage number (1-indexed). Defaults to 1.
Page number (1-indexed). Defaults to 1.
page_sizeNumber of items per page. Defaults to 20, max 100.
Number of items per page. Defaults to 20, max 100.
List Service Instance Runs › Responses
This instance's run history
Pagination metadata included in paginated responses
Trigger Service Instance Run
Runs the service now: records a manual run (trigger.kind: "manual", naming the caller) that the kernel's scheduler launches as a Job within about ten seconds. A 200 means the run is queued, not that the container started: poll getServiceInstanceRun until startedAt and then outcome are set. Refused (422) while the subscription is not entitled to run now, such as when suspended, and (429) once the service already has five runs in progress. Takes no body and no operation lease.
path Parameters
idTrigger Service Instance Run › Responses
The queued run
created_atidWho or what caused a run to be decided.
exit_codefinished_atnull until the run concludes, and always null for a skip.
log_object_keyA pointer to this run's captured log, if one was captured. null
today: log capture is a later slice.
null exactly while a fired run is in flight: decided, not yet
concluded. See this module's header -- do not treat this as a status
string with a seventh "running" value.
peak_cpu_millicorespeak_memory_bytesscheduled_forWhen this run was due. null for a manual trigger, which has no due
time by construction.
skip_reasonWhy a run was skipped or missed. null for one that fired.
started_atnull for a run that was skipped, or one that has not started yet.
termination_reasonThe Kubernetes termination reason, e.g. OOMKilled. null unless the
run concluded abnormally.
Get Service Instance Run
Reads one run. A run_id naming a run that does not exist, or one belonging to a different service instance, is a 404 -- the same answer either way, so this route cannot be used to probe for another tenant's run ids.
path Parameters
run_ididGet Service Instance Run › Responses
The run
created_atidWho or what caused a run to be decided.
exit_codefinished_atnull until the run concludes, and always null for a skip.
log_object_keyA pointer to this run's captured log, if one was captured. null
today: log capture is a later slice.
null exactly while a fired run is in flight: decided, not yet
concluded. See this module's header -- do not treat this as a status
string with a seventh "running" value.
peak_cpu_millicorespeak_memory_bytesscheduled_forWhen this run was due. null for a manual trigger, which has no due
time by construction.
skip_reasonWhy a run was skipped or missed. null for one that fired.
started_atnull for a run that was skipped, or one that has not started yet.
termination_reasonThe Kubernetes termination reason, e.g. OOMKilled. null unless the
run concluded abnormally.
List Service Instance Schedules
Lists this service's cron schedules. A subscription may own many, each with its own cron expression, timezone, overlap policy, timeout and guard conditions. The kernel's scheduler fires them (Kubernetes only executes), so each answers nextFireAt and upcomingFireTimes (UTC; empty while paused), computed by the same code that fires them. Whether a schedule has ever fired is in listServiceInstanceRuns. 404 for a service whose product does not offer this capability, which is the same answer a service belonging to somebody else gives.
path Parameters
idquery Parameters
pagePage number (1-indexed). Defaults to 1.
Page number (1-indexed). Defaults to 1.
page_sizeNumber of items per page. Defaults to 20, max 100.
Number of items per page. Defaults to 20, max 100.
List Service Instance Schedules › Responses
This instance's schedules
Pagination metadata included in paginated responses
Create Service Instance Schedule
Creates one cron schedule on this service instance. Does not deploy or reconfigure anything: this saves a row the kernel's scheduler reads within ten seconds, and takes no operation lease. cronExpression is a standard five-field expression (minute hour day-of-month month day-of-week; no seconds, no @daily nicknames) and timezone an IANA name such as Europe/Helsinki; both are parsed by the scheduler's own parser, so one that saves is one that fires. A service owns at most twenty schedules. timeoutSeconds must be positive and is capped at an absolute ceiling (currently six hours) so a customer cannot author a container that Kubernetes will never terminate on its own -- a per-plan cap will replace this ceiling later. Every httpCheck condition's URL is resolved and refused if it points at a private, loopback, or otherwise non-public address, since kernel itself will eventually fetch it. Every jobSucceededSince condition's scheduleId must name one of this instance's own schedules; one that does not exist and one belonging to another tenant are refused identically, so this field cannot be used to probe for another organization's schedule ids. action is what each fire does and is required: run_job starts the service's job and is accepted only by a cron-job service; tasks (1 to 25) performs, in order, console commands, executables, start / stop / restart, backups and waits, each starting only after the one before it succeeded (the first failure ends the run), and is accepted by every other service. The wrong one for the service is refused with 400. With tasks, timeoutSeconds is not used (each task has its own).
path Parameters
idCreate Service Instance Schedule › Request Body
What each fire does (V-0702). Required: run_job for a cron-job
service, tasks for any other.
cron_expressionFive space-separated fields. Syntax only is checked here and in the domain; computing the next fire time is the scheduler's job, out of scope for this slice.
nameThe three concurrency policies a schedule may declare. Mirrors
[OverlapPolicy] one for one; see this module's header for why it is not
reused directly.
timeout_secondstimezoneAn IANA zone name, e.g. Europe/Helsinki. Checked syntactically only:
this platform does not carry a timezone database yet, and adding one
is a dependency decision for the owner, not this slice.
pausedCreate Service Instance Schedule › Responses
The created schedule
What each fire does.
created_atcron_expressionidinvalidtrue when the stored schedule no longer validates (for example its
time zone is no longer known): it cannot fire until it is edited.
Every other field is the stored value as it is.
nameThe three concurrency policies a schedule may declare. Mirrors
[OverlapPolicy] one for one; see this module's header for why it is not
reused directly.
pausedtimeout_secondstimezoneupcoming_fire_timesThe next few fires after now (at most [UPCOMING_FIRE_TIMES]), in UTC;
empty while paused. The same computation the scheduler runs, so what is
shown is what will happen, daylight-saving changes included.
updated_atinvalid_reasonWhy the schedule is invalid; null when it is valid.
next_fire_atThe next instant the kernel's scheduler will fire this schedule, in UTC.
null while the schedule is paused or invalid, or when the expression never
matches again.
Update Service Instance Schedule
Replaces one schedule's whole configuration. A schedule_id naming a schedule that does not exist, or one belonging to a different service instance, is a 404 -- the same answer either way, since a distinguishable refusal would turn this route into an oracle for which schedule ids exist. The same absolute timeout ceiling, URL guard, and cross-instance schedule check createServiceInstanceSchedule applies also apply here, so a customer cannot raise a timeout or add a condition through an update that creation would have refused. Takes no operation lease and does not reconfigure the running workload.
path Parameters
schedule_ididUpdate Service Instance Schedule › Request Body
What each fire does (V-0702). Required: run_job for a cron-job
service, tasks for any other.
cron_expressionnameThe three concurrency policies a schedule may declare. Mirrors
[OverlapPolicy] one for one; see this module's header for why it is not
reused directly.
timeout_secondstimezonepausedUpdate Service Instance Schedule › Responses
The schedule as it now stands
What each fire does.
created_atcron_expressionidinvalidtrue when the stored schedule no longer validates (for example its
time zone is no longer known): it cannot fire until it is edited.
Every other field is the stored value as it is.
nameThe three concurrency policies a schedule may declare. Mirrors
[OverlapPolicy] one for one; see this module's header for why it is not
reused directly.
pausedtimeout_secondstimezoneupcoming_fire_timesThe next few fires after now (at most [UPCOMING_FIRE_TIMES]), in UTC;
empty while paused. The same computation the scheduler runs, so what is
shown is what will happen, daylight-saving changes included.
updated_atinvalid_reasonWhy the schedule is invalid; null when it is valid.
next_fire_atThe next instant the kernel's scheduler will fire this schedule, in UTC.
null while the schedule is paused or invalid, or when the expression never
matches again.
Delete Service Instance Schedule
Deletes one schedule outright. Its run history is not deleted with it: service_runs.schedule_id is ON DELETE SET NULL precisely so a deleted schedule's history survives, and this route performs a plain repository delete with no application-level cascade that would defeat that. A schedule_id naming a schedule that does not exist, or one belonging to a different service instance, is a 404.
path Parameters
schedule_ididDelete Service Instance Schedule › Responses
Deleted
Run Service Instance Schedule Now
Runs this schedule now: records a manual run (trigger.kind: "manual", naming the caller and the schedule) that the kernel's scheduler executes within about ten seconds. A schedule with tasks performs them in order through the same services the console uses (so a task waits its turn behind a manual action instead of colliding with it); one without starts the service's job. The schedule's guard conditions are not evaluated. A 200 means the run is queued: poll getServiceInstanceRun until outcome is set; its terminationReason lists what each task did. Refused with 409 while the schedule's overlap policy forbids another run (skip: any run in progress; queue: one already waiting), 429 at the service-wide ceiling of five runs in progress, and 422 for a schedule that is invalid or a subscription that is not entitled to run now. A schedule that is not this service's is a 404. Takes no body.
path Parameters
schedule_ididRun Service Instance Schedule Now › Responses
The queued run
created_atidWho or what caused a run to be decided.
exit_codefinished_atnull until the run concludes, and always null for a skip.
log_object_keyA pointer to this run's captured log, if one was captured. null
today: log capture is a later slice.
null exactly while a fired run is in flight: decided, not yet
concluded. See this module's header -- do not treat this as a status
string with a seventh "running" value.
peak_cpu_millicorespeak_memory_bytesscheduled_forWhen this run was due. null for a manual trigger, which has no due
time by construction.
skip_reasonWhy a run was skipped or missed. null for one that fired.
started_atnull for a run that was skipped, or one that has not started yet.
termination_reasonThe Kubernetes termination reason, e.g. OOMKilled. null unless the
run concluded abnormally.
Get Service Instance Source
What this service runs, and the ways this product lets a customer change it. source is null for a service that has been paid for and never configured, which is the panel's empty state rather than an error. A registry source carries credentialUsername and never a password: the browser is never given one, and there is no route that reads one back. permittedArms is the product's own declaration, so a panel never holds the list as a literal; a product permitting exactly one arm renders no chooser, because a radio group with a single option asks a question with one answer. imageReference is what the next deployment will pull, composed here rather than in the client because the rules that build it are the platform's. pending compares that against what the primary workload is actually running, and is null when the resources could not be read, which is a different statement from false. watchTag is always false: nothing polls a registry for a moved tag, so the flag would promise a redeploy that never happens. 404 for a service whose product does not offer this capability, which is the same answer a service belonging to somebody else gives.
path Parameters
idGet Service Instance Source › Responses
What runs, and the arms this product permits
The arms this product permits, in the order it declared them.
A product with exactly one permitted arm renders no chooser at all: a radio group with a single option is a control that asks a question with one answer. Supplied by kernel rather than held as a frontend literal, for the same reason a region list is.
watch_tagWhether the platform re-pulls when the tag moves.
Always false, and that is the honest answer rather than a
placeholder. Nothing polls a registry for a moved tag, so there is no
watcher to turn on; a stored flag would promise a redeploy that never
happens, which 12-source.md §8 names as the failure to avoid and then
asks for anyway. A write that sets it is refused with the reason.
image_referenceThe reference the next deployment will pull, null when nothing has
been chosen.
Composed here rather than in the panel (R2), because the rules that
build it are the platform's: a digest wins over a tag, and Docker Hub's
own images live under library/.
pendingWhether what is running differs from what is saved.
null means kernel could not tell, because the instance's resources
could not be read. That is a third answer on purpose: false would
claim the running workload is up to date, which is a statement rather
than an absence of one.
running_imageThe reference the workload is running right now, read off the
instance's primary resource. null when nothing is deployed.
What this service runs, or null for one that has not been told yet.
null is the panel's empty state and covers a subscription that has
been paid for and never configured. It is not an error and it is not a
broken service.
Set Service Instance Source
Chooses what this service runs. It does not start it. Saving here changes what the next deployment will pull; no rollout, no restart and no deployment happen on this request, which is the whole reason Source and Deployments are separate capabilities. An arm this product does not permit is refused with the arms it does, and an arm the platform cannot serve is refused with the reason: nothing in the platform clones or builds a repository, so the git arm has no write path today. credentials has three states, because two cannot express them: absent leaves the stored login alone, null clears it and pulls anonymously, and an object replaces it. Both halves or neither; a username with no password is refused while the form is still open. The password is never returned by any route. A Docker Hub repository with no namespace is qualified with library/, because that is where Docker publishes its own images and the registry answers for nothing else. A host that names an address inside the platform's own network is refused, since the pull happens from inside the cluster with the customer's credential attached. watchTag is refused when true: nothing polls a registry for a moved tag, and a flag with no watcher behind it promises a redeploy that never happens. Takes a reconfigure lease, so it is refused with 409 while another operation holds this service. A service with no configuration at all is given one, which is how a Container bought unconfigured gets its image.
path Parameters
idSet Service Instance Source › Request Body
Decision Table
| Variant | Matching Criteria |
|---|---|
| type = object · requires: host, repository, tag +1 more | |
| type = object · requires: kind | |
| type = object · requires: kind | |
| type = object · requires: kind |
kindhostghcr.io, docker.io, registry.example.com:5000.
repositoryacme/worker. A single-segment repository on Docker Hub is qualified
with library/ by kernel, so a customer types nginx.
tagThree states, and two would not be enough.
| Body | Meaning |
|---|---|
| field absent | leave the stored credentials alone |
null | clear them, pull anonymously |
{ username, password } | replace them |
An Option that is None would have to mean either "unchanged" or
"clear", and whichever it meant, the other would be unreachable from a
panel that is never shown the password it would otherwise resend.
watch_tagAccepted so a client that sends it gets an answer rather than silence,
and refused when true. See [SourceResponse::watch_tag].
Set Service Instance Source › Responses
What runs now, and whether it has been deployed
The arms this product permits, in the order it declared them.
A product with exactly one permitted arm renders no chooser at all: a radio group with a single option is a control that asks a question with one answer. Supplied by kernel rather than held as a frontend literal, for the same reason a region list is.
watch_tagWhether the platform re-pulls when the tag moves.
Always false, and that is the honest answer rather than a
placeholder. Nothing polls a registry for a moved tag, so there is no
watcher to turn on; a stored flag would promise a redeploy that never
happens, which 12-source.md §8 names as the failure to avoid and then
asks for anyway. A write that sets it is refused with the reason.
image_referenceThe reference the next deployment will pull, null when nothing has
been chosen.
Composed here rather than in the panel (R2), because the rules that
build it are the platform's: a digest wins over a tag, and Docker Hub's
own images live under library/.
pendingWhether what is running differs from what is saved.
null means kernel could not tell, because the instance's resources
could not be read. That is a third answer on purpose: false would
claim the running workload is up to date, which is a statement rather
than an absence of one.
running_imageThe reference the workload is running right now, read off the
instance's primary resource. null when nothing is deployed.
What this service runs, or null for one that has not been told yet.
null is the panel's empty state and covers a subscription that has
been paid for and never configured. It is not an error and it is not a
broken service.
Issue Registry Token
The container registry's token endpoint, the realm of its Bearer challenge (Docker token authentication). Send the registry credential as HTTP Basic auth and the requested scopes (repository:<namespace>/<repo>:pull,push, repeatable); the answer is a short-lived signed bearer token the registry verifies. Anything the credential may not do is left out of the token rather than refused, so another tenant's namespace cannot be probed. Invalid credentials answer 401, a suspended, unpaid or deleted registry 403.
Issue Registry Token › Responses
A bearer token carrying the granted access.
access_tokenThe same token: OAuth2-style clients read this name.
expires_inSeconds the token stays valid.
issued_attokenThe signed bearer token the registry verifies.
List Subscription Registry Tags
Lists the tags of one repository (path below the registry's namespace), newest first, with each tag's digest, size and build time.
path Parameters
idquery Parameters
pathThe repository path below the registry's namespace, e.g. app/web.
The repository path below the registry's namespace, e.g. app/web.
List Subscription Registry Tags › Responses
OK
truncatedThe repository has more tags than one listing describes; only the first ones (in the registry's order) are shown.
Delete Subscription Registry Tag
Deletes one tag (tag) of a repository (path). The image stays reachable under its other tags; storage is reclaimed by garbage collection.
path Parameters
idquery Parameters
pathThe repository path below the registry's namespace, e.g. app/web.
The repository path below the registry's namespace, e.g. app/web.
tagThe tag to delete.
The tag to delete.
Delete Subscription Registry Tag › Responses
Deleted
List Bucket Objects
Lists the folders and objects directly under prefix (delimiter /), one page at a time (at most 200). Metadata only: listing is not billed.
path Parameters
idquery Parameters
prefixThe folder to list: empty for the bucket root, else a path ending in / (a missing trailing slash is added).
The folder to list: empty for the bucket root, else a path ending in / (a missing trailing slash is added).
tokennext_token of the previous page.
next_token of the previous page.
limitPage size, 1 to 200 (default 100).
Page size, 1 to 200 (default 100).
List Bucket Objects › Responses
One page
Sign Bucket Object Download
Signs a short-lived (15 minutes) GET for one object. The download goes straight to the object storage endpoint and is billed as egress exactly like any S3 client's: previews and thumbnails count too. Refused while the bucket is suspended.
path Parameters
idSign Bucket Object Download › Request Body
keysave_asMakes the browser save the file under this name instead of showing it.
Sign Bucket Object Download › Responses
The signed URL
A GET. Billed egress, like any S3 download.
Start Bucket Object Upload
Starts an upload of size_bytes. Up to 64 MiB: a signed PUT of exactly that many bytes. Larger (up to 625 GiB): a multipart upload. Uploads are free (ingress is not billed). Refused when the bucket is over its cap, the upload would take it over, or the bucket is suspended.
path Parameters
idStart Bucket Object Upload › Request Body
keysize_bytesThe exact size in bytes. A single PUT is signed for exactly this many.
content_typeStart Bucket Object Upload › Responses
How to upload
Sign Bucket Upload Parts
Signs PUT URLs for the given 1-based part numbers (at most 50 per call) of a multipart upload. Each part is signed for its exact length.
path Parameters
idSign Bucket Upload Parts › Request Body
keyparts1-based part numbers, at most 50 per request.
size_bytesThe object's total size, as given to start the upload.
upload_idSign Bucket Upload Parts › Responses
Part URLs
Abort Bucket Upload
Delete Bucket Objects
Deletes up to 1000 objects by key. Allowed while the bucket is over its cap; refused while it is suspended.
path Parameters
idDelete Bucket Objects › Responses
What failed
