API Reference
BetaUse an API key to work with your Kanorio sites over HTTPS. This page lists every endpoint's parameters, examples and required permission. The same content is available as a machine-readable OpenAPI spec.
Before you start
- Create an API key in Account Settings and choose Other tools.
- Send Authorization: Bearer knr_pat_your_key with every request.
- Changes to pages, header, footer and site design are saved as drafts. Call publish to make them live.
- To read published collection items on the frontend without a key, use the Content Delivery API at https://{your-site}/api/v1/collections/{key}/items.
- Management API rate limits: 120 requests per minute per key, and 30 publish or unpublish calls per hour. Content Delivery API rate limits (cache hits are unlimited and free; only cache misses and form writes count): 20 requests per second per site (burst 100) and 10 requests per second per visitor IP (burst 30). Over the limit you get a 429; wait for the Retry-After seconds.
Base URL
Endpoint descriptions match what AI assistants read.
Section specs
/sectionssections.describe
BetaRead-onlyList the section (module) types that can be placed on a page, with an English name, description, category and, in full mode, the JSON Schema (draft 2020-12) each section object must satisfy. Call this before pages.replace_sections. Without `types` you get a compact summary of all types; pass `types` (or detail=full) to receive the schemas. Pass `websiteId` to learn which types are available on that website's plan (sets `available`); this requires the editor:enter scope on that website. Errors: FORBIDDEN (no access to websiteId), WEBSITE_NOT_FOUND.
- Permission
- Any valid key
- Rate limit
- 120 per minute
Query parameters
websiteIdstringOptional. When set, `available` reflects that website's plan; needs editor:enter.
typesstring[]Return only these section types, with full JSON Schemas.
detailstringsummary (default when `types` is omitted) or full (schemas included).
curl -X GET "https://app.kanorio.com/api/v1/sections?types=hero%2Cfaq&detail=summary" \ -H "Authorization: Bearer $KANORIO_TOKEN"
Sites
/sitessites.list
BetaRead-onlyList the websites the token owner is a member of, restricted to the websites the token was granted for. Returns ids you need for every other site-scoped call. Errors: none beyond FORBIDDEN when the token lacks console:view.
- Permission
- console:view
- Rate limit
- 120 per minute
curl -X GET "https://app.kanorio.com/api/v1/sites" \ -H "Authorization: Bearer $KANORIO_TOKEN"
/sitessites.create
BetaCreate a new website owned by the token owner. Requires a token granted for all websites (not restricted to specific websiteIds). mode=blank: creates the skeleton immediately (empty home page, hidden legal pages, a default header and footer in globalSections, owner membership) and returns websiteId. Then follow sections.describe -> conventions.brandFirst: set the theme (site.update_settings), define buttons (globals.update_site_settings), create pages, fill them with pages.replace_sections, rebuild the header navigation (globals.replace_header) and publish. mode=brief: queues the AI site builder with a brand brief and returns jobId; poll jobs.get every 5-10 seconds until status is SUCCEEDED (websiteId is set) or FAILED. This consumes the owner's AI credits and daily site-creation quota. Errors: TOKEN_WEBSITE_SCOPED, VALIDATION, DAILY_LIMIT_REACHED (brief).
- Permission
- console:view
- Rate limit
- 120 per minute
curl -X POST "https://app.kanorio.com/api/v1/sites" \
-H "Authorization: Bearer $KANORIO_TOKEN" \
-H "Content-Type: application/json" \
-d '{}'/sites/{id}sites.get
BetaRead-onlyGet one website's summary: plan, publish state, subdomain, primary custom domain and whether there are unpublished changes. Errors: FORBIDDEN, WEBSITE_NOT_FOUND.
- Permission
- console:view
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
curl -X GET "https://app.kanorio.com/api/v1/sites/{id}" \
-H "Authorization: Bearer $KANORIO_TOKEN"/sites/{id}/structuresites.structure
BetaRead-onlyReturn the visual sitemap tree of a website: top-level pages with nested subpages (up to 3 levels), real page status (published / changed / draft / hidden), the ordered list of section types on each page, and summary counts for Kanorio-managed Store and Blog pages. Errors: FORBIDDEN, WEBSITE_NOT_FOUND.
- Permission
- editor:enter
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
curl -X GET "https://app.kanorio.com/api/v1/sites/{id}/structure" \
-H "Authorization: Bearer $KANORIO_TOKEN"/jobs/{id}jobs.get
BetaRead-onlyGet the status of a site-generation job (from sites.create mode=brief) or a page-generation job. Poll until status is SUCCEEDED or FAILED; respect pollAfterSeconds. Errors: JOB_NOT_FOUND, FORBIDDEN.
- Permission
- console:view
- Rate limit
- 120 per minute
Path parameters
idstringRequired
curl -X GET "https://app.kanorio.com/api/v1/jobs/{id}" \
-H "Authorization: Bearer $KANORIO_TOKEN"/sites/{id}/searchsite.search
BetaRead-onlySearch the live site the way visitors do: published pages, blog posts, blog categories and tags, products and product categories. Use it to check whether the site already covers a topic before writing, or to find the page to edit. Every term in q must appear in the title or body (AND); full-width characters, case and term order do not matter. Drafts, hidden pages and pages excluded from site search are not included; an unpublished site returns no results. Errors: FORBIDDEN, VALIDATION (details.reason: QUERY_REQUIRED, QUERY_TOO_SHORT or QUERY_TOO_LONG), SEARCH_BUSY.
- Permission
- console:view
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
Query parameters
qstringRequiredSearch terms separated by spaces (up to 4 are used). One term needs 2 CJK or Thai characters, or 3 letters or digits.
kindstring[]Only these kinds. REST accepts kind=PAGE,PRODUCT. Omit for all kinds.
limitintegerResults to return (1-20, default 20).
curl -X GET "https://app.kanorio.com/api/v1/sites/{id}/search?q=sourdough&kind=PAGE%2CCOLLECTION_ITEM&limit=5" \
-H "Authorization: Bearer $KANORIO_TOKEN"Site design & settings
/sites/{id}/settingssite.get_settings
BetaRead-onlyRead the website's visual theme (brand colors, fonts, corner radius, density, color scheme), content language and website currency. Errors: FORBIDDEN, WEBSITE_NOT_FOUND.
- Permission
- site:manage_settings
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
curl -X GET "https://app.kanorio.com/api/v1/sites/{id}/settings" \
-H "Authorization: Bearer $KANORIO_TOKEN"/sites/{id}/settingssite.update_settings
BetaUpdate the website's visual theme and basic settings; only the fields you send change. brandColor { light, dark } are hex colors used for buttons, links and accents in light/dark mode; brandForeground overrides the text color on brand-colored surfaces (null resets). typography picks body font ids per script (bodyEnFontId, bodyZhHantFontId, bodyZhHansFontId, bodyJaFontId, bodyKoFontId). cornerRadius: sharp | normal | soft; sectionDensity: standard | compact; colorScheme: system | light | dark. locale changes the content language (fonts, HTML lang, legal pages). The website currency can't be changed here: it re-labels every price and is limited by the connected payment providers, so the owner changes it in website settings. Do this before filling pages so the brand colors apply everywhere. Theme changes are draft until site.publish. Errors: FORBIDDEN, WEBSITE_NOT_FOUND, VALIDATION (details lists the failing field), WRITE_FROZEN.
- Permission
- site:manage_settings
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
curl -X PATCH "https://app.kanorio.com/api/v1/sites/{id}/settings" \
-H "Authorization: Bearer $KANORIO_TOKEN" \
-H "Content-Type: application/json" \
-d '{"settings":{"brandColor":{"light":"#D9822B","dark":"#F0A55A"},"cornerRadius":"soft"}}'Header, footer & site buttons
/sites/{id}/globalsglobals.get
BetaRead-onlyRead the site-level draft shared by all pages: the primary header and footer (from globalSections), siteSettings (customButtons referenced by sections via ctaIds, socialLinks) and the revision marker contentUpdatedAt. Call it before globals.replace_header / globals.replace_footer / globals.update_site_settings and pass contentUpdatedAt back as ifUnmodifiedSince. Images of the site's media library appear as asset:<assetId>; assets holds them (with display URLs). Errors: FORBIDDEN, WEBSITE_NOT_FOUND.
- Permission
- editor:enter
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
curl -X GET "https://app.kanorio.com/api/v1/sites/{id}/globals" \
-H "Authorization: Bearer $KANORIO_TOKEN"/sites/{id}/globals/headersglobals.list_headers
BetaRead-onlyList all headers in globalSections: the primary header plus any secondary headers created for specific pages (ADR-0001). Most websites only need the primary header. Errors: FORBIDDEN, WEBSITE_NOT_FOUND.
- Permission
- editor:enter
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
curl -X GET "https://app.kanorio.com/api/v1/sites/{id}/globals/headers" \
-H "Authorization: Bearer $KANORIO_TOKEN"/sites/{id}/globals/headersglobals.create_header
BetaCreate a secondary header in globalSections with a human-readable key. Only use this when specific pages need a different navigation bar (for example a sub-brand or campaign microsite); most websites only need the primary header. After creating the header, assign its returned id to a page with pages.update({ globalHeaderId }). Saved as draft only; call site.publish to go live. Errors: FORBIDDEN, WEBSITE_NOT_FOUND, VALIDATION, KEY_TAKEN, CONFLICT, WRITE_FROZEN, ASSET_NOT_FOUND (details.assetIds: not in this site's media library), ASSET_NOT_ALLOWED (product files cannot be shown on pages).
- Permission
- content:edit
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
curl -X POST "https://app.kanorio.com/api/v1/sites/{id}/globals/headers" \
-H "Authorization: Bearer $KANORIO_TOKEN" \
-H "Content-Type: application/json" \
-d '{"ifUnmodifiedSince":"2026-10-06T08:00:00.000Z","key":"campaign","header":{"id":"hdr_campaign_01","type":"header","navItems":[{"id":"nav_home","text":"Home","linkType":"internal","pageSlug":"/"},{"id":"nav_about","text":"About Us","linkType":"internal","pageSlug":"/about"}],"ctaIds":["btn_order"],"key":"campaign"}}'/sites/{id}/globals/headers/{key}globals.delete_header
BetaDelete a secondary header by key and automatically reassign any pages using it back to the primary header. The primary header cannot be deleted. Saved as draft only; call site.publish to go live. Errors: FORBIDDEN, WEBSITE_NOT_FOUND, HEADER_NOT_FOUND, PRIMARY_HEADER_PROTECTED, CONFLICT, WRITE_FROZEN.
- Permission
- content:edit
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
keystringRequiredUnique header key (a-z, 0-9, hyphen, underscore; 1-40 chars). 'primary' refers to the main site header.
Query parameters
ifUnmodifiedSincestringRequiredcontentUpdatedAt from globals.get. Required: the write is rejected with CONFLICT when the site-level draft changed since (details.contentUpdatedAt holds the current value).
curl -X DELETE "https://app.kanorio.com/api/v1/sites/{id}/globals/headers/{key}?ifUnmodifiedSince=2026-10-06T08%3A00%3A00.000Z" \
-H "Authorization: Bearer $KANORIO_TOKEN"/sites/{id}/globals/site-settingsglobals.update_site_settings
BetaPartially update siteSettings (only the keys you send are replaced; optimistic concurrency). customButtons is the single list of CTA buttons for the whole site: define them here (text, url, optional icon and style), then reference their ids from sections, the header and the footer via ctaIds (up to 2 per place). Buttons without an id get one; read it back from the response. Replaces the whole list when sent. socialLinks: [{ platform, url }] rendered in the footer and social sections. Contact fields (address/phone/email/hours) are business facts and are not editable here. Saved as draft only; call site.publish to go live. Errors: FORBIDDEN, WEBSITE_NOT_FOUND, VALIDATION, CONFLICT, WRITE_FROZEN, ASSET_NOT_FOUND (details.assetIds: not in this site's media library), ASSET_NOT_ALLOWED (product files cannot be shown on pages).
- Permission
- content:edit
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
curl -X PATCH "https://app.kanorio.com/api/v1/sites/{id}/globals/site-settings" \
-H "Authorization: Bearer $KANORIO_TOKEN" \
-H "Content-Type: application/json" \
-d '{"ifUnmodifiedSince":"2026-10-06T08:00:00.000Z","siteSettings":{"customButtons":[{"id":"btn_order","text":"Order online","url":"/shop","style":"brand"}]}}'/sites/{id}/globals/headerglobals.replace_header
BetaReplace the primary header or a secondary header identified by key (whole object, optimistic concurrency). The header's id stays the one pages already reference; when the site has no header yet, the given id is used and attached to every page. Typical use after creating pages: rebuild navItems so each visible page has an internal link. Saved as draft only; call site.publish to go live. Reference a logoOverride image as asset:<assetId>. Errors: FORBIDDEN, WEBSITE_NOT_FOUND, HEADER_NOT_FOUND, VALIDATION (details lists the failing field), CONFLICT, WRITE_FROZEN, ASSET_NOT_FOUND (details.assetIds: not in this site's media library), ASSET_NOT_ALLOWED (product files cannot be shown on pages).
- Permission
- content:edit
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
curl -X PUT "https://app.kanorio.com/api/v1/sites/{id}/globals/header" \
-H "Authorization: Bearer $KANORIO_TOKEN" \
-H "Content-Type: application/json" \
-d '{"ifUnmodifiedSince":"2026-10-06T08:00:00.000Z","header":{"id":"sec_header01","type":"header","navItems":[{"id":"nav_home","text":"Home","linkType":"internal","pageSlug":"/"},{"id":"nav_about","text":"About Us","linkType":"internal","pageSlug":"/about"}],"ctaIds":["btn_order"]}}'Pages
/sites/{id}/pagespages.list
BetaRead-onlyList the pages of a website (home page first), with slug, visibility, SEO fields and the revision marker updatedAt. Sections are not included; use pages.get. Errors: FORBIDDEN.
- Permission
- editor:enter
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
curl -X GET "https://app.kanorio.com/api/v1/sites/{id}/pages" \
-H "Authorization: Bearer $KANORIO_TOKEN"/sites/{id}/pagespages.create
BetaCreate an empty page (up to 3 levels deep). Pass parentSlug (e.g. "/services") plus the last segment in slug (e.g. "/haircut") rather than concatenating multi-segment paths yourself; if the parent page does not exist yet, a hidden folder page is created automatically. Omit slug to have one generated from the title. The home page ("/") already exists and cannot be created; link-in-bio pages have a dedicated flow. The new page uses the home page's header and footer unless you pass globalHeaderId/globalFooterId. It is not added to the navigation automatically: after creating pages, call globals.replace_header with a navItem per visible page. Fill the page afterwards with pages.replace_sections. Errors: FORBIDDEN, VALIDATION, SLUG_TAKEN, RESERVED_SLUG, RESERVED_SEGMENT, SEGMENT_TOO_LONG, DEPTH_EXCEEDED, PARENT_NOT_ALLOWED, BREADCRUMB_PARENT_INVALID, HOME_NOT_CREATABLE, LINK_IN_BIO_DEDICATED_ENTRY.
- Permission
- content:edit
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
curl -X POST "https://app.kanorio.com/api/v1/sites/{id}/pages" \
-H "Authorization: Bearer $KANORIO_TOKEN" \
-H "Content-Type: application/json" \
-d '{"title":"About Us","slug":"/about","isVisible":true}'/sites/{id}/pages/orderpages.reorder
BetaSet the order of all non-home pages (the home page is always first). Order drives the page list in the console; navigation links come from the header's navItems, which you manage with globals.replace_header. pageIds must list every non-home page exactly once; legal pages created with the site count too (get them from pages.list). Errors: FORBIDDEN, FOREIGN_PAGE (an id is not a page of this site), HOME_NOT_SORTABLE (home page included), INCOMPLETE_ORDER (some pages missing or duplicated).
- Permission
- content:edit
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
curl -X PUT "https://app.kanorio.com/api/v1/sites/{id}/pages/order" \
-H "Authorization: Bearer $KANORIO_TOKEN" \
-H "Content-Type: application/json" \
-d '{"pageIds":["pg_example789"]}'/sites/{id}/pages/{pageId}pages.get
BetaRead-onlyGet one page including its current draft sections, hierarchy metadata (path, parentSlug, isDirectory, depth, ancestors, breadcrumbs, breadcrumbSource) and updatedAt. Always read the page right before pages.replace_sections and pass updatedAt back as ifUnmodifiedSince. Images and files of the site's media library appear as asset:<assetId> in sections; assets holds them (with display URLs). Errors: FORBIDDEN, PAGE_NOT_FOUND.
- Permission
- editor:enter
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
pageIdstringRequiredPage id. Get it from pages.list.
curl -X GET "https://app.kanorio.com/api/v1/sites/{id}/pages/{pageId}" \
-H "Authorization: Bearer $KANORIO_TOKEN"/sites/{id}/pages/{pageId}pages.update
BetaUpdate a page's properties: title, slug, parentSlug, createRedirect, breadcrumbParentSlug, visibility, header/footer reference, SEO fields (seoTitle, seoDescription, seoKeywords, og*, canonicalUrl, robots*) and excludeFromSiteSearch. Only the fields you send change; sections are untouched (use pages.replace_sections). Nullable fields (parentSlug, breadcrumbParentSlug, globalHeaderId, globalFooterId, ogImageAssetId) can be cleared by passing null; all other fields can only be replaced, not cleared. Slug, parentSlug and visibility changes take effect on the published site immediately; renaming automatically updates descendant subpages and creates 301 redirects for previously published pages unless createRedirect is false. Errors: FORBIDDEN, PAGE_NOT_FOUND, PARENT_NOT_FOUND, PARENT_NOT_ALLOWED, DEPTH_EXCEEDED, SEGMENT_TOO_LONG, RESERVED_SLUG, RESERVED_SEGMENT, BREADCRUMB_PARENT_INVALID, REDIRECT_CONFLICT, REDIRECT_LIMIT, VALIDATION, SLUG_TAKEN, HOME_SLUG_IMMUTABLE, HOME_NOT_HIDEABLE, PRODUCT_PAGES_PLAN_REQUIRED, ASSET_NOT_FOUND, ASSET_NOT_ALLOWED.
- Permission
- content:edit
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
pageIdstringRequiredPage id. Get it from pages.list.
curl -X PATCH "https://app.kanorio.com/api/v1/sites/{id}/pages/{pageId}" \
-H "Authorization: Bearer $KANORIO_TOKEN" \
-H "Content-Type: application/json" \
-d '{"seoTitle":"About Us | Sunny Bakery","seoDescription":"Naturally leavened sourdough baked fresh every morning.","ogImageAssetId":"asset_example01"}'/sites/{id}/pages/{pageId}pages.delete
BetaDelete a page and its draft content. The home page cannot be deleted. When the page has subpages, you must pass mode: "subtree" (delete the page and all its subpages) or "lift-children" (move subpages up one level with 301 redirects before deleting the parent); omitting mode returns HAS_CHILDREN with details.children. Errors: FORBIDDEN, PAGE_NOT_FOUND, HOME_NOT_DELETABLE, HAS_CHILDREN, SLUG_TAKEN, REDIRECT_CONFLICT, REDIRECT_LIMIT.
- Permission
- content:edit
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
pageIdstringRequiredPage id. Get it from pages.list.
Query parameters
modestringRequired when deleting a parent page that has subpages: "subtree" deletes all descendants; "lift-children" moves subpages up one level first.
createRedirectbooleanWith mode "lift-children": whether to create 301 redirects from the old subpage URLs for previously published subpages (defaults to true). Ignored otherwise.
curl -X DELETE "https://app.kanorio.com/api/v1/sites/{id}/pages/{pageId}" \
-H "Authorization: Bearer $KANORIO_TOKEN"/sites/{id}/pages/{pageId}/sectionspages.replace_sections
BetaReplace the whole draft section list of a page (optimistic concurrency). Get the shapes from sections.describe; read the page with pages.get and pass its updatedAt as ifUnmodifiedSince. If someone else (another agent or a person in the editor) changed the page since, the call fails with CONFLICT and details.updatedAt holds the current revision: re-read the page, merge, retry. Changes are saved as draft only; call site.publish to go live. Reference images and files as asset:<assetId> (from media.list, media.upload, media.import_stock, media.upload_link_status); values you read with pages.get can be sent back unchanged. Errors: FORBIDDEN, PAGE_NOT_FOUND, VALIDATION (details lists the failing section index and field), CONFLICT, ASSET_NOT_FOUND (details.assetIds: not in this site's media library), ASSET_NOT_ALLOWED (product files cannot be shown on pages).
- Permission
- content:edit
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
pageIdstringRequiredPage id. Get it from pages.list.
curl -X PUT "https://app.kanorio.com/api/v1/sites/{id}/pages/{pageId}/sections" \
-H "Authorization: Bearer $KANORIO_TOKEN" \
-H "Content-Type: application/json" \
-d '{"ifUnmodifiedSince":"2026-10-06T08:00:00.000Z","sections":[{"id":"sec_hero01","type":"hero","title":"Freshly baked sourdough every morning","subtitle":"Natural starter, local grain. Doors open at 7 a.m.","image":"asset:asset_example01","ctaIds":["btn_order"]},{"id":"sec_faq01","type":"faq","title":"Frequently Asked Questions","items":[{"question":"Can I pre-order loaves?","answer":"Yes, place pre-orders by 5 p.m. the day before."}]}]}'/sites/{id}/revisionsrevisions.list
BetaRead-onlyList content revisions for a website draft (subject: WEBSITE, subjectId omitted or equal to websiteId) or a blog post (subject: BLOG_POST, subjectId: postId). Revisions are retained for 30 days and coalesced within 10-minute autosave windows. Optionally pass pageId when listing WEBSITE revisions to filter to edits that touched that page. Errors: FORBIDDEN.
- Permission
- editor:enter
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
Query parameters
subjectstringDefaults to WEBSITE.
subjectIdstringRequired when subject is BLOG_POST (pass the postId); defaults to websiteId for WEBSITE.
pageIdstringOptional filter for WEBSITE revisions: only revisions that modified this page or whole-site checkpoints.
limitintegerMax revisions to return (1-200, default 50).
curl -X GET "https://app.kanorio.com/api/v1/sites/{id}/revisions?subject=WEBSITE&limit=20" \
-H "Authorization: Bearer $KANORIO_TOKEN"/sites/{id}/revisions/{revisionId}revisions.get
BetaRead-onlyGet the full unpacked snapshot of a content revision by revisionId. Media references belonging to this site's library are presented as asset:<assetId> with display metadata in assets. Errors: FORBIDDEN, REVISION_NOT_FOUND.
- Permission
- editor:enter
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
revisionIdstringRequiredRevision identifier from revisions.list.
curl -X GET "https://app.kanorio.com/api/v1/sites/{id}/revisions/{revisionId}" \
-H "Authorization: Bearer $KANORIO_TOKEN"/sites/{id}/revisions/{revisionId}/restorerevisions.restore
BetaRestore a website draft or blog post working copy to a previous revision. Before writing, the current draft is automatically backed up as a PRE_RESTORE revision so the restore itself can be undone. Restoring writes only to the draft/working copy and never alters the live published site directly; call site.publish or posts.publish to publish. For WEBSITE revisions, pass mode: "page" with pageId to restore only a single page's sections, or mode: "full" (default) to restore the entire site draft and theme settings. Errors: FORBIDDEN, REVISION_NOT_FOUND, SUBJECT_NOT_FOUND, PAGE_NOT_FOUND_IN_REVISION, PAGE_NOT_FOUND_IN_SITE, VALIDATION_FAILED, WRITE_FROZEN.
- Permission
- content:edit
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
revisionIdstringRequiredRevision identifier from revisions.list.
curl -X POST "https://app.kanorio.com/api/v1/sites/{id}/revisions/{revisionId}/restore" \
-H "Authorization: Bearer $KANORIO_TOKEN" \
-H "Content-Type: application/json" \
-d '{"mode":"page","pageId":"pg_example456"}'Images
/sites/{id}/mediamedia.list
BetaRead-onlyList the website's media library (the same files the user sees in the dashboard): images, videos, audio, PDFs, documents and product files, newest first, plus storage usage. Filter with assetKind, unusedOnly and search (file name); pages hold 40 files, so pass offset to continue while hasMore is true. Files in the trash and older versions kept after media.replace are not listed; files in the trash still count toward storage. Errors: FORBIDDEN.
- Permission
- editor:enter
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
Query parameters
assetKindstringOnly this kind of file; all kinds by default.
unusedOnlyboolean | stringOnly files no content uses (candidates for cleaning up storage).
searchstringPart of the file name.
sortstringnewest (default), oldest or largest.
offsetintegerNumber of items to skip.
curl -X GET "https://app.kanorio.com/api/v1/sites/{id}/media?assetKind=image&unusedOnly=false" \
-H "Authorization: Bearer $KANORIO_TOKEN"/sites/{id}/mediamedia.upload
BetaUpload one image into the website's media library. Provide exactly one of base64 or url. Files the user attaches in chat are not available to you: use media.create_upload_link for those, media.list_page_images for a page the user owns, or media.search_stock when they have no photos. Returns the asset: put asset.url in sections (pages.replace_sections), blog posts and product images, and keep asset.assetId to manage the file later (media.get, media.replace, media.trash). Uploads are kept; unused files show as unused in the media library. Errors: FORBIDDEN, VALIDATION, INVALID_IMAGE_DATA, UNSUPPORTED_IMAGE_TYPE, FILE_TOO_LARGE, FETCH_FAILED, UPLOAD_FAILED, STORAGE_LIMIT_EXCEEDED (plan storage is full; images count toward it).
- Permission
- content:edit
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
curl -X POST "https://app.kanorio.com/api/v1/sites/{id}/media" \
-H "Authorization: Bearer $KANORIO_TOKEN" \
-H "Content-Type: application/json" \
-d '{"url":"https://example.com/photos/croissant.jpg"}'/sites/{id}/media/upload-linksmedia.create_upload_link
BetaCreate a short-lived (15 min) upload page the user opens on their phone or computer to send you photos. Use it whenever the user offers photos in the conversation: chat clients never pass attachments to tools, so you cannot see or upload those files yourself and must not pretend you did. Reply to the user with the returned url in plain words (e.g. 'Open this link and add your photos, then tell me when you're done'). Afterwards call media.upload_link_status with the same token to get the uploaded images. Errors: FORBIDDEN, SERVICE_UNAVAILABLE (try again shortly).
- Permission
- content:edit
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
curl -X POST "https://app.kanorio.com/api/v1/sites/{id}/media/upload-links" \
-H "Authorization: Bearer $KANORIO_TOKEN" \
-H "Content-Type: application/json" \
-d '{"maxFiles":6,"purpose":"menu photos"}'/sites/{id}/media/upload-links/statusmedia.upload_link_status
BetaRead-onlyCheck what the user has uploaded through an upload link (media.create_upload_link). Call it when the user says they are done, or to poll every 20-30 seconds while waiting. Returns the uploaded images as assets (put asset.url in sections, keep assetId to manage them) and how many more the link accepts. The status stays readable for a few minutes after the link expires. Errors: FORBIDDEN, LINK_INVALID (token does not belong to this website or is malformed).
- Permission
- editor:enter
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
Query parameters
tokenstringRequiredThe token returned by media.create_upload_link.
curl -X GET "https://app.kanorio.com/api/v1/sites/{id}/media/upload-links/status?token=example-upload-link-token" \
-H "Authorization: Bearer $KANORIO_TOKEN"/sites/{id}/media/stockmedia.search_stock
BetaRead-onlySearch free stock photos (Pexels and Pixabay) when the user has no photos of their own. Ask the user first whether they have photos; use stock as the fallback and tell them the images are stock photos they can replace later. Write the query in English with concrete nouns (e.g. 'sourdough bread bakery counter', not 'nice bakery'); add orientation=landscape for hero backgrounds. Both libraries allow commercial use without attribution; do not use stock photos as the brand logo or to imply endorsement. Pick a hit, then call media.import_stock to copy it into the website's media library. Errors: FORBIDDEN, SEARCH_BUSY (retry after details.retryAfter seconds), SEARCH_FAILED, UNKNOWN_PROVIDER.
- Permission
- editor:enter
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite the photos are for (scopes the token's access).
Query parameters
querystringRequiredEnglish search terms work best.
orientationstringproviderstringDefaults to all (results interleaved).
perPageintegerDefaults to 9.
pageinteger
curl -X GET "https://app.kanorio.com/api/v1/sites/{id}/media/stock?query=sourdough+bread+bakery+counter&orientation=landscape&perPage=3" \
-H "Authorization: Bearer $KANORIO_TOKEN"/sites/{id}/media/stockmedia.import_stock
BetaCopy one stock photo from media.search_stock into the website's media library. Pass provider, id and downloadURL exactly as returned by the search. Returns the asset: put asset.url in sections (backgroundImage, images[].url) and keep asset.assetId to manage it. Write the imageAlt yourself in the site's content language, based on the photo's alt and the section's purpose. Errors: FORBIDDEN, UNKNOWN_PROVIDER, INVALID_STOCK_URL, STOCK_BUSY, INVALID_IMAGE_DATA, UPLOAD_FAILED, STORAGE_LIMIT_EXCEEDED.
- Permission
- content:edit
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
curl -X POST "https://app.kanorio.com/api/v1/sites/{id}/media/stock" \
-H "Authorization: Bearer $KANORIO_TOKEN" \
-H "Content-Type: application/json" \
-d '{"provider":"pexels","id":"1234567","downloadURL":"https://images.pexels.com/photos/1234567/pexels-photo-1234567.jpeg"}'/sites/{id}/media/page-imagesmedia.list_page_images
BetaRead-onlyList the images found on a public web page (its cover image, content images and logo) when the user points you to a site they own, such as their old website or a brand page. Nothing is downloaded; pick the ones you need and copy them with media.upload (url mode). Before copying, confirm with the user that the images are theirs or they have the right to use them; do not copy images from sites that are not the user's. Pages behind a login or anti-bot walls (Instagram, Facebook) fail with FETCH_FAILED: ask the user to use an upload link instead. Errors: FORBIDDEN, INVALID_URL (private or non-http address), FETCH_FAILED (details.status is the upstream status).
- Permission
- editor:enter
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite the images are for (scopes the token's access).
Query parameters
urlstringRequiredmaxintegerDefaults to 12.
curl -X GET "https://app.kanorio.com/api/v1/sites/{id}/media/page-images?url=https%3A%2F%2Fold-site.example.com%2F&max=5" \
-H "Authorization: Bearer $KANORIO_TOKEN"/sites/{id}/media/{assetId}media.get
BetaRead-onlyGet one file from the media library or the trash, with every place the site uses it (page sections, share images, brand, posts, products, emails). Errors: FORBIDDEN, ASSET_NOT_FOUND.
- Permission
- editor:enter
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
assetIdstringRequiredAsset id from media.list.
curl -X GET "https://app.kanorio.com/api/v1/sites/{id}/media/{assetId}" \
-H "Authorization: Bearer $KANORIO_TOKEN"/sites/{id}/media/{assetId}media.purge
BetaPermanently delete a file that is already in the trash (call media.trash first) and free its storage. This cannot be undone. If the site still uses the file, the call fails with ASSET_IN_USE and details.usages: tell the user those places will stay empty, and only retry with confirm: true after they agree. Errors: FORBIDDEN, NOT_FOUND, NOT_IN_TRASH, PRODUCT_FILE_PROTECTED, ASSET_IN_USE, EXPORT_HOLD (details.until: an export keeps the file until then), DELETE_FAILED.
- Permission
- content:edit
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
assetIdstringRequiredAsset id from media.list.
Query parameters
confirmboolean | stringSet true (REST: ?confirm=true) only after the user agreed that the places in ASSET_IN_USE details.usages will stay empty.
curl -X DELETE "https://app.kanorio.com/api/v1/sites/{id}/media/{assetId}" \
-H "Authorization: Bearer $KANORIO_TOKEN"/sites/{id}/media/{assetId}/replacemedia.replace
BetaUpload a new version of an image (exactly one of base64 or url). Every place that uses it switches to the new version and keeps the same assetId, so no content needs to be edited: the editor, brand logo, share images, products and blog posts right away; published pages after the next site.publish (awaitingPublish). When the aspect ratio changes, crops are re-centered per layout (aspectRatioChanged): tell the user to check the pages listed in usages. Tell the user before replacing a file that many places use. Only images; videos, audio, PDFs and documents are replaced in the dashboard media library. The older version stays until no published page uses it, then moves to the trash. Errors: FORBIDDEN, ASSET_NOT_FOUND (also for files in the trash), IMAGES_ONLY, REPLACE_NOT_AVAILABLE, VALIDATION, INVALID_IMAGE_DATA, UNSUPPORTED_IMAGE_TYPE, FILE_TOO_LARGE, FETCH_FAILED, STORAGE_LIMIT_EXCEEDED, SERVICE_UNAVAILABLE, UPLOAD_FAILED.
- Permission
- content:edit
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
assetIdstringRequiredAsset id from media.list.
curl -X POST "https://app.kanorio.com/api/v1/sites/{id}/media/{assetId}/replace" \
-H "Authorization: Bearer $KANORIO_TOKEN" \
-H "Content-Type: application/json" \
-d '{"url":"https://example.com/photos/hero-2026.jpg"}'/sites/{id}/media/{assetId}/trashmedia.trash
BetaMove a file to the trash. It stops showing on the site right away (places that use it show nothing), still counts toward storage, and is deleted permanently after 30 days unless restored with media.restore. The response lists where it was used so you can tell the user what will look empty. Product files cannot be trashed; remove them from the product instead. Errors: FORBIDDEN, NOT_FOUND, PRODUCT_FILE_PROTECTED.
- Permission
- content:edit
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
assetIdstringRequiredAsset id from media.list.
curl -X POST "https://app.kanorio.com/api/v1/sites/{id}/media/{assetId}/trash" \
-H "Authorization: Bearer $KANORIO_TOKEN" \
-H "Content-Type: application/json" \
-d '{}'/sites/{id}/media/{assetId}/restoremedia.restore
BetaRestore a file from the trash; it shows on the site again right away. An older version left by replacing a file comes back as a separate file with a new assetId (returned); old content keeps showing the current version. Errors: FORBIDDEN, NOT_FOUND, PRODUCT_FILE_PROTECTED, RESTORE_FAILED.
- Permission
- content:edit
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
assetIdstringRequiredAsset id from media.list.
curl -X POST "https://app.kanorio.com/api/v1/sites/{id}/media/{assetId}/restore" \
-H "Authorization: Bearer $KANORIO_TOKEN" \
-H "Content-Type: application/json" \
-d '{}'Blog
/sites/{id}/postsposts.list
BetaRead-onlyList blog posts (drafts and published) with status, taxonomy and revision timestamps; contentMarkdown is not included, use posts.get. Filter by status, category, tag or search; sort by edited/published/views. Errors: FORBIDDEN.
- Permission
- posts:view
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
Query parameters
statusstringsearchstringCase-insensitive match on title or slug.
categoryIdstringtagIdstringsortstringDefaults to edited_desc.
limitintegerPage size (1-100). Defaults vary per capability.
offsetintegerNumber of items to skip.
curl -X GET "https://app.kanorio.com/api/v1/sites/{id}/posts?status=DRAFT" \
-H "Authorization: Bearer $KANORIO_TOKEN"/sites/{id}/postsposts.create
BetaCreate a blog post as a DRAFT. Drafts are not visible on the public site until posts.publish. Taxonomy ids (categoryIds, tagIds, authorIds) must belong to this website; use blog_categories.list / blog_tags.list first. Errors: FORBIDDEN, VALIDATION, SLUG_TAKEN, ASSET_NOT_FOUND (details.assetIds: not in this site's media library; the share image also must not be in the trash), ASSET_NOT_ALLOWED (product files, or a non-image as the share image).
- Permission
- blog:manage
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
curl -X POST "https://app.kanorio.com/api/v1/sites/{id}/posts" \
-H "Authorization: Bearer $KANORIO_TOKEN" \
-H "Content-Type: application/json" \
-d '{"title":"How we feed our sourdough starter","contentMarkdown":"## 5 a.m. in the bakehouse\n\nDiscard half the starter, then fold in fresh flour and warm water...","categoryIds":["cat_example01"],"tagIds":["tag_example01"]}'/sites/{id}/posts/{postId}posts.get
BetaRead-onlyGet one blog post including the working-copy contentMarkdown (what the editor shows, not necessarily the published copy) and SEO fields. Errors: FORBIDDEN, POST_NOT_FOUND.
- Permission
- posts:view
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
postIdstringRequiredBlog post id. Get it from posts.list.
curl -X GET "https://app.kanorio.com/api/v1/sites/{id}/posts/{postId}" \
-H "Authorization: Bearer $KANORIO_TOKEN"/sites/{id}/posts/{postId}posts.update
BetaPartially update a blog post's working copy (only provided fields change; categoryIds/tagIds/authorIds replace the whole list when provided). Editing a PUBLISHED post does not change the public copy until posts.publish is called again (hasDraftChanges becomes true). Errors: FORBIDDEN, POST_NOT_FOUND, VALIDATION, SLUG_TAKEN, ASSET_NOT_FOUND (details.assetIds: not in this site's media library; the share image also must not be in the trash), ASSET_NOT_ALLOWED (product files, or a non-image as the share image).
- Permission
- blog:manage
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
postIdstringRequiredBlog post id. Get it from posts.list.
curl -X PATCH "https://app.kanorio.com/api/v1/sites/{id}/posts/{postId}" \
-H "Authorization: Bearer $KANORIO_TOKEN" \
-H "Content-Type: application/json" \
-d '{"excerpt":"The first thing we do at 5 a.m. every morning."}'/sites/{id}/posts/{postId}/publishposts.publish
BetaPublish a blog post (or re-publish a published post's pending edits). Snapshots the working copy to the public site immediately; the website itself must already be published (site.publish) and on a paid plan. Errors: FORBIDDEN, POST_NOT_FOUND, PRO_REQUIRED, SITE_NOT_PUBLISHED, SLUG_TAKEN.
- Permission
- blog:manage
- Rate limit
- 30 per hour
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
postIdstringRequiredBlog post id. Get it from posts.list.
curl -X POST "https://app.kanorio.com/api/v1/sites/{id}/posts/{postId}/publish" \
-H "Authorization: Bearer $KANORIO_TOKEN" \
-H "Content-Type: application/json" \
-d '{}'/sites/{id}/posts/{postId}/unpublishposts.unpublish
BetaRevert a published post to DRAFT so it disappears from the public site. The content is kept; publishedAt is preserved as the first-publish date. Errors: FORBIDDEN, POST_NOT_FOUND.
- Permission
- blog:manage
- Rate limit
- 30 per hour
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
postIdstringRequiredBlog post id. Get it from posts.list.
curl -X POST "https://app.kanorio.com/api/v1/sites/{id}/posts/{postId}/unpublish" \
-H "Authorization: Bearer $KANORIO_TOKEN" \
-H "Content-Type: application/json" \
-d '{}'/sites/{id}/blog/categoriesblog_categories.list
BetaRead-onlyList this website's blog categories (id, slug, name, counts.posts). Use the ids in posts.create / posts.update categoryIds and primaryCategoryId. Errors: FORBIDDEN.
- Permission
- posts:view
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
curl -X GET "https://app.kanorio.com/api/v1/sites/{id}/blog/categories" \
-H "Authorization: Bearer $KANORIO_TOKEN"Collections
/sites/{id}/collectionscollections.list
BetaRead-onlyList the site's collections (custom and system) with their field schemas and item counts. Call this before reading or writing items. Errors: FORBIDDEN.
- Permission
- collections:view
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
curl -X GET "https://app.kanorio.com/api/v1/sites/{id}/collections" \
-H "Authorization: Bearer $KANORIO_TOKEN"/sites/{id}/collectionscollections.create
BetaCreate a collection (a small database for site content: teachers, projects, locations, FAQ…). Not for app data such as members, orders or comments. Field types: text, rich_text, email, phone, url, video_url, number, boolean, date, datetime, select, multi_select, color, image, gallery, file, reference, multi_reference, json. Every field needs id (snake_case), name, type; required defaults to false. Constraints: text min/max/pattern/unique/default; number integer/min/max/unique; select/multi_select options [{id,label}]; reference/multi_reference targetCollectionKey; gallery/multi_* max. Add aiHint to tell future agents how to fill a field. titleFieldId must point to a text/email/url field; it names items and generates slugs. Returns the Delivery API endpoints and a fetch example. Errors: FORBIDDEN, VALIDATION (details.issues), KEY_TAKEN, COLLECTION_LIMIT_REACHED, SYSTEM_COLLECTION (reserved key).
- Permission
- collections:manage
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
curl -X POST "https://app.kanorio.com/api/v1/sites/{id}/collections" \
-H "Authorization: Bearer $KANORIO_TOKEN" \
-H "Content-Type: application/json" \
-d '{"key":"teachers","displayName":"Teachers","singularName":"Teacher","description":"Faculty shown on the About page.","titleFieldId":"name","fields":[{"id":"name","name":"Name","type":"text","required":true,"max":80,"unique":true,"aiHint":"Full name as shown on the site."},{"id":"avatar","name":"Avatar","type":"image","required":false,"help":"Square portrait."},{"id":"subjects","name":"Subjects","type":"multi_select","required":true,"options":[{"id":"math","label":"Math"},{"id":"english","label":"English"},{"id":"physics","label":"Physics"}]},{"id":"bio","name":"Bio","type":"rich_text","required":false,"max":2000},{"id":"website","name":"Personal website","type":"url","required":false},{"id":"course","name":"Main course","type":"reference","required":false,"targetCollectionKey":"courses"}]}'/sites/{id}/collections/{key}collections.get
BetaRead-onlyGet one collection's schema (fields, constraints, aiHint) plus its Content Delivery API endpoints. Errors: FORBIDDEN, COLLECTION_NOT_FOUND.
- Permission
- collections:view
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
keystringRequiredCollection key (slug). Get it from collections.list.
curl -X GET "https://app.kanorio.com/api/v1/sites/{id}/collections/{key}" \
-H "Authorization: Bearer $KANORIO_TOKEN"/sites/{id}/collections/{key}collections.update
BetaChange a collection's name, description, titleFieldId or fields. fields replaces the whole ordered list: read it with collections.get, edit, send it back. Allowed immediately: add fields, rename, change help/aiHint, add options, relax constraints, remove custom fields (data is ignored, cleaned on next write). Type changes only along compatible paths (e.g. text→rich_text, select→multi_select, reference→multi_reference, image→gallery); otherwise add a new field, migrate, remove the old one. Tightened constraints are checked against existing items first. System collections (blog): reserved fields cannot be removed or retyped. Errors: FORBIDDEN, COLLECTION_NOT_FOUND, VALIDATION (details.issues), SCHEMA_CHANGE_REJECTED (details.schemaIssues).
- Permission
- collections:manage
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
keystringRequiredCollection key (slug). Get it from collections.list.
curl -X PATCH "https://app.kanorio.com/api/v1/sites/{id}/collections/{key}" \
-H "Authorization: Bearer $KANORIO_TOKEN" \
-H "Content-Type: application/json" \
-d '{"description":"Faculty and guest lecturers.","fields":[{"id":"name","name":"Name","type":"text","required":true,"max":80,"unique":true,"aiHint":"Full name as shown on the site."},{"id":"avatar","name":"Avatar","type":"image","required":false,"help":"Square portrait."},{"id":"subjects","name":"Subjects","type":"multi_select","required":true,"options":[{"id":"math","label":"Math"},{"id":"english","label":"English"},{"id":"physics","label":"Physics"}]},{"id":"bio","name":"Bio","type":"rich_text","required":false,"max":2000},{"id":"website","name":"Personal website","type":"url","required":false},{"id":"course","name":"Main course","type":"reference","required":false,"targetCollectionKey":"courses"},{"id":"years","name":"Years of experience","type":"number","required":false,"integer":true,"min":0}]}'/sites/{id}/collections/{key}collections.delete
BetaDelete a custom collection and ALL its items. Irreversible. confirmKey must equal key. Refused while another collection references it, and for system collections. Not included in any OAuth scope preset; a PAT must grant collections:manage explicitly. Errors: FORBIDDEN, COLLECTION_NOT_FOUND, CONFIRM_REQUIRED, REFERENCED (details.referencedBy), SYSTEM_COLLECTION.
- Permission
- collections:manage
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
keystringRequiredCollection key (slug). Get it from collections.list.
Query parameters
confirmKeystringRequiredMust equal key.
curl -X DELETE "https://app.kanorio.com/api/v1/sites/{id}/collections/{key}?confirmKey=teachers" \
-H "Authorization: Bearer $KANORIO_TOKEN"/sites/{id}/collections/{key}/itemsitems.list
BetaRead-onlyList or query items with the same filter/sort DSL the Content Delivery API uses: AND of up to 10 conditions, 3 sort fields, cursor or offset paging. source=draft (default) includes unpublished edits; source=published returns only what the public API serves. Over REST (GET) pass filter and sort as JSON strings, e.g. ?filter={"subjects":{"has":"math"}}&sort=-publishedAt. Errors: FORBIDDEN, COLLECTION_NOT_FOUND, VALIDATION (details.queryIssues: unknown field, op not allowed for the type, invalid value).
- Permission
- collections:view
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
keystringRequiredCollection key (slug). Get it from collections.list.
Query parameters
sourcestringstatusstringOnly with source=draft.
filterobject | stringsortstring | object[]Array of { field, direction } or a comma-separated shorthand, e.g. "-publishedAt,name".
limitintegerPage size (1-100). Defaults vary per capability.
offsetintegerNumber of items to skip.
cursorstringfieldsstring[]Only return these fieldIds.
expandstring[]Reference fields to expand one level (id, slug, title).
curl -X GET "https://app.kanorio.com/api/v1/sites/{id}/collections/{key}/items?source=published&filter=%7B%22subjects%22%3A%7B%22has%22%3A%22math%22%7D%2C%22name%22%3A%7B%22contains%22%3A%22chen%22%7D%7D&sort=-publishedAt%2Cname&limit=20" \
-H "Authorization: Bearer $KANORIO_TOKEN"/sites/{id}/collections/{key}/itemsitems.create
BetaCreate one item. Values are validated against the collection schema; fix the listed fieldIds on VALIDATION. slug is generated from the title field when omitted. Errors: FORBIDDEN, COLLECTION_NOT_FOUND, VALIDATION (details.issues: fieldId, code, message, example), UNIQUE_CONFLICT, SLUG_TAKEN, PLAN_ITEM_LIMIT_REACHED (details.quota), COLLECTION_ITEM_LIMIT_REACHED, SYSTEM_COLLECTION (blog collections are read-only here; use blog.*).
- Permission
- collections:manage
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
keystringRequiredCollection key (slug). Get it from collections.list.
curl -X POST "https://app.kanorio.com/api/v1/sites/{id}/collections/{key}/items" \
-H "Authorization: Bearer $KANORIO_TOKEN" \
-H "Content-Type: application/json" \
-d '{"fieldData":{"name":"Amy Chen","avatar":"asset_example01","subjects":["math","physics"],"bio":"Ten years of teaching high-school math.","website":"https://amychen.example.com","course":"item_example02"},"publish":true}'/sites/{id}/collections/{key}/items/bulkitems.bulk_create
BetaCreate up to 200 items in one transaction (all or nothing). On failure nothing is written and failed[] lists each bad entry by index with its issues. Errors: FORBIDDEN, COLLECTION_NOT_FOUND, VALIDATION, UNIQUE_CONFLICT, SLUG_TAKEN, PLAN_ITEM_LIMIT_REACHED (details.quota), COLLECTION_ITEM_LIMIT_REACHED, SYSTEM_COLLECTION.
- Permission
- collections:manage
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
keystringRequiredCollection key (slug). Get it from collections.list.
curl -X POST "https://app.kanorio.com/api/v1/sites/{id}/collections/{key}/items/bulk" \
-H "Authorization: Bearer $KANORIO_TOKEN" \
-H "Content-Type: application/json" \
-d '{"items":[{"fieldData":{"name":"Amy Chen","avatar":"asset_example01","subjects":["math","physics"],"bio":"Ten years of teaching high-school math.","website":"https://amychen.example.com","course":"item_example02"}},{"fieldData":{"name":"Ben Lin","subjects":["english"]}}],"publish":true}'/sites/{id}/collections/{key}/items/bulkitems.bulk_update
BetaUpdate up to 200 items in one transaction (all or nothing); each entry is a partial update by itemId. Errors: FORBIDDEN, COLLECTION_NOT_FOUND, ITEM_NOT_FOUND, VALIDATION, UNIQUE_CONFLICT, SLUG_TAKEN, SYSTEM_COLLECTION.
- Permission
- collections:manage
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
keystringRequiredCollection key (slug). Get it from collections.list.
curl -X PATCH "https://app.kanorio.com/api/v1/sites/{id}/collections/{key}/items/bulk" \
-H "Authorization: Bearer $KANORIO_TOKEN" \
-H "Content-Type: application/json" \
-d '{"items":[{"itemId":"item_example01","fieldData":{"subjects":["math"]}}],"publish":true}'/sites/{id}/collections/{key}/items/publishitems.publish
BetaPublish up to 200 items: copies each draft to the public copy. Returns the updated items and ids that were not found. Errors: FORBIDDEN, COLLECTION_NOT_FOUND, VALIDATION, SYSTEM_COLLECTION.
- Permission
- collections:manage
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
keystringRequiredCollection key (slug). Get it from collections.list.
curl -X POST "https://app.kanorio.com/api/v1/sites/{id}/collections/{key}/items/publish" \
-H "Authorization: Bearer $KANORIO_TOKEN" \
-H "Content-Type: application/json" \
-d '{"itemIds":["item_example01"]}'/sites/{id}/collections/{key}/items/unpublishitems.unpublish
BetaUnpublish up to 200 items: removes them from the Content Delivery API; drafts are kept. Errors: FORBIDDEN, COLLECTION_NOT_FOUND, VALIDATION, SYSTEM_COLLECTION.
- Permission
- collections:manage
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
keystringRequiredCollection key (slug). Get it from collections.list.
curl -X POST "https://app.kanorio.com/api/v1/sites/{id}/collections/{key}/items/unpublish" \
-H "Authorization: Bearer $KANORIO_TOKEN" \
-H "Content-Type: application/json" \
-d '{"itemIds":["item_example01"]}'/sites/{id}/collections/{key}/items/{itemId}items.get
BetaRead-onlyGet one item by id or slug, with draft and published values. Errors: FORBIDDEN, COLLECTION_NOT_FOUND, ITEM_NOT_FOUND.
- Permission
- collections:view
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
keystringRequiredCollection key (slug). Get it from collections.list.
itemIdstringRequiredItem id or slug.
curl -X GET "https://app.kanorio.com/api/v1/sites/{id}/collections/{key}/items/{itemId}" \
-H "Authorization: Bearer $KANORIO_TOKEN"/sites/{id}/collections/{key}/items/{itemId}items.update
BetaPartially update an item: only the fieldIds you send change; send null to clear a field. publish=false keeps the public copy unchanged (status becomes changed). Errors: FORBIDDEN, COLLECTION_NOT_FOUND, ITEM_NOT_FOUND, VALIDATION (details.issues: fieldId, code, message, example), UNIQUE_CONFLICT, SLUG_TAKEN, PLAN_ITEM_LIMIT_REACHED (details.quota), COLLECTION_ITEM_LIMIT_REACHED, SYSTEM_COLLECTION (blog collections are read-only here; use blog.*).
- Permission
- collections:manage
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
keystringRequiredCollection key (slug). Get it from collections.list.
itemIdstringRequiredItem id. Get it from items.list.
curl -X PATCH "https://app.kanorio.com/api/v1/sites/{id}/collections/{key}/items/{itemId}" \
-H "Authorization: Bearer $KANORIO_TOKEN" \
-H "Content-Type: application/json" \
-d '{"fieldData":{"bio":"Updated bio, not yet published."},"publish":false}'/sites/{id}/collections/{key}/items/{itemId}items.delete
BetaDelete one item. Refused with REFERENCED (details.referencedBy) while other items reference it, unless force=true (readers then ignore the dangling id). Errors: FORBIDDEN, COLLECTION_NOT_FOUND, ITEM_NOT_FOUND, REFERENCED, SYSTEM_COLLECTION.
- Permission
- collections:manage
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
keystringRequiredCollection key (slug). Get it from collections.list.
itemIdstringRequiredItem id. Get it from items.list.
Query parameters
forceboolean
curl -X DELETE "https://app.kanorio.com/api/v1/sites/{id}/collections/{key}/items/{itemId}?force=false" \
-H "Authorization: Bearer $KANORIO_TOKEN"/sites/{id}/allowed-originssite.get_allowed_origins
BetaRead-onlyList the origins allowed to call the Content Delivery API cross-origin (CORS allowlist). Same-origin and localhost need no entry. Errors: FORBIDDEN.
- Permission
- collections:view
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
curl -X GET "https://app.kanorio.com/api/v1/sites/{id}/allowed-origins" \
-H "Authorization: Bearer $KANORIO_TOKEN"/sites/{id}/allowed-originssite.update_allowed_origins
BetaReplace the CORS allowlist for the Content Delivery API (up to 20 https origins such as https://app.example.com; no paths or wildcards). Errors: FORBIDDEN, VALIDATION (details.issues).
- Permission
- site:manage_settings
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
curl -X PUT "https://app.kanorio.com/api/v1/sites/{id}/allowed-origins" \
-H "Authorization: Bearer $KANORIO_TOKEN" \
-H "Content-Type: application/json" \
-d '{"origins":["https://app.example.com","https://preview.example.com"]}'/sites/{id}/developer-settingssite.update_developer_settings
BetaUpdate headless developer settings for the website: enable headless mode (so the Content Delivery API and blog publishing work without publishing the hosted template site) and/or set the external storefront URL (so visitor traffic on the hosted site 302-redirects to your external frontend while /api/v1/*, /checkout and /account stay active). Pass null to externalStorefrontUrl to clear it. Returns the site's permanent systemHost (s-xxx.kanorio.com). Errors: FORBIDDEN, VALIDATION (details.issues).
- Permission
- site:manage_settings
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
curl -X PATCH "https://app.kanorio.com/api/v1/sites/{id}/developer-settings" \
-H "Authorization: Bearer $KANORIO_TOKEN" \
-H "Content-Type: application/json" \
-d '{"headlessEnabled":true,"externalStorefrontUrl":"https://www.sunnybakery.example"}'/sites/{id}/preview-tokenssite.create_preview_token
BetaMint a read-only headless preview token (knr_pv_…) for reading unpublished drafts via the Content Delivery API (send X-Kanorio-Preview: knr_pv_… or Authorization: Bearer knr_pv_… with ?preview=1). Unlike a PAT, a preview token can only read drafts of this website and expires automatically. Errors: FORBIDDEN, VALIDATION.
- Permission
- site:manage_settings
- Rate limit
- 30 per hour
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
curl -X POST "https://app.kanorio.com/api/v1/sites/{id}/preview-tokens" \
-H "Authorization: Bearer $KANORIO_TOKEN" \
-H "Content-Type: application/json" \
-d '{"label":"Next.js Draft Mode","ttlSeconds":604800}'/sites/{id}/webhookswebhooks.list
BetaRead-onlyList the website's webhook endpoints, recent deliveries, plan quota (Pro: 3, Business: 10) and subscribable event keys. Errors: FORBIDDEN.
- Permission
- site:integrations
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
curl -X GET "https://app.kanorio.com/api/v1/sites/{id}/webhooks" \
-H "Authorization: Bearer $KANORIO_TOKEN"/sites/{id}/webhookswebhooks.create
BetaCreate a webhook endpoint (public https URL). Returns the HMAC-SHA256 signingSecret (whsec_…) once — store it in your receiver's environment to verify X-Kanorio-Signature. Pass events (from webhooks.list subscribableEvents) to subscribe to specific events, or omit/null to subscribe to all events. Errors: FORBIDDEN, PLAN_REQUIRED, WEBHOOK_LIMIT_REACHED, DUPLICATE_WEBHOOK, VALIDATION.
- Permission
- site:integrations
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
curl -X POST "https://app.kanorio.com/api/v1/sites/{id}/webhooks" \
-H "Authorization: Bearer $KANORIO_TOKEN" \
-H "Content-Type: application/json" \
-d '{"url":"https://www.sunnybakery.example/api/revalidate","label":"Vercel ISR Revalidate","events":["collections.item.published","collections.items.bulkChanged"]}'/sites/{id}/webhooks/{webhookId}/eventswebhooks.update_events
BetaReplace the subscribed event list and optional filter (collectionKeys / formIds) of a webhook endpoint. Pass null for events to subscribe to all events (including future events). Filters require the Business plan. Errors: FORBIDDEN, WEBHOOK_NOT_FOUND, PLAN_REQUIRED, VALIDATION.
- Permission
- site:integrations
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
webhookIdstringRequiredWebhook destination id. Get it from webhooks.list.
curl -X PUT "https://app.kanorio.com/api/v1/sites/{id}/webhooks/{webhookId}/events" \
-H "Authorization: Bearer $KANORIO_TOKEN" \
-H "Content-Type: application/json" \
-d '{"events":["collections.item.published"],"filter":{"collectionKeys":["blog"]}}'/sites/{id}/webhooks/{webhookId}webhooks.delete
BetaDelete a webhook endpoint. Errors: FORBIDDEN, WEBHOOK_NOT_FOUND.
- Permission
- site:integrations
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
webhookIdstringRequiredWebhook destination id. Get it from webhooks.list.
curl -X DELETE "https://app.kanorio.com/api/v1/sites/{id}/webhooks/{webhookId}" \
-H "Authorization: Bearer $KANORIO_TOKEN"/sites/{id}/webhooks/{webhookId}/testwebhooks.test
BetaSend a one-off team.test ping to a webhook endpoint and return the HTTP status and latency (does not count toward auto-disable failures). Errors: FORBIDDEN, WEBHOOK_NOT_FOUND.
- Permission
- site:integrations
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
webhookIdstringRequiredWebhook destination id. Get it from webhooks.list.
curl -X POST "https://app.kanorio.com/api/v1/sites/{id}/webhooks/{webhookId}/test" \
-H "Authorization: Bearer $KANORIO_TOKEN" \
-H "Content-Type: application/json" \
-d '{}'Forms
/sites/{id}/formsforms.list
BetaRead-onlyList this website's online forms with status, availability and submission counts. Errors: FORBIDDEN.
- Permission
- marketing:view
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
curl -X GET "https://app.kanorio.com/api/v1/sites/{id}/forms" \
-H "Authorization: Bearer $KANORIO_TOKEN"/sites/{id}/forms/{formId}forms.get
BetaRead-onlyGet one form including its field definitions and settings (read-only; forms are edited in the console). Errors: FORBIDDEN, FORM_NOT_FOUND.
- Permission
- marketing:view
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
formIdstringRequiredForm id. Get it from forms.list.
curl -X GET "https://app.kanorio.com/api/v1/sites/{id}/forms/{formId}" \
-H "Authorization: Bearer $KANORIO_TOKEN"/sites/{id}/forms/{formId}/submissionssubmissions.list
BetaRead-onlyList submissions of one form, newest first, with answers keyed by field id. Filter by status, full-text query and recent days. Attachments are returned as metadata only; downloading files and exporting CSV are not available to agents. Errors: FORBIDDEN, FORM_NOT_FOUND.
- Permission
- marketing:view
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
formIdstringRequiredForm id. Get it from forms.list.
Query parameters
pageinteger1-based page number.
pageSizeinteger10-100; defaults to 50.
statusstringqstringFull-text search in answers.
daysintegerOnly submissions from the last N days in the website's timezone; one of 1, 7, 30, 90.
curl -X GET "https://app.kanorio.com/api/v1/sites/{id}/forms/{formId}/submissions?page=1&pageSize=20" \
-H "Authorization: Bearer $KANORIO_TOKEN"/sites/{id}/forms/{formId}/submissions/{submissionId}submissions.get
BetaRead-onlyGet one submission of a form with its answers and attachment metadata. Errors: FORBIDDEN, SUBMISSION_NOT_FOUND.
- Permission
- marketing:view
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
formIdstringRequiredForm id. Get it from forms.list.
submissionIdstringRequired
curl -X GET "https://app.kanorio.com/api/v1/sites/{id}/forms/{formId}/submissions/{submissionId}" \
-H "Authorization: Bearer $KANORIO_TOKEN"Contacts
/sites/{id}/contactscontacts.list
BetaRead-onlyList contacts (50 per page) with email marketing status, tags and purchase summary. Filter by status, source, buyers only, or search on email/name/phone; sort by RECENT, SPENT or LAST_ORDER. Errors: FORBIDDEN.
- Permission
- customers:view
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
Query parameters
pageinteger1-based page number.
searchstringstatusstringsourcestringbuyerstringBUYERS = has at least one paid order.
sortstring
curl -X GET "https://app.kanorio.com/api/v1/sites/{id}/contacts?page=1" \
-H "Authorization: Bearer $KANORIO_TOKEN"/sites/{id}/contactscontacts.add
BetaAdd one contact by email (source MANUAL). Only set marketingConsent=true when the person has explicitly agreed to receive marketing email; otherwise the contact is created without consent. Errors: FORBIDDEN, DUPLICATE (email already exists), SUPPRESSED (address is blocked), INVALID_EMAIL, INVALID_PHONE.
- Permission
- customers:manage
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
curl -X POST "https://app.kanorio.com/api/v1/sites/{id}/contacts" \
-H "Authorization: Bearer $KANORIO_TOKEN" \
-H "Content-Type: application/json" \
-d '{"email":"customer@example.com","name":"Alex Chen","tags":["cake-order"],"marketingConsent":false}'/sites/{id}/contacts/{contactId}contacts.get
BetaRead-onlyGet one contact with consent state, note, custom profile attributes, purchase summary with recent orders, and the last 50 timeline events/messages. Errors: FORBIDDEN, CONTACT_NOT_FOUND.
- Permission
- customers:view
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
contactIdstringRequiredContact id. Get it from contacts.list.
curl -X GET "https://app.kanorio.com/api/v1/sites/{id}/contacts/{contactId}" \
-H "Authorization: Bearer $KANORIO_TOKEN"/sites/{id}/segmentssegments.list
BetaRead-onlyList contact segments with their rules and live audience counts. Use a segment id as campaigns.* audience. Errors: FORBIDDEN.
- Permission
- customers:view
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
curl -X GET "https://app.kanorio.com/api/v1/sites/{id}/segments" \
-H "Authorization: Bearer $KANORIO_TOKEN"Products
/sites/{id}/productsproducts.list
BetaRead-onlyList products (ACTIVE first, then ARCHIVED) with images, variants and paid order counts; storeCurrency is the ISO 4217 code all amounts use. Errors: FORBIDDEN.
- Permission
- store:view
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
Query parameters
statusstringlimitintegerPage size (1-100). Defaults vary per capability.
offsetintegerNumber of items to skip.
curl -X GET "https://app.kanorio.com/api/v1/sites/{id}/products" \
-H "Authorization: Bearer $KANORIO_TOKEN"/sites/{id}/productsproducts.create
BetaCreate an ACTIVE product. Products have no draft state: it appears in the store immediately once it has at least one published variant (add variants/prices in the console). Images are media-library assets: pass their assetId (upload with media.upload or media.import_stock first). Slug is generated from the title when omitted. Errors: FORBIDDEN, VALIDATION (details.reason), PRODUCT_LIMIT_REACHED, SITE_SUSPENDED, ASSET_NOT_FOUND (details.assetIds: not in this site's media library, in the trash, or its file is missing), ASSET_NOT_ALLOWED (not an image, or a product file).
- Permission
- commerce:manage
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
curl -X POST "https://app.kanorio.com/api/v1/sites/{id}/products" \
-H "Authorization: Bearer $KANORIO_TOKEN" \
-H "Content-Type: application/json" \
-d '{"title":"Strawberry Birthday Cake","productType":"PHYSICAL","description":"Seasonal strawberries and fresh whipped cream. Pre-order at least one day ahead.","images":[{"assetId":"asset_example01","alt":"Strawberry birthday cake"}]}'/sites/{id}/products/{productId}products.get
BetaRead-onlyGet one product with images, options and variants. Errors: FORBIDDEN, PRODUCT_NOT_FOUND.
- Permission
- store:view
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
productIdstringRequiredProduct id. Get it from products.list.
curl -X GET "https://app.kanorio.com/api/v1/sites/{id}/products/{productId}" \
-H "Authorization: Bearer $KANORIO_TOKEN"/sites/{id}/products/{productId}products.update
BetaPartially update a product (only provided fields change; images replace the whole list). Changes go live on the public store immediately. Errors: FORBIDDEN, PRODUCT_NOT_FOUND, VALIDATION (details.reason), SITE_SUSPENDED, ASSET_NOT_FOUND (details.assetIds: not in this site's media library, in the trash, or its file is missing), ASSET_NOT_ALLOWED (not an image, or a product file).
- Permission
- commerce:manage
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
productIdstringRequiredProduct id. Get it from products.list.
curl -X PATCH "https://app.kanorio.com/api/v1/sites/{id}/products/{productId}" \
-H "Authorization: Bearer $KANORIO_TOKEN" \
-H "Content-Type: application/json" \
-d '{"purchaseNotes":"Please leave your preferred pickup time in the order note."}'/sites/{id}/products/{productId}/archiveproducts.archive
BetaArchive a product: it disappears from the store but keeps its orders and can be restored in the console. Deleting products is not available to agents. Errors: FORBIDDEN, PRODUCT_NOT_FOUND, SITE_SUSPENDED.
- Permission
- commerce:manage
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
productIdstringRequiredProduct id. Get it from products.list.
curl -X POST "https://app.kanorio.com/api/v1/sites/{id}/products/{productId}/archive" \
-H "Authorization: Bearer $KANORIO_TOKEN" \
-H "Content-Type: application/json" \
-d '{}'/sites/{id}/product-categoriesproduct_categories.list
BetaRead-onlyList product categories (id, slug, name, sortOrder). Category assignment is managed in the console. Errors: FORBIDDEN.
- Permission
- store:view
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
curl -X GET "https://app.kanorio.com/api/v1/sites/{id}/product-categories" \
-H "Authorization: Bearer $KANORIO_TOKEN"Deliverables & access
/sites/{id}/deliverablesdeliverables.list
BetaRead-onlyList deliverables (courses, e-books, audio series, template packs) with unit counts and linked products. A deliverable is what a buyer receives; products only sell it. Errors: FORBIDDEN.
- Permission
- store:view
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
Query parameters
pageinteger1-based page number.
statusstringsearchstring
curl -X GET "https://app.kanorio.com/api/v1/sites/{id}/deliverables" \
-H "Authorization: Bearer $KANORIO_TOKEN"/sites/{id}/deliverablesdeliverables.create
BetaCreate a deliverable. Add chapters and units with deliverable_units.replace_tree, then link it to a product with products.update({ deliverables }) or grant it directly with entitlements.grant. Use structure DOWNLOAD for a plain file bundle (e-book, template pack) and COURSE when learners should see chapters and progress. Errors: FORBIDDEN, DELIVERABLE_NOT_FOUND, KEY_TAKEN, VALIDATION (details.issues), ASSET_NOT_FOUND (details.assetIds).
- Permission
- commerce:manage
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
curl -X POST "https://app.kanorio.com/api/v1/sites/{id}/deliverables" \
-H "Authorization: Bearer $KANORIO_TOKEN" \
-H "Content-Type: application/json" \
-d '{"key":"sourdough-fundamentals","title":"Sourdough Fundamentals","description":"Six-week video course with downloadable recipe cards.","coverAssetId":"asset_example01","structure":"COURSE"}'/sites/{id}/deliverables/{deliverableId}deliverables.get
BetaRead-onlyGet one deliverable with settings and the full chapter/unit tree (no signed file URLs). Errors: FORBIDDEN, DELIVERABLE_NOT_FOUND.
- Permission
- store:view
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
deliverableIdstringRequiredDeliverable id or key. Get it from deliverables.list.
curl -X GET "https://app.kanorio.com/api/v1/sites/{id}/deliverables/{deliverableId}" \
-H "Authorization: Bearer $KANORIO_TOKEN"/sites/{id}/deliverables/{deliverableId}deliverables.update
BetaPartially update a deliverable (title, description, cover, structure, settings such as completionRule/certificate/comments). Units are managed with deliverable_units.*. Errors: FORBIDDEN, DELIVERABLE_NOT_FOUND, KEY_TAKEN, VALIDATION (details.issues), ASSET_NOT_FOUND (details.assetIds).
- Permission
- commerce:manage
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
deliverableIdstringRequiredDeliverable id or key. Get it from deliverables.list.
curl -X PATCH "https://app.kanorio.com/api/v1/sites/{id}/deliverables/{deliverableId}" \
-H "Authorization: Bearer $KANORIO_TOKEN" \
-H "Content-Type: application/json" \
-d '{"settings":{"completionRule":{"type":"percent","percent":80},"certificate":{"enabled":true,"title":"Certificate of Completion","signatureName":"Head Baker"}}}'/sites/{id}/deliverables/{deliverableId}/archivedeliverables.archive
BetaArchive a deliverable: it can no longer be granted or sold, existing learners keep access until you revoke their entitlements. Deliverables are never deleted. Errors: FORBIDDEN, DELIVERABLE_NOT_FOUND.
- Permission
- commerce:manage
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
deliverableIdstringRequiredDeliverable id or key. Get it from deliverables.list.
curl -X POST "https://app.kanorio.com/api/v1/sites/{id}/deliverables/{deliverableId}/archive" \
-H "Authorization: Bearer $KANORIO_TOKEN" \
-H "Content-Type: application/json" \
-d '{}'/sites/{id}/deliverables/{deliverableId}/unitsdeliverable_units.replace_tree
BetaReplace the whole chapter/unit tree of a deliverable (PUT semantics): units with an id are updated, units without an id are created, units missing from the payload are deleted along with learner progress on them. Two levels only: top-level nodes may have children; children cannot. For a flat download bundle just pass units without children. Upload files with media.upload first and reference them by primaryAssetId / attachmentAssetIds. Errors: FORBIDDEN, DELIVERABLE_NOT_FOUND, UNIT_TREE_INVALID (details.reason), ASSET_NOT_FOUND, VALIDATION.
- Permission
- commerce:manage
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
deliverableIdstringRequiredDeliverable id or key. Get it from deliverables.list.
curl -X PUT "https://app.kanorio.com/api/v1/sites/{id}/deliverables/{deliverableId}/units" \
-H "Authorization: Bearer $KANORIO_TOKEN" \
-H "Content-Type: application/json" \
-d '{"units":[{"kind":"chapter","title":"Week 1 · Getting started","children":[{"kind":"video","title":"Welcome and course overview","primaryAssetId":"asset_example01","isPreview":true},{"kind":"text","title":"Set up your workspace","body":{"markdown":"## Install\n\n1. Download the starter kit…"},"releaseAfterDays":2}]}]}'/sites/{id}/deliverables/{deliverableId}/units/reorderdeliverable_units.reorder
BetaReorder sibling units: pass every id of one level (top level when parentId is null) in the new order. Errors: FORBIDDEN, DELIVERABLE_NOT_FOUND, UNIT_TREE_INVALID.
- Permission
- commerce:manage
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
deliverableIdstringRequiredDeliverable id or key. Get it from deliverables.list.
curl -X POST "https://app.kanorio.com/api/v1/sites/{id}/deliverables/{deliverableId}/units/reorder" \
-H "Authorization: Bearer $KANORIO_TOKEN" \
-H "Content-Type: application/json" \
-d '{"parentId":"unit_chapter01","orderedIds":["unit_text01","unit_video01"]}'/sites/{id}/deliverable-units/{unitId}deliverable_units.update
BetaUpdate one unit in place (title, file, preview flag, unlock schedule, tier scope) without touching the tree. Errors: FORBIDDEN, DELIVERABLE_NOT_FOUND, ASSET_NOT_FOUND, VALIDATION.
- Permission
- commerce:manage
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
unitIdstringRequiredUnit id. Get it from deliverables.get.
curl -X PATCH "https://app.kanorio.com/api/v1/sites/{id}/deliverable-units/{unitId}" \
-H "Authorization: Bearer $KANORIO_TOKEN" \
-H "Content-Type: application/json" \
-d '{"title":"Welcome!","isPreview":true}'/sites/{id}/entitlementsentitlements.list
BetaRead-onlyList entitlements (who can access which deliverable) filtered by contact or deliverable; includes revoked and expired rows. Errors: FORBIDDEN.
- Permission
- customers:view
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
Query parameters
pageinteger1-based page number.
contactIdstringdeliverableIdstringDeliverable id or key. Get it from deliverables.list.
activeOnlybooleanOnly rows that are not revoked and not expired.
curl -X GET "https://app.kanorio.com/api/v1/sites/{id}/entitlements" \
-H "Authorization: Bearer $KANORIO_TOKEN"/sites/{id}/entitlementsentitlements.grant
BetaGrant a contact access to a deliverable without a purchase (gift, corporate seat, lead magnet). Idempotent: an existing active manual grant for the same deliverable is extended instead of duplicated. Errors: FORBIDDEN, CONTACT_NOT_FOUND, DELIVERABLE_NOT_FOUND (archived deliverables cannot be granted).
- Permission
- customers:manage
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
curl -X POST "https://app.kanorio.com/api/v1/sites/{id}/entitlements" \
-H "Authorization: Bearer $KANORIO_TOKEN" \
-H "Content-Type: application/json" \
-d '{"contactId":"contact_example01","deliverableId":"dlv_example01"}'/sites/{id}/entitlements/checkentitlements.check
BetaRead-onlyCheck whether a contact can access a deliverable or a single unit right now (entitlement, free preview, release schedule, expiry). Errors: FORBIDDEN, DELIVERABLE_NOT_FOUND.
- Permission
- customers:view
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
Query parameters
contactIdstringRequireddeliverableIdstringDeliverable id or key. Get it from deliverables.list.
unitIdstringUnit id. Get it from deliverables.get.
curl -X GET "https://app.kanorio.com/api/v1/sites/{id}/entitlements/check?contactId=contact_example01&deliverableId=dlv_example01" \
-H "Authorization: Bearer $KANORIO_TOKEN"/sites/{id}/entitlements/{entitlementId}/revokeentitlements.revoke
BetaRevoke one entitlement (learner loses access immediately; the row is kept for audit). Errors: FORBIDDEN, ENTITLEMENT_NOT_FOUND.
- Permission
- customers:manage
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
entitlementIdstringRequired
curl -X POST "https://app.kanorio.com/api/v1/sites/{id}/entitlements/{entitlementId}/revoke" \
-H "Authorization: Bearer $KANORIO_TOKEN" \
-H "Content-Type: application/json" \
-d '{"reason":"Corporate seat reassigned"}'/sites/{id}/deliverables/{deliverableId}/progressprogress.list
BetaRead-onlyList learner progress for one deliverable (percent, completed, per-unit status). One row per contact that has an active entitlement. Errors: FORBIDDEN, DELIVERABLE_NOT_FOUND.
- Permission
- customers:view
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
deliverableIdstringRequiredDeliverable id or key. Get it from deliverables.list.
Query parameters
pageinteger1-based page number.
contactIdstring
curl -X GET "https://app.kanorio.com/api/v1/sites/{id}/deliverables/{deliverableId}/progress" \
-H "Authorization: Bearer $KANORIO_TOKEN"Orders
/sites/{id}/ordersorders.list
BetaRead-onlyList orders newest first with line items and shipment summary (amounts in minor units of order.currency). Refunds, payment settings and invoices are not available to agents. Errors: FORBIDDEN.
- Permission
- store:view
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
Query parameters
statusstringlimitintegerPage size (1-100). Defaults vary per capability.
offsetintegerNumber of items to skip.
curl -X GET "https://app.kanorio.com/api/v1/sites/{id}/orders" \
-H "Authorization: Bearer $KANORIO_TOKEN"/sites/{id}/orders/{orderId}orders.get
BetaRead-onlyGet one order with line items and shipments. Errors: FORBIDDEN, ORDER_NOT_FOUND.
- Permission
- store:view
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
orderIdstringRequired
curl -X GET "https://app.kanorio.com/api/v1/sites/{id}/orders/{orderId}" \
-H "Authorization: Bearer $KANORIO_TOKEN"Campaigns
/sites/{id}/campaignscampaigns.list
BetaRead-onlyList email campaigns (newest updated first) with status, audience segment and delivery stats for sent ones. Errors: FORBIDDEN, PLAN_REQUIRED.
- Permission
- marketing:send
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
curl -X GET "https://app.kanorio.com/api/v1/sites/{id}/campaigns" \
-H "Authorization: Bearer $KANORIO_TOKEN"/sites/{id}/campaignscampaigns.create_draft
BetaCreate an email campaign as a DRAFT. Agents cannot send or schedule campaigns; the owner reviews and sends from the console. content is optional; when provided it must match the email design-template content shape (subject, previewText, blocks). Audience defaults to the all-subscribers segment. Reference images as asset:<assetId> (media.upload, media.import_stock). Errors: FORBIDDEN, PLAN_REQUIRED, VALIDATION, INVALID_CONTENT (details.detail lists issues), CHANNEL_UNAVAILABLE, ASSET_NOT_FOUND, ASSET_NOT_ALLOWED.
- Permission
- marketing:send
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
curl -X POST "https://app.kanorio.com/api/v1/sites/{id}/campaigns" \
-H "Authorization: Bearer $KANORIO_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"October seasonal bake","channel":"EMAIL"}'/sites/{id}/campaigns/{campaignId}campaigns.update_draft
BetaUpdate a DRAFT campaign's name, content and/or audience segment. Only drafts can be changed by agents (NOT_EDITABLE otherwise); scheduling and sending stay in the console. Errors: FORBIDDEN, PLAN_REQUIRED, CAMPAIGN_NOT_FOUND, NOT_EDITABLE, INVALID_CONTENT, INVALID_AUDIENCE, SEGMENT_NOT_FOUND, ASSET_NOT_FOUND, ASSET_NOT_ALLOWED.
- Permission
- marketing:send
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
campaignIdstringRequiredCampaign id. Get it from campaigns.list.
curl -X PATCH "https://app.kanorio.com/api/v1/sites/{id}/campaigns/{campaignId}" \
-H "Authorization: Bearer $KANORIO_TOKEN" \
-H "Content-Type: application/json" \
-d '{"audience":{"kind":"segment","segmentId":"seg_example01"}}'Analytics
/sites/{id}/analytics/overviewanalytics.overview
BetaRead-onlyGet website traffic overview for the selected period (default 30 days): pageviews, unique visitors, sessions, button clicks, form submissions, external link clicks, top traffic sources, UTM campaigns, and countries. Errors: FORBIDDEN.
- Permission
- analytics:view
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
Query parameters
daysintegerNumber of days to aggregate (1 to 90, defaults to 30).
curl -X GET "https://app.kanorio.com/api/v1/sites/{id}/analytics/overview?days=30" \
-H "Authorization: Bearer $KANORIO_TOKEN"/sites/{id}/analytics/pagesanalytics.pages
BetaRead-onlyGet per-page traffic, entry sessions, bounce rate, engagement duration, button clicks, and form submissions (excluding transient checkout pages). Errors: FORBIDDEN.
- Permission
- analytics:view
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
Query parameters
daysintegerNumber of days to aggregate (1 to 90, defaults to 30).
curl -X GET "https://app.kanorio.com/api/v1/sites/{id}/analytics/pages?days=30" \
-H "Authorization: Bearer $KANORIO_TOKEN"/sites/{id}/analytics/botsanalytics.bots
BetaRead-onlyGet AI crawler and search bot activity summary (GPTBot, ClaudeBot, PerplexityBot, Googlebot, etc.) for the selected period. Errors: FORBIDDEN.
- Permission
- analytics:view
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
Query parameters
daysintegerNumber of days to aggregate (1 to 90, defaults to 30).
curl -X GET "https://app.kanorio.com/api/v1/sites/{id}/analytics/bots?days=30" \
-H "Authorization: Bearer $KANORIO_TOKEN"Publishing
/sites/{id}/publishsite.publish
BetaPublish the current draft (all visible pages) so it is live. On first publish you must choose a subdomain (lowercase letters, digits, hyphens; it becomes https://<subdomain>.kanorio.com). Afterwards omit subdomain to keep the current one. Do not use this to change custom domains; use domains.bind. Publishing is rate-limited per token (30/hour). Errors: FORBIDDEN, SUBDOMAIN_MISSING (first publish without subdomain), SUBDOMAIN_TAKEN, RESERVED_SUBDOMAIN, INVALID_SUBDOMAIN, SUBDOMAIN_CHANGE_FORBIDDEN, PLAN_CANNOT_PUBLISH, FREE_VISIBLE_MODULE_LIMIT, FREE_VISIBLE_PAGE_LIMIT, CONTENT_VALIDATION_FAILED (details.issues lists pages/fields to fix), MODERATION_LOCKED, EMPTY_CONTENT, HOSTNAME_CONFLICT.
- Permission
- site:lifecycle
- Rate limit
- 30 per hour
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
curl -X POST "https://app.kanorio.com/api/v1/sites/{id}/publish" \
-H "Authorization: Bearer $KANORIO_TOKEN" \
-H "Content-Type: application/json" \
-d '{"subdomain":"sunny-bakery"}'/sites/{id}/unpublishsite.unpublish
BetaTake the website offline (content and settings are kept; publish again to restore). Only the website owner may do this. Errors: OWNER_REQUIRED, WEBSITE_NOT_FOUND, FORBIDDEN.
- Permission
- site:lifecycle
- Rate limit
- 30 per hour
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
curl -X POST "https://app.kanorio.com/api/v1/sites/{id}/unpublish" \
-H "Authorization: Bearer $KANORIO_TOKEN" \
-H "Content-Type: application/json" \
-d '{}'Domains
/sites/{id}/domainsdomains.list
BetaRead-onlyList the custom domains bound to a website (primary first) with their verification status. Errors: FORBIDDEN, NOT_FOUND.
- Permission
- site:manage_settings
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
curl -X GET "https://app.kanorio.com/api/v1/sites/{id}/domains" \
-H "Authorization: Bearer $KANORIO_TOKEN"/sites/{id}/domainsdomains.bind
BetaSet the complete list of custom domains for a website: the first hostname becomes the primary (canonical) domain, the rest become aliases that 301-redirect to it. Hostnames missing from the list are unbound; pass an empty list to remove all custom domains. After binding, the owner must point DNS (CNAME) at Kanorio; call domains.status to see the exact record and verification progress. Requires a paid plan. Errors: FORBIDDEN, PRO_REQUIRED, INVALID_FORMAT, BLOCKED, HIGH_RISK_TLD, LIMIT_REACHED (details.max), TAKEN (used by another site), READD_COOLDOWN (details.retryAfterSeconds).
- Permission
- site:manage_settings
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
curl -X PUT "https://app.kanorio.com/api/v1/sites/{id}/domains" \
-H "Authorization: Bearer $KANORIO_TOKEN" \
-H "Content-Type: application/json" \
-d '{"hostnames":["www.sunnybakery.example","sunnybakery.example"]}'/sites/{id}/domains/statusdomains.status
BetaRead-onlyRe-check DNS/TLS for every PENDING custom domain right now and return the current list. Domains that are still PENDING include a `diagnoses[hostname]` entry explaining what record is missing (expected vs. observed). Also returns the primary binding. Poll every 15-60 seconds after domains.bind until status is ACTIVE; DNS propagation can take minutes to hours. Errors: FORBIDDEN.
- Permission
- site:manage_settings
- Rate limit
- 120 per minute
Path parameters
idstringRequiredWebsite id. Get it from sites.list or from sites.create.
curl -X GET "https://app.kanorio.com/api/v1/sites/{id}/domains/status" \
-H "Authorization: Bearer $KANORIO_TOKEN"Error codes
{
"error": {
"code": "CONFLICT",
"message": "The resource changed since you read it; re-read it and retry with the new revision marker (updatedAt / contentUpdatedAt).",
"details": {
"updatedAt": "2026-10-06T08:05:12.000Z"
}
}
}| Code | HTTP |
|---|---|
| EMPTY_SLUG | 400 |
| INVALID_BODY | 400 |
| INVALID_EDITED_PATH | 400 |
| INVALID_FORMAT | 400 |
| INVALID_ORDER | 400 |
| INVALID_SUBDOMAIN | 400 |
| UNSUPPORTED_EDITED_PATH | 400 |
| VALIDATION | 400 |
| UNAUTHENTICATED | 401 |
| UNAUTHORIZED | 401 |
| CUSTOM_DOMAIN_CHANGE_FORBIDDEN | 403 |
| CUSTOM_DOMAIN_LIMIT_REACHED | 403 |
| FORBIDDEN | 403 |
| FREE_VISIBLE_MODULE_LIMIT | 403 |
| FREE_VISIBLE_PAGE_LIMIT | 403 |
| LIMIT_REACHED | 403 |
| MODERATION_LOCKED | 403 |
| OWNER_REQUIRED | 403 |
| PLAN_CANNOT_PUBLISH | 403 |
| PRO_REQUIRED | 403 |