public

POST /v1/public/cart/{token}/plan

Add a hosting plan, or a free trial of one, to an anonymous cart.

All public endpoints

Authentication

This endpoint is public. It takes no credential and no organisation — it is what our own marketing site and AI answer engines read.

This endpoint takes no organisation id. Your key already identifies the organisation it belongs to, and the response is scoped to it.

Try it

Replace anything in angle brackets with your own values, and the key placeholder with a key from your dashboard.

curl -X POST https://api.zinndigital.com/v1/public/cart/{token}/plan \
  -H "Content-Type: application/json" \
  -d '{ "plan_version_id": <string>, "interval": <string<monthly, annual>> }'

Signed in? The API console in your dashboard fills in your real organisation id and your own key, and runs the request against the live API so you can see the actual response. Open this endpoint in the API console

Details

Owner ruling D-W15-2: hosting, free trials and domains go through ONE public checkout, so a visitor never has to sign up in the app before they can buy. The price is computed by the server from the pinned plan VERSION in the cart's own currency; anything sent by the client is ignored. A basket holds one plan at a time, because a subscription governs the org rather than a line. `trial: true` prices the line at **zero** and is refused (`422`) on a plan that does not offer a trial — eligibility is read from the catalogue, never taken on trust.

Parameters

NameTypeRequiredWhat it is
token (path)stringYesThe anonymous cart's opaque bearer token (`zgc_…`), as returned by `createPublicCart`. **It is a credential** — anyone holding it can read and modify the cart — and it travels i…

Request body

NameTypeRequiredWhat it is
plan_version_idstringYesThe immutable plan VERSION being bought. Pinning the version rather than the plan is what stops a catalogue edit repricing a basket somebody is part-way through.
intervalstring<monthly, annual>Yes
domainPublicCartPlanDomainNoWhich domain this hosting is for. **Optional** — "I will decide later" is a real and common answer, and refusing it would put a wall in front of the purchase this field exists t…
trialbooleanNoStart a free trial of this plan instead of buying it. The line prices at zero and the order completes with no payment step (owner ruling 2026-08-09 — a trial takes no card and s…

Response

NameTypeRequiredWhat it is
idUuidYesUUIDv7 identifier — sortable by creation time (docs/02 §8).
tokenstringNoThe bearer token. Returned **only** from `createPublicCart` — it is absent on every subsequent read, because only its digest is stored.
statusstring<open, converted, expired>Yes
currencyCurrencyCodeYesISO 4217 currency code (money is minor units + this code — CLAUDE.md §2.8).
product_linestringNo
expires_atstringYesAfter this the cart is gone — reads 404 whether or not it has been purged.
itemsPublicCartItem[]Yes
totalsPublicCartTotalsYesPre-tax totals. Tax appears on the order, once a billing country exists.

Errors this endpoint can return

404 · 422 · 429