API Reference
Base URL https://curateone.ai/api/v1 — JSON in, JSON out, bearer-key auth on every call.
Account
Who the key belongs to, and how many AI credits remain.
/meRetrieve the account
Returns the account behind the presented API key, its plan, and the current billing period's credit usage. Use it as the canonical "is my key working?" probe.
curl https://curateone.ai/api/v1/me \
-H "Authorization: Bearer co_live_…"{
"account": {
"id": "acc_8f31…",
"name": "Akino Studio",
"email": "owner@example.com",
"plan": "pro",
"createdAt": 1750757400000
},
"usage": { "used": 14, "limit": 100, "remaining": 86, "bonusTokens": 25 }
}Sites
Every website on the account — list them, inspect one, or generate a new one.
/sitesList sites
All sites on the account, newest first. `status` is draft, provisioning, or live; `url` is set once the site's subdomain is fully live (SSL + content checks passed).
curl https://curateone.ai/api/v1/sites \
-H "Authorization: Bearer co_live_…"{
"sites": [
{
"id": "prj_ax92…",
"name": "Billu Barber",
"status": "live",
"url": "https://billu-barber.curateone.ai",
"customDomain": null,
"pages": 5,
"createdAt": 1751189000000,
"updatedAt": 1752598000000
}
]
}/sites5 AI creditsGenerate a site
Starts a full AI website generation as a background job and returns 202 with a job id. Poll GET /jobs/{jobId} until the job is terminal. Costs 5 AI credits (the same as a site build in the Studio), reserved up front and refunded automatically if the job fails or is cancelled. Builds share the Studio's per-account generation limit: a short burst, then a slow hourly refill — past it the call answers 429 rate_limited with Retry-After.
Body parameters
| businessNamerequired | string | The business the site is for. |
| industryrequired | string | Industry or category, e.g. "barber shop", "SaaS analytics". |
| audience | string | Who the site should speak to. |
| goals | string | What the site should achieve (bookings, signups, calls…). |
| personality | string | Brand personality cues, e.g. "premium, playful". |
| competitors | string | Competitor names or URLs to differentiate from. |
| existingUrl | string | An existing website to draw context from. |
curl -X POST https://curateone.ai/api/v1/sites \
-H "Authorization: Bearer co_live_…" \
-H "Content-Type: application/json" \
-d '{
"businessName": "Billu Barber",
"industry": "barber shop",
"audience": "young professionals in Indiranagar",
"goals": "walk-in bookings"
}'{ "jobId": "job_k2f8…" }/sites/{id}Retrieve a site
One site by id. Returns 404 for sites that don't exist or belong to another account.
curl https://curateone.ai/api/v1/sites/prj_ax92… \
-H "Authorization: Bearer co_live_…"{
"site": {
"id": "prj_ax92…",
"name": "Billu Barber",
"status": "live",
"url": "https://billu-barber.curateone.ai",
"customDomain": null,
"pages": 5,
"createdAt": 1751189000000,
"updatedAt": 1752598000000
}
}Generation jobs
Track a POST /sites generation from queued to live-editable.
/jobs/{id}Poll a job
The job's current status: pending, running, completed, failed, or cancelled. Poll every 3–5 seconds. On completed, `siteId` is set — the generated site is then available via GET /sites/{siteId}. Failed and cancelled jobs refund their reserved credits automatically.
curl https://curateone.ai/api/v1/jobs/job_k2f8… \
-H "Authorization: Bearer co_live_…"{
"job": {
"id": "job_k2f8…",
"status": "running",
"progress": 62,
"stage": "Composing pages",
"siteId": null,
"error": null
}
}/jobs/{id}Cancel a job
Cancels a queued or running generation and refunds the reserved credits. Idempotent — cancelling a finished job returns its terminal state unchanged.
curl -X DELETE https://curateone.ai/api/v1/jobs/job_k2f8… \
-H "Authorization: Bearer co_live_…"{
"job": { "id": "job_k2f8…", "status": "cancelled", "progress": 62, "stage": "Cancelled", "siteId": null, "error": null }
}Leads
Form submissions captured on your live sites, with CRM status.
/sites/{id}/leadsList leads
The site's captured leads, newest first. Sync them into your own CRM, or use webhooks (see the Webhooks guide) for push instead of pull.
Query parameters
| status | string | Filter: new, contacted, qualified, won, or lost. |
| limit | number | Page size, 1–200. Default 50. |
| skip | number | Offset for pagination. Default 0. |
curl "https://curateone.ai/api/v1/sites/prj_ax92…/leads?status=new&limit=50" \
-H "Authorization: Bearer co_live_…"{
"leads": [
{
"id": "led_77ab…",
"name": "Priya S",
"email": "priya@example.com",
"phone": "+91 98…",
"message": "Do you take Sunday appointments?",
"status": "new",
"source": "/contact",
"createdAt": 1752600000000
}
],
"total": 1
}Events
The site's events page — list and create events, and read who has registered.
/sites/{id}/eventsList events
The site's events, soonest first (most recent first for `when=past`). `confirmedSeats` counts confirmed registrations; `url` is the event's path on the site.
Query parameters
| when | string | upcoming, past, or all (default). |
| status | string | Filter: published or draft. |
| limit | number | Page size, 1–200. Default 50. |
| skip | number | Offset for pagination. Default 0. |
curl "https://curateone.ai/api/v1/sites/prj_ax92…/events?when=upcoming" \
-H "Authorization: Bearer co_live_…"{
"events": [
{
"id": "3f2c…",
"slug": "open-studio-day",
"title": "Open studio day",
"summary": "Try the wheel with our potters.",
"startsAt": 1760000000000,
"endsAt": 1760014400000,
"timezone": "Asia/Kolkata",
"venueName": "The studio",
"address": null,
"onlineUrl": null,
"priceLabel": "Free",
"capacity": 30,
"registrationEnabled": true,
"confirmedSeats": 12,
"status": "published",
"url": "/events/open-studio-day",
"createdAt": 1752600000000,
"updatedAt": 1752600000000
}
],
"total": 1
}/sites/{id}/eventsCreate an event
Creates an event and returns 201 with it. Saved as a draft unless `status` is "published", so a calendar sync never puts a half-mapped event on the live site.
Body parameters
| titlerequired | string | The event's name. |
| startsAtrequired | number | string | Start time: epoch milliseconds or an ISO-8601 string. |
| endsAt | number | string | End time, same formats. |
| timezone | string | IANA time zone, e.g. "Asia/Kolkata". |
| venueName | string | Where it happens. |
| address | string | Street address. |
| mapUrl | string | A map link for the venue. |
| onlineUrl | string | Join link for an online event. |
| summary | string | One or two lines for listings. |
| descriptionMarkdown | string | The full description, in Markdown. |
| priceLabel | string | Free text, e.g. "Free" or "₹500". |
| capacity | number | Seats available; omit for unlimited. |
| registrationEnabled | boolean | Accept registrations. Default true. |
| status | string | draft (default) or published. |
curl -X POST https://curateone.ai/api/v1/sites/prj_ax92…/events \
-H "Authorization: Bearer co_live_…" \
-H "Content-Type: application/json" \
-d '{ "title": "Open studio day", "startsAt": "2026-11-02T10:00:00+05:30", "capacity": 30 }'{ "event": { "id": "3f2c…", "slug": "open-studio-day", "title": "Open studio day", "status": "draft", "url": "/events/open-studio-day" } }/sites/{id}/events/{eventId}/registrationsList registrations
Who has registered for an event. This is attendees' personal data (names, emails, phone numbers), returned only to the account that owns the site.
Query parameters
| status | string | Filter: confirmed, waitlisted, or cancelled. |
| limit | number | Page size, 1–200. Default 100. |
| skip | number | Offset for pagination. Default 0. |
curl "https://curateone.ai/api/v1/sites/prj_ax92…/events/3f2c…/registrations?status=confirmed" \
-H "Authorization: Bearer co_live_…"{
"registrations": [
{
"id": "9a1d…",
"name": "Priya S",
"email": "priya@example.com",
"phone": null,
"seats": 2,
"message": null,
"fields": null,
"status": "confirmed",
"createdAt": 1752600000000
}
],
"total": 1,
"confirmedSeats": 12
}Gallery
The site's photo gallery — list images and albums, or add an image by URL.
/sites/{id}/galleryList images
The site's gallery images in display order, with the album names in use.
Query parameters
| album | string | Only images in this album. |
| status | string | Filter: published or draft. |
| limit | number | Page size, 1–200. Default 50. |
| skip | number | Offset for pagination. Default 0. |
curl "https://curateone.ai/api/v1/sites/prj_ax92…/gallery?album=Workshop" \
-H "Authorization: Bearer co_live_…"{
"images": [
{
"id": "c81e…",
"url": "https://images.example.com/bowl.webp",
"album": "Workshop",
"title": "Glazed bowl",
"caption": null,
"alt": "A blue glazed bowl on a wheel",
"width": 1600,
"height": 1200,
"status": "published",
"createdAt": 1752600000000
}
],
"total": 1,
"albums": ["Workshop"]
}/sites/{id}/galleryAdd an image
Adds an image by its https:// address and returns 201 with it. A link, not an upload: the API is for systems that already host their images; files are uploaded in the Studio.
Body parameters
| urlrequired | string | The image's https:// address. |
| album | string | Album to file it under. |
| title | string | Short title. |
| caption | string | Caption shown with the image. |
| alt | string | Alt text for screen readers. |
| status | string | published (default) or draft. |
curl -X POST https://curateone.ai/api/v1/sites/prj_ax92…/gallery \
-H "Authorization: Bearer co_live_…" \
-H "Content-Type: application/json" \
-d '{ "url": "https://images.example.com/bowl.webp", "album": "Workshop", "alt": "A blue glazed bowl" }'{ "image": { "id": "c81e…", "url": "https://images.example.com/bowl.webp", "album": "Workshop", "status": "published" } }Analytics
Cookieless first-party analytics for any site on the account.
/sites/{id}/analyticsRetrieve analytics
Traffic summary for the chosen range: pageviews, uniques, CTA clicks, form funnel, conversion, daily series, top pages/referrers, and privacy-safe device/country/language breakdowns.
Query parameters
| range | string | 7d, 30d (default), or 90d. |
curl "https://curateone.ai/api/v1/sites/prj_ax92…/analytics?range=30d" \
-H "Authorization: Bearer co_live_…"{
"analytics": {
"range": 30,
"pageviews": 1284,
"uniques": 902,
"ctaClicks": 187,
"formViews": 240,
"formSubmits": 41,
"leads": 41,
"conversion": 3.2,
"series": [{ "day": "2026-07-15", "pageviews": 96 }],
"topPaths": [{ "path": "/", "views": 810 }],
"topReferrers": [{ "ref": "google.com", "visits": 322 }],
"devices": [{ "device": "mobile", "views": 884 }],
"topCountries": [{ "country": "IN", "views": 1030 }],
"languages": [{ "lang": "en", "views": 1102 }],
"sources": [{ "source": "organic", "views": 640 }]
}
}