Kaiten

Deployments

Deployment Zones

Shared and dedicated zones — what a deployment zone models, how releases and instances relate to one, and where the dedicated model meets Kaiten's own editions.

A deployment zone is a logical execution environment where instances run. It is the unit at which a release lands and the place an instance attaches to. A zone is not a cluster, a cloud account, or a region by itself — those are properties a zone may carry — but the thing that has a current release and a set of instances at the same time.

Examples use $KAITEN_API and $KAITEN_TOKEN as set up in the quickstart, and add to the seeded Kaiten Sushi Shop zones without altering them. Responses are illustrative — ids, actors, and timestamps depend on your stack.

What a zone models

Two isolation models, one entity:

  • A shared zone runs instances of many customers side by side — one operated stack of your product serving several restaurants. Kaiten Sushi Shop runs two: shared-eu and shared-apac.
  • A dedicated zone runs the instances of one customer alone — its own stack, upgraded on its own schedule. Sakura Tokyo's sakura-dedicated is one; its metadata records compliance_profile: pci-dss, the reason it exists.

Both are the same record with the same fields, and nothing in the record's structure separates them: Kaiten Sushi Shop says which is which with a boolean metadata field, dedicated, set to true on sakura-dedicated alone. What differs is how you operate them, and the model makes that visible: the three seeded zones hold three journal histories, and the dedicated one still runs 2026.7.0 while both shared zones moved to 2026.8.0 — a fact the journal shows and the contract can be compared against.

The Deployment Zones list of Kaiten Sushi Shop: Shared APAC and Shared EU, both of type Production and on release 2026.8.0, and Sakura Dedicated, of type Production and still on 2026.7.0, each with the count of releases it has run and of its instances.The Deployment Zones list of Kaiten Sushi Shop: Shared APAC and Shared EU, both of type Production and on release 2026.8.0, and Sakura Dedicated, of type Production and still on 2026.7.0, each with the count of releases it has run and of its instances.

Fields

FieldRequiredWhat it holds
nameyesDisplay name, at least 1 character
typeyesEnvironment class of the zone, free-form — see below
descriptionyesFree text
slugno2–100 characters, ^[a-z0-9][a-z0-9-]*[a-z0-9]$, unique per organization; generated when omitted
metadatanoTyped properties, validated against the DEPLOYMENT_ZONE metadata fields your organization declared
releaseIdnoThe release the zone currently runs

Responses add id, createdBy, createdAt, updatedBy, and updatedAt. Reading requires read:deployment_zones; every write requires write:deployment_zones.

type is the zone's environment class. The API stores any string as sent and exposes it to targeting rules as __kaiten.deploymentZone.type; production, staging, and development are the values the console labels. Kaiten Sushi Shop follows that convention, and its three zones are all production — whether a zone is shared or dedicated is not an environment, so it is not recorded here. Pick one convention and hold to it: rules and filters compare the raw value.

metadata is where the infrastructure facts go. Kaiten Sushi Shop declares three zone fields — compliance_profile (Compliance profile), an enum of standard and pci-dss; region (Cloud region), free text; and dedicated (Dedicated), a boolean — so every zone carries them in a shape the console renders and a rule can read. A write whose metadata does not conform to the declared fields is rejected.

Create a zone

Open a shared zone for North American restaurants, already running the current release. Supplying releaseId at creation records the zone's first deployment — one journal entry, one RELEASE_DEPLOYED. Look up the release's id — a zone takes the id, not the slug. The seeded 2026.8.0 is also addressable as r-2026-8-0; finding it by version in the list works on any stack:

export RELEASE_280_ID=$(curl -s "$KAITEN_API/releases" \
  -H "Authorization: Bearer $KAITEN_TOKEN" \
  | jq -r '.items[] | select(.version == "2026.8.0") | .id')
