Websites
Order a finished, hosted one-page website for a customer. $350.00 once, then $20.00 a month for as long as it stays online. You sell it at whatever you like; we never appear on it.
What you get
One page, written and designed around the business you name, at an address of ours (their-name.sites.kleos.click) until your customer points their own domain at it. It is built for them — not assembled from a template picker — and it arrives finished. There is no editor, no login and nothing for your customer to maintain, which is the product: the people who buy this are the people who never finished the website builder they paid for two years ago.
One revision is included. A further one is refused rather than charged — you will never discover on an invoice that you bought something.
What we build for
Send one of these as niche:
photographerlandscapercryptotradingecommerce_educationesportscreatorgeneric
generic is a real answer, not a fallback for a mistake — a business that is none of the others still gets a proper site. Anything else is refused with the full list in the message, and it is checked before your balance, so you are never sent to top up for something you still could not have ordered.
What you are charged, and when
The $350.00 build fee is taken when the order is accepted. If the build fails, or you cancel before anything has been delivered, it is refunded in full — as a refund line in your ledger, where your accountant can see it, rather than as a charge that quietly never happened.
Hosting starts at go-live, not at order. A build that takes three weeks costs you nothing for those three weeks. From the day it is live, $20.00 renews monthly on the same day of the month.
We charge on order rather than on delivery on purpose. Billing on delivery reads fairer and is worse: it would let one $350.00 balance order ten builds, nine of which get built and cannot be billed for.
What happens if the balance runs out
A site is never taken down without warning, and — unlike a released phone number — taking it down is reversible. There are four steps:
- Warned. Your balance will not cover the next month. Nothing has happened yet and the site keeps serving. You get
website.hosting_due. - Grace. A month could not be taken. The site stays up for another 14 days and the response now carries
suspend_due_on, the exact day it would go offline. Top up before then and it is stood back down, including on the last morning. - Suspended. The site stops serving and
website.suspendedis sent. It is offline, not deleted: everything needed to put it back is kept, andpurge_due_ontells you how long for. Nothing further is charged while it is suspended. Topping up brings it back at the same address. - Purged. After 90 days suspended, the site is destroyed. This one has no undo — a new order builds a new site.
Both dates are recorded when the step is taken, not worked out when you ask. A date nobody was ever given cannot be used to switch something off: if the record has no suspend_due_on, the suspension is refused rather than invented.
Your customer’s own domain
Send their bare domain to the domain endpoint and you get back one CNAME record to add at their registrar. That is the whole procedure.
We never ask for nameservers and never take the domain over. Delegating a zone moves the customer’s email with it, and the first time a website order silently breaks somebody’s MX records is the last time that reseller sells a website. A CNAME leaves every other record where it is, and the person who owns the name can undo it in one click.
In test mode
Nothing is built, nothing is charged and no address is returned — the record moves through the same states so you can build the list, the ladder fields and the cancel against real responses without owning anything.
The websites this customer has
GET/v1/customers/{id}/websites
Includes failed, canceled and purged ones. Read `suspend_due_on` and `purge_due_on`: the first is the day an unpaid site goes offline, the second the day it stops being recoverable. A suspended site is offline, not deleted — topping up before `purge_due_on` brings it back at the same address.
Permission: sites:read
Parameters
| Name | In | Type | |
|---|---|---|---|
id * | path | string | Kleos id or your `external_ref`. |
Response
{
"object": "list",
"data": [
{
"object": "website",
"id": "c7a2f108-3b6e-4c11-9a55-1e8d4b02f733",
"customer_id": "0f2a6c4e-96a2-4f2e-8f2b-6c1a0e73d8b1",
"niche": "photographer",
"business_name": "Vega Studio",
"locale": "en",
"status": "live",
"failure_reason": null,
"build_fee_cents": 35000,
"fee_refunded": false,
"revisions_used": 1,
"revisions_included": 1,
"url": "https://vega-studio.sites.kleos.click",
"custom_domain": "vegastudio.com",
"custom_domain_status": "active",
"hosting_status": "active",
"hosting_monthly_cents": 2000,
"currency": "usd",
"next_charge_on": "2026-09-06",
"suspend_due_on": null,
"purge_due_on": null,
"suspended_at": null,
"purged_at": null,
"grace_days": 14,
"retention_days": 90,
"mode": "live",
"created_at": "2026-08-06T09:12:44.000Z"
}
],
"has_more": false
}Refusals
| Status | Code | When |
|---|---|---|
| 404 | customer_not_found | No customer with that id in this mode. |
One website
GET/v1/customers/{id}/websites/{build_id}
The same object the list returns, for a single site. This is what to poll after an order: `status` moves through `queued`, `building`, `in_review`, `ready` and `live`, and `url` is filled in the moment there is an address to visit.
Permission: sites:read
Parameters
| Name | In | Type | |
|---|---|---|---|
id * | path | string | Kleos id or your `external_ref`. |
build_id * | path | string | The website id. |
Response
{
"object": "website",
"id": "c7a2f108-3b6e-4c11-9a55-1e8d4b02f733",
"customer_id": "0f2a6c4e-96a2-4f2e-8f2b-6c1a0e73d8b1",
"niche": "photographer",
"business_name": "Vega Studio",
"locale": "en",
"status": "live",
"failure_reason": null,
"build_fee_cents": 35000,
"fee_refunded": false,
"revisions_used": 1,
"revisions_included": 1,
"url": "https://vega-studio.sites.kleos.click",
"custom_domain": "vegastudio.com",
"custom_domain_status": "active",
"hosting_status": "active",
"hosting_monthly_cents": 2000,
"currency": "usd",
"next_charge_on": "2026-09-06",
"suspend_due_on": null,
"purge_due_on": null,
"suspended_at": null,
"purged_at": null,
"grace_days": 14,
"retention_days": 90,
"mode": "live",
"created_at": "2026-08-06T09:12:44.000Z"
}Refusals
| Status | Code | When |
|---|---|---|
| 404 | website_not_found | No such website for this customer in this mode. |
Order a website for your customer
POST/v1/customers/{id}/websites
$350 once, then $20/month once it is live — hosting starts at go-live, not at order, so a build that takes three weeks costs you nothing for three weeks. The build fee is charged when the order is accepted and refunded in full if the site is never delivered. One included revision. Your customer's own domain is added afterwards with one CNAME; we never take over their domain or their email. In test mode nothing is built, nothing is charged and no address is returned. Send an `Idempotency-Key`: this is the most expensive retry in the API.
Permission: sites:order
Parameters
| Name | In | Type | |
|---|---|---|---|
id * | path | string | Kleos id or your `external_ref`. |
Idempotency-Key | header | string | Your own unique string. Replaying it returns the first response for 24 hours. |
Body
| Field | Type | |
|---|---|---|
niche * | string | The kind of business. The error lists every value we build for. |
business_name * | string | The name that appears on the finished site. |
locale | string | Language of the copy. Defaults to `en`. |
website_url | string | Their existing site, if any. Used as source material. |
brief | string | A JSON object with anything else worth knowing: services, hours, tone, photos. |
Response
{
"object": "website",
"id": "c7a2f108-3b6e-4c11-9a55-1e8d4b02f733",
"customer_id": "0f2a6c4e-96a2-4f2e-8f2b-6c1a0e73d8b1",
"niche": "photographer",
"business_name": "Vega Studio",
"locale": "en",
"status": "building",
"build_fee_cents": 35000,
"fee_refunded": false,
"revisions_used": 0,
"revisions_included": 1,
"url": null,
"hosting_status": "active",
"hosting_monthly_cents": 2000,
"currency": "usd",
"next_charge_on": null,
"suspend_due_on": null,
"purge_due_on": null,
"grace_days": 14,
"retention_days": 90,
"mode": "live",
"created_at": "2026-08-06T09:12:44.000Z",
"charged_cents": 35000
}Refusals
| Status | Code | When |
|---|---|---|
| 404 | customer_not_found | No customer with that id in this mode. |
| 422 | niche_not_supported | We do not build sites for that trade. The message lists the ones we do — checked before your balance, so you are never sent to top up for something you still could not order. |
| 400 | business_name_required | `business_name` was missing. |
| 409 | build_already_in_flight | This customer already has a site being built. A second order would be a second build fee. |
| 402 | insufficient_balance | The build fee cannot be covered. Nothing was started. |
| 403 | emporos_suspended | No new work is started while an account is suspended. Existing sites keep serving. |
| 402 | charge_failed | The fee could not be taken, so nothing was started. |
Cancel a build and get the fee back
DELETE/v1/customers/{id}/websites/{build_id}
Refundable while nothing has been delivered — `queued`, `building` or `in_review`. Once a site is `ready` or `live` the work exists and a cancel is a cancel, not a refund. A live site cannot be canceled here at all: it is serving your customer's customers, and it comes down by stopping hosting, with notice, not by a DELETE. The refunded amount is on the response and in your ledger.
Permission: sites:order
Parameters
| Name | In | Type | |
|---|---|---|---|
id * | path | string | Kleos id or your `external_ref`. |
build_id * | path | string | The website id. |
Body
| Field | Type | |
|---|---|---|
reason | string | Kept on the record. Optional. |
Response
{
"object": "website",
"id": "c7a2f108-3b6e-4c11-9a55-1e8d4b02f733",
"customer_id": "0f2a6c4e-96a2-4f2e-8f2b-6c1a0e73d8b1",
"niche": "photographer",
"business_name": "Vega Studio",
"status": "canceled",
"build_fee_cents": 35000,
"fee_refunded": true,
"mode": "live",
"refunded_cents": 35000
}Refusals
| Status | Code | When |
|---|---|---|
| 404 | website_not_found | No such website for this customer in this mode. |
| 409 | cancel_not_available | A live or already-finished site cannot be canceled. |
| 502 | refund_failed | The fee could not be refunded, so nothing was canceled. Your build is unchanged. |
Ask for a change before it goes live
POST/v1/customers/{id}/websites/{build_id}/revision
One revision is included. The second is refused rather than charged — you will never find out you bought something from an invoice. Send `notes` describing what should change; a revision with no instructions cannot be worked on. A live site is changed through a release instead, and is not taken offline while that happens.
Permission: sites:order
Parameters
| Name | In | Type | |
|---|---|---|---|
id * | path | string | Kleos id or your `external_ref`. |
build_id * | path | string | The website id. |
Body
| Field | Type | |
|---|---|---|
notes * | string | What should change. |
Response
{
"object": "website",
"id": "c7a2f108-3b6e-4c11-9a55-1e8d4b02f733",
"customer_id": "0f2a6c4e-96a2-4f2e-8f2b-6c1a0e73d8b1",
"business_name": "Vega Studio",
"status": "building",
"revisions_used": 1,
"revisions_included": 1,
"mode": "live"
}Refusals
| Status | Code | When |
|---|---|---|
| 404 | website_not_found | No such website for this customer in this mode. |
| 400 | revision_notes_required | `notes` was missing. |
| 409 | revision_not_available | The site is live, or in a state that cannot be revised. |
| 409 | revisions_exhausted | The included revision has been used. Order a new site for a further rebuild. |
Point your customer's own domain at their site
POST/v1/customers/{id}/websites/{build_id}/domain
Returns one CNAME record to add at their registrar. **Never change their nameservers** — that would move their email with it. A CNAME leaves every other record where it is and your customer can undo it themselves, which is both correct and the only version of this a small business will agree to. The record goes live once it resolves; `custom_domain_status` tracks it.
Permission: sites:order
Parameters
| Name | In | Type | |
|---|---|---|---|
id * | path | string | Kleos id or your `external_ref`. |
build_id * | path | string | The website id. |
Body
| Field | Type | |
|---|---|---|
custom_domain * | string | A bare domain, e.g. vegastudio.com — no scheme, no path. |
Response
{
"object": "website",
"id": "c7a2f108-3b6e-4c11-9a55-1e8d4b02f733",
"business_name": "Vega Studio",
"custom_domain": "vegastudio.com",
"custom_domain_status": "pending",
"mode": "live",
"dns": {
"type": "CNAME",
"name": "vegastudio.com",
"value": "vega-studio.sites.kleos.click",
"note": "Add this one record at your customer's registrar. Do not change their nameservers — a CNAME leaves their email and every other record exactly where it is, and they can undo it themselves."
}
}Refusals
| Status | Code | When |
|---|---|---|
| 404 | website_not_found | No such website for this customer in this mode. |
| 400 | invalid_domain | Send a bare domain — no scheme and no path. |
| 409 | website_not_built_yet | The site has no address yet. Add the domain once the build is ready. |
| 409 | domain_in_use | That domain is already pointed at another site. |