Docs
API

Solutions and prices API

Read the solutions on offer and their prices, and install one.

A bundle is the set of apps one kind of organisation, its archetype, is offered as a single item, from the files in catalog/bundles. It is offered once a platform admin gives it a price on the Prices page, until it is withdrawn.

Every price here is the team's own: a lower price while the bundle has one for the team, and the Standard price otherwise. A team's price is fixed with its first solution, installed or paid for, from the address that did it (the X-Real-Ip header Traefik writes), and its every month is charged at it. Until then a price is the one for the address asking. A bundle or an install's terms priced below Standard also give list_price_cents, the Standard price, and give none otherwise.

List Bundles

GET /api/v1/teams/{teamSlug}/bundles

Response 200: {"bundles": [...]}, each bundle with its id, name, archetype, its apps (each with its id, name, what it does, who it is sized_for, whether it backs_up its data, and alone_cents, what it would cost a month on its own), its monthly price_cents for the team (null until it has one), whether it is offered, alone_cents, what its apps would cost a month bought one by one, and saving_cents, what its price saves against that (null when it saves nothing). Every member of the team may read it.

Bundles on Offer

GET /api/v1/bundles

No session needed: the public pages read it for each visit.

Response 200: {"bundles": [...]}, only the bundles on offer, each with its id, name, archetype, its apps (each with its id, name, what it does, who it is sized_for, and whether it backs_up its data) and its monthly price_cents for the visitor, as /prices gives it. A bundle with no price, or one withdrawn, is left out.

Prices

GET /api/v1/prices

No session needed: the public pages read it for each visit.

Response 200: {"rates": {...}, "addons": [...], "solutions": [...]}. rates are what App hosting charges, gb_hour_cents, vcpu_hour_cents and volume_gb_month_cents (null when the plans differ). addons are those on sale, each with its id, kind, name, days and monthly price_cents. solutions are the bundles on offer, each with its id, name, use_case, apps (id and name) and monthly price_cents for the visitor: a lower price for the addresses staff have set one for, and the Standard price for any other address, an unknown one, or with no country database. A solution priced below Standard also carries list_price_cents, the Standard price, and one at Standard carries none. The price comes from the request's address, looked up in the country database the API image carries; nothing is kept, and the answer does not say how the price was chosen.

Terms of an Install

GET /api/v1/teams/{teamSlug}/bundles/{bundleId}/terms

The terms an install of the bundle by the caller would take, for the confirm to show and then send to the install: the bundle's monthly price_cents for the team, whether the install starts the free trial, trial_ends_at, when that trial would end were the install made now, or null when the install takes its first month from the team's credit instead, and has_paid, whether a payment has reached the team. The install starts the trial when it is the team's first bundle and neither the caller nor the team has had one, and records the end the confirm showed. When the trial ends, a team that has paid is charged the bundle's first month. One that has not is charged nothing, its apps stop 72 hours later, and the first month starts with its first payment.

Response 200:

{"bundle_id": "hospital", "price_cents": 12200, "trial": true, "trial_ends_at": "2026-11-14T10:00:00Z", "has_paid": false}

It runs the install's checks without making anything, and answers a check that fails as the install would: 403 unless the caller is one of the team's owners or admins, 404, 409 bundle_not_offered, 409 bundle_installed, 402 billing_required, and 402 insufficient_credit when the install starts no trial and the team's credit is below the bundle's monthly price.

Install a Bundle

POST /api/v1/teams/{teamSlug}/bundles/{bundleId}/install

Makes one app for each app in the bundle, as a catalog install does, and records them as one install. Its body is the terms the installer's confirm showed: the bundle's monthly price, whether the install starts the free trial, when that trial ends, null without one, and whether it showed the team as having paid.

{"price_cents": 12200, "trial": true, "trial_ends_at": "2026-11-14T10:00:00Z", "has_paid": false}

Clusterz answers each app's setup itself, with the app's address, the installer's email, the team's name and an administrator's password of the app's own.

A team's first bundle starts the 14-day free trial, which needs no credit: each person has one trial, by their verified email and their account, and so does each team. Any other bundle takes its first month's price from the team's credit as it installs. Every check runs before anything is made:

  • 403 unless the caller is one of the team's owners or admins;
  • 400 without the confirm's price_cents and trial, or without its trial_ends_at when it showed a trial;
  • 404 for a bundle the platform does not ship;
  • 409 bundle_not_offered for a bundle with no price, or withdrawn;
  • 409 bundle_installed when the team holds the bundle already, an install of it with an app left, as a second click finds it; nothing was made or charged;
  • 402 billing_required when the team's balance is below zero or its apps are paused;
  • 402 insufficient_credit when the install starts no trial and the team's credit is below the bundle's monthly price;
  • 409 price_changed when the price or the trial differs from the confirm's, the confirm's trial_ends_at lies more than an hour from 336 hours after the install, as a confirm left open for over an hour shows, or a trial's has_paid differs from the confirm's, with the terms as they now stand, as the terms route gives them; nothing was made or charged;
  • 409 when another install took the trial meanwhile; nothing was made;
  • an app that cannot be installed answers as a catalog install does, with the app's id in app.

Response 201: the install (id, team_id, bundle_id, created_by, created_at, and trial_ends_at: when the free trial it started ends, the end its confirm showed, as recorded and as billing keeps to, or null when it paid its first month) and its apps, each with its catalog_id, its project and its state: setting_up once its first release has started, or needs_attention with an error when it could not be set up or started. Such an app has a failed deployment, which the deployment's retry runs again; the bundle's other apps carry on.

An app whose settings could not be stored keeps none of them. Its retry (POST .../deployments/{deployId}/retry) first answers its setup again, as the install did: its address, the installer's email, the team's name as it is now and a new administrator's password, which How to sign in on its page then shows. An app that kept its settings keeps them, since its databases were made with the passwords in them.