curl -X POST "$KAITEN_API/deployment-zones" \
  -H "Authorization: Bearer $KAITEN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Shared US",
    "slug": "shared-us",
    "type": "production",
    "description": "Shared zone for North American restaurants.",
    "metadata": { "region": "us-east-1", "compliance_profile": "standard", "dedicated": false },
    "releaseId": "'"$RELEASE_280_ID"'"
  }'
{
  "id": "5e6f7a8b-9c0d-4e1f-a2b3-c4d5e6f7a8b9",
  "name": "Shared US",
  "slug": "shared-us",
  "type": "production",
  "description": "Shared zone for North American restaurants.",
  "metadata": { "region": "us-east-1", "compliance_profile": "standard", "dedicated": false },
  "releaseId": "2b6f9c1e-8d3a-4f7b-9e0c-6a5d4b3c2f1e",
  "createdBy": { "id": "…", "name": "…" },
  "createdAt": "2026-09-08T11:00:00Z",
  "updatedBy": { "id": "…", "name": "…" },
  "updatedAt": "2026-09-08T11:00:00Z"
}

201 Created; DEPLOYMENT_ZONE_CREATED and RELEASE_DEPLOYED are emitted. A slug already in use is a 409. A compliance_profile outside the declared enum — "hipaa", say — is refused, because the metadata field says what is allowed there.

A zone created without releaseId exists with nothing deployed: it has no releaseId until the first PUT that sets one.

Update a zone

PUT /deployment-zones/{slug} replaces the zone's details — name, type, and description are required again, and metadata is written as sent. Send everything you want to keep.

curl -i -X PUT "$KAITEN_API/deployment-zones/shared-us" \
  -H "Authorization: Bearer $KAITEN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Shared US East",
    "type": "production",
    "description": "Shared zone for North American restaurants (US East).",
    "metadata": { "region": "us-east-1", "compliance_profile": "standard", "dedicated": false },
    "releaseId": "'"$RELEASE_280_ID"'"
  }'

HTTP/1.1 204 No Content; DEPLOYMENT_ZONE_UPDATED is emitted. The releaseId in this call echoes the current one, so the journal is untouched — omitting it has the same effect. Sending a different releaseId is how a deployment is recorded; that is the subject of Deployments & Lifecycle.

How instances relate to zones

An instance optionally points at one zone, through deploymentZoneId; responses also carry the zone's slug as deploymentZoneSlug. The link is the whole of the runtime association: an instance runs whatever its zone currently runs, and that is a lookup — instance → zone → releaseId — not a field you maintain on the instance. The six seeded instances are spread across the three zones: sakura-tokyo-prod alone in sakura-dedicated; demo-restaurant-prod in shared-eu; and sakura-tokyo-demo, ninja-osaka-prod, ninja-osaka-delivery, and kappa-kyoto-prod side by side in shared-apac — one Customer can have an instance in a dedicated zone and another in a shared one.

Placing an instance in a zone emits INSTANCE_DEPLOYED; moving it from one zone to another emits INSTANCE_MIGRATED.

At creation. POST /instances accepts deploymentZoneId, and the instance is placed from its first moment. A staging instance for Sakura Tokyo, on the current version of its Premium License, in the shared APAC zone:

curl -X POST "$KAITEN_API/instances" \
  -H "Authorization: Bearer $KAITEN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Sakura Tokyo Staging",
    "slug": "sakura-tokyo-staging",
    "description": "Staging instance for the Sakura Tokyo restaurant group.",
    "customerId": "'"$SAKURA_TOKYO_ID"'",
    "licenseId": "'"$PREMIUM_ID"'",
    "deploymentZoneId": "'"$SHARED_APAC_ID"'",
    "startLicenseDate": "2026-09-01T00:00:00Z",
    "endLicenseDate": "2027-09-01T00:00:00Z",
    "metadata": { "environment": "staging" }
  }'

The ids come from GET /customers/sakura-tokyo, GET /deployment-zones/shared-apac, and GET /license-families/premium, whose currentVersion.id is the version the Premium family serves — premium-v2. GET /licenses/premium would return the family's first version, which is archived: assigning it to an instance is refused with 422 Unprocessable Entity. metadata is the instance's only free-form object, and it is typed like the zone's: every key a declared INSTANCE metadata field covers is validated against that field (Kaiten Sushi Shop declares environment, an enum of production, staging, and demo), and keys no field declares are kept as sent. There is no separate infrastructure object on an instance: a region or a runtime, if you want the model to know and the console to render them, are metadata fields you declare. The 201 response carries the placement:

