Integrate your website
Ember CMS is an API-only backend. Your site is programmed and hosted separately. Call these public endpoints for published content, booking slots, and shop checkout. No auth token — CORS must allow your frontend origin (set by the platform). Connected sites also get https://api.yourdomain.lt as a branded API host (same paths).
active sites resolve./api/v1/public/websites/by-domain/{domain}e.g. by-domain/acmebakery.com
/api/v1/public/websites/by-slug/{slug}e.g. by-slug/ember-studio
/api/v1/public/websites/{website_id}After you have the id
const res = await fetch("/api/v1/public/websites/by-slug/ember-studio");
const site = await res.json();
// site.id → use for pages, blog, booking, shop
// site.default_locale, site.timezone, …{ key, type, value }. Types: string, text, number, boolean, url, json. Disabled fields are omitted on the detail endpoint./api/v1/public/websites/{website_id}/pages/api/v1/public/websites/{website_id}/pages/{slug}const pages = await fetch(`/api/v1/public/websites/${site.id}/pages`).then(r => r.json());
const home = await fetch(`/api/v1/public/websites/${site.id}/pages/home`).then(r => r.json());
// home.sections: [{ section_type: "meta", content: { key, type, value } }, …]body is sanitized HTML — render with your site's styles (or a sanitizer if you transform it further)./api/v1/public/websites/{website_id}/blog/posts/api/v1/public/websites/{website_id}/blog/posts/{slug}/api/v1/public/websites/{website_id}/booking/services/api/v1/public/websites/{website_id}/booking/staff/api/v1/public/websites/{website_id}/booking/slots?service_id=&date_from=&date_to=&staff_member_id=date_from / date_to are ISO dates (YYYY-MM-DD). staff_member_id optional.
/api/v1/public/websites/{website_id}/booking/bookingsawait fetch(`/api/v1/public/websites/${site.id}/booking/bookings`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
service_id: "…",
starts_at: "2026-08-01T10:00:00Z",
customer_name: "Casey Morgan",
customer_email: "casey@example.com",
customer_phone: "+15550100",
notes: "First visit",
// optional free-form fields (also accepted as "extra")
metadata: { phone: "+3706…", party_size: 2, source: "web" },
}),
});payment_url — redirect the customer there. Tenant must have shop entitlements and a ready Stripe Connect account when Connect is required./api/v1/public/websites/{website_id}/shop/products/api/v1/public/websites/{website_id}/shop/products/{product_id}Your Product ID (slug), e.g. hoodie-black
/api/v1/public/websites/{website_id}/shop/checkoutconst order = await fetch(`/api/v1/public/websites/${site.id}/shop/checkout`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
customer_name: "Sam Patel",
customer_email: "sam@example.com",
items: [{ product_id: "…", quantity: 2 }],
}),
}).then(r => r.json());
window.location.href = order.payment_url;/api/v1/public/websites/{website_id}/customers/register/api/v1/public/websites/{website_id}/customers/login/api/v1/public/websites/{website_id}/customers/refresh/api/v1/public/websites/{website_id}/customers/meBearer customer token
/api/v1/public/websites/{website_id}/customers/me/ordersBearer customer token
/api/v1/public/websites/{website_id}/newsletter/subscribe/api/v1/public/websites/{website_id}/newsletter/unsubscribe// Register
const auth = await fetch(`/api/v1/public/websites/${site.id}/customers/register`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
email: "sam@example.com",
password: "securepass",
full_name: "Sam Patel",
newsletter_opt_in: true,
}),
}).then(r => r.json());
// Newsletter only (no password)
await fetch(`/api/v1/public/websites/${site.id}/newsletter/subscribe`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email: "news@example.com" }),
});
// My orders
const orders = await fetch(`/api/v1/public/websites/${site.id}/customers/me/orders`, {
headers: { Authorization: `Bearer ${auth.access_token}` },
}).then(r => r.json());Errors return JSON like { "code": "not_found", "message": "…", "details": null, "request_id": "…" }.
Browser calls only work from origins on the website’s allowlist (plus platform admin origins). Ask the platform team to add your production and preview origins when the site is connected.
Domains are connected by pointing nameservers to Cloudflare so the platform can manage DNS. Content is never rendered by this API — your frontend owns HTML/UI.
// Minimal bootstrap
async function loadSite(host = window.location.hostname) {
const site = await fetch(`/api/v1/public/websites/by-domain/${host}`).then(async (r) => {
if (!r.ok) throw new Error(await r.text());
return r.json();
});
const page = await fetch(`/api/v1/public/websites/${site.id}/pages/home`).then((r) => r.json());
return { site, page };
}