commerce

POST /v1/carts/{cartId}/lines

Add a line to a cart.

All commerce endpoints

All developer docs →

Authentication

Send an API key as a bearer token. The endpoint checks billing.payment.manage; a key without it is refused with 403, not 404.

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/carts/{cartId}/lines \
  -H "Authorization: Bearer zdk_live_…" \
  -H "Content-Type: application/json" \
  -d '{ "kind": <SellableLineKind> }'

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

Adds a priced line. A hosting_plan line needs a plan_version_id; a domain_register/domain_transfer/domain_renew line needs a domain_name, tld and period_years. The line shape and price are validated + stamped by the server; a bad shape (or a plan version with no price) is a 422.

Parameters

NameTypeRequiredWhat it is
cartId (path)UuidYesThe cart's id.

Request body

NameTypeRequiredWhat it is
kindSellableLineKindYesThe line kinds a cart will accept today — the write-side subset of LineKind. Narrower than LineKind on purpose. LineKind is what a line can be (a read shape, including…
domain_namestringNoRequired for a domain line — the FULL name including its extension (example.com, matching tld); a bare label is refused with 422.
tldstringNoRequired for a domain line.
period_yearsintegerNoRequired for a register/transfer/renew line.
privacybooleanNo—
auto_renewbooleanNo—
availability_tokenstringNoThe signed token from searchDomains for this exact name. Optional: an ordinary name prices from the TLD catalogue without one. It is required to buy a premium name, because…
auth_codestringNoThe EPP/authorization code issued by the registrar the domain is currently held at. Required for a domain_transfer line — no registry will initiate a transfer without it, so…
registrar_routeRegistrationRouteKeyNoWhich registrar buys the name, on a domain_register or domain_transfer line. Omit it for the organisation's own registrar, which is the behaviour every caller had before this…
plan_version_idUuid | nullNoRequired for a hosting_plan line — the immutable plan version to bill.
extra_codestringNoThe catalogue code of the service an extra line buys. Required for that kind and meaningless on any other. Which addons a cart may buy is validated against…
aged_domain_idUuid | nullNoRequired for an aged_domain line (s1014 DOMAINS, docs/1107 §5) — an aged domain on sale (listAgedDomains). Priced at the catalogue's supplier list price, no markup; a USD…
aged_destinationobjectNoWhere the bought aged domain goes, asked in the checkout so staff never have to ask: registrar (pushed to your own account there — registrar and account required) or zinn…
listing_package_idUuid | nullNoRequired for a marketplace_package line — the package on a live listing being bought. The price is the seller's and is re-read on every basket read, so a client-sent amount…
intervalBillingIntervalNoThe recurrence a price is quoted for.
regionstringNoThe data centre this hosting is bought for — carried onto the resulting subscription and used as the default region for sites created against it (docs/370). Blank or omitted means…
computeComputeLineConfigNoHow one machine on a compute_server cart line is built. The values are not trusted from here: the engine re-resolves the whole order against the live vendor before the line…
databaseDatabaseLineConfigNoThe managed database a managed_database cart line buys (docs/497 §8). The values are not trusted from here: the engine re-resolves the whole purchase through the same…

Response

NameTypeRequiredWhat it is
idUuidYesUUIDv7 identifier — sortable by creation time (docs/02 §8).
org_idUuidYesUUIDv7 identifier — sortable by creation time (docs/02 §8).
statusstring<open, checking_out, converted, abandoned, expired>Yes—
currencyCurrencyCode | nullNoFixed when the cart is opened, from CartCreate.currency or the X-Zinn-Currency header, and then locked — every line must match it. Null only on a legacy cart created before…
product_lineobjectNo—
linesCartLine[]Yes—
subtotalMoneyAmountYesA money value — integer minor units + an ISO 4217 code (CLAUDE.md §2.8).
discountMoneyAmountYesA money value — integer minor units + an ISO 4217 code (CLAUDE.md §2.8).
totalMoneyAmountYesA money value — integer minor units + an ISO 4217 code (CLAUDE.md §2.8).
created_atstringYes—
updated_atstringNo—

Errors this endpoint can return

401 · 403 · 404 · 422 · 429