{
  "id": "…",
  "name": "Sakura Tokyo Staging",
  "slug": "sakura-tokyo-staging",
  "customerId": "…",
  "customerSlug": "sakura-tokyo",
  "licenseId": "…",
  "licenseSlug": "premium-v2",
  "deploymentZoneId": "…",
  "deploymentZoneSlug": "shared-apac",
  "status": "HEALTHY",
  "metadata": { "environment": "staging" },
  "…": "…"
}

Later. PUT /instances/{slug} with a different deploymentZoneId moves the instance. The same call with deploymentZoneId omitted preserves the current zone, and clearing the link back to "no zone" is not supported through this endpoint. PUT on an instance is also a full replacement, so resend the fields you keep:

curl -i -X PUT "$KAITEN_API/instances/sakura-tokyo-staging" \
  -H "Authorization: Bearer $KAITEN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Sakura Tokyo Staging",
    "description": "Staging instance for the Sakura Tokyo restaurant group.",
    "customerId": "'"$SAKURA_TOKYO_ID"'",
    "licenseId": "'"$PREMIUM_ID"'",
    "deploymentZoneId": "'"$SAKURA_DEDICATED_ID"'",
    "startLicenseDate": "2026-09-01T00:00:00Z",
    "endLicenseDate": "2027-09-01T00:00:00Z",
    "metadata": { "environment": "staging" }
  }'

HTTP/1.1 204 No Content. The staging instance now runs what sakura-dedicated runs — 2026.7.0, until that zone is upgraded.

A deploymentZoneId that does not exist in your organization is a 404, on create and on update alike: another organization's zone is indistinguishable from a zone that does not exist.

Delete a zone

DELETE /deployment-zones/{slug} returns 204 No Content and emits DEPLOYMENT_ZONE_DELETED. The instances that were placed in the zone are detached, not deleted: their deploymentZoneId is cleared, so the model no longer knows what they run until they are placed again. The journal entries recorded for the zone are removed with it; the releases they pointed at are untouched.

Zones in targeting rules

A zone's type and typed metadata are among the facts a flag rule sees, under __kaiten.deploymentZone. A rule that serves a variant only to instances running in a dedicated, PCI-certified zone:

__kaiten.deploymentZone.metadata.dedicated == true && __kaiten.deploymentZone.metadata.compliance_profile == 'pci-dss'

A rule that reads the environment class, which every seeded zone matches:

__kaiten.deploymentZone.type == 'production'

Dedicated zones and the Standalone edition

If your product is sold with a dedicated option — a customer's own stack, on their infrastructure or yours — a dedicated zone is how that option appears in the model: one zone, that customer's instances, its own release history, and metadata that says why it is separate. Kaiten is offered the same way. Kaiten Cloud runs your organization on a shared, managed stack; the Standalone edition runs Kaiten itself dedicated, on your infrastructure. The editions page lays out what each edition includes.

Events

Event nameEvent typeWhen
DEPLOYMENT_ZONE_CREATEDcom.kaiten.deployment_zone.v1.createdA zone is created
DEPLOYMENT_ZONE_UPDATEDcom.kaiten.deployment_zone.v1.updatedA zone's details change
DEPLOYMENT_ZONE_DELETEDcom.kaiten.deployment_zone.v1.deletedA zone is deleted
RELEASE_DEPLOYEDcom.kaiten.deployment_zone.v1.release_deployedA zone's releaseId is set at creation or changed
INSTANCE_DEPLOYEDcom.kaiten.instance.v1.deployedAn instance is placed in a zone
INSTANCE_MIGRATEDcom.kaiten.instance.v1.migratedAn instance moves from one zone to another

The zone events carry the DeploymentZone object; the instance events carry the Instance; RELEASE_DEPLOYED carries the journal entry itself.

Where to go next

What happens when a zone's release changes, and how to read what a zone ran and when: Deployments & Lifecycle. Exact reference: data model.

On this page