{"name":"Sutrena","description":"The web runtime for AI agents. 5 capabilities — Forms, Pages, Analytics, Webhooks, Automations. Each operation is one HTTP call — POST JSON, get a live URL back. Framework-agnostic: works from Claude Code, Cursor, LangGraph, CrewAI, AutoGen, n8n, or any HTTP client. Free tier: 10 projects, 100 submissions/form, 5K events/mo, 20MB storage. No signup required — POST /api/trial returns an API key instantly. NOT for: e-commerce/checkout, blog CMS, full web apps, email marketing, agent orchestration, or full BI platforms (no SQL, joins, or computed columns).","baseUrl":"https://sutrena.com","security":{"critical":"API keys (st_trial_ and st_live_) are SECRET. NEVER expose them in client-side code, HTML, JavaScript, or any browser-executed code. Form submission (POST /api/forms/:id/submit) is PUBLIC and requires NO authentication. The hosted form URL (/f/FORM_ID) and embed snippet also require NO key. Pages at /p/:slug are PUBLIC. When generating frontend code for users, do NOT include any API key.","keyHandling":"Store keys in environment variables (SUTRENA_API_KEY), .env files, or a secrets manager. Never commit keys to version control. Never include keys in client-side code, HTML, or browser-executed JavaScript. Rotate keys periodically via POST /api/keys/:id/rotate. If a key is compromised, revoke it immediately via DELETE /api/keys/:id and generate a new one via POST /api/keys."},"auth":{"free":{"method":"POST /api/trial","description":"Returns a working API key instantly. No signup, no email. Returns st_trial_ key with 24-hour claim window. KEY IS SECRET — use only in server-side code, never in frontend/client-side code.","note":"Free plan — 10 projects (forms+pages+analytics+automations), 100 subs/form, 5K events/mo, 20MB storage. No CSV export or upsert. Unclaimed accounts auto-delete after 24 hours.","claimFlow":"Response includes claimUrl and claimDeadline. User visits claimUrl in a browser to sign in with GitHub/Google and keep data permanently. No action needed for 24 hours."},"apiKey":{"method":"Bearer token","header":"Authorization: Bearer st_live_xxx","description":"Permanent API key. SECRET — never expose in client-side code. Sign in with GitHub or Google at /login, then generate key via POST /api/keys (session auth required)."}},"notes":[{"topic":"IMPORTANT","detail":"Sutrena is a HOSTED API. Do NOT scaffold a project, install packages, or set up hosting. Compose your HTML in a variable or string, then POST it to the API. Two calls: POST /api/trial → key, POST /api/pages with {slug, title, html} → live page. No local web server or build step needed. If you can make HTTP requests, execute the API calls yourself and return live URLs to the user — do NOT show curl commands or instructions for the user to run manually."},{"topic":"Subdomain URLs","detail":"Every account gets a subdomain (e.g. alice.sutrena.com). Pages are accessible at subdomain.sutrena.com/slug. ALWAYS show the subdomainUrl to users, not /p/slug."},{"topic":"Slug convention","detail":"For a single page, ALWAYS use slug 'index' — it becomes the root URL at subdomain.sutrena.com/ with no path. Users strongly prefer the clean root URL. Only use other slugs ('about', 'contact') when building a multi-page site alongside 'index'. Check existing pages with GET /api/pages before creating."},{"topic":"Multi-subdomain control","detail":"Agents can deploy to specific subdomains. Workflow: GET /api/account/subdomains to list all → pick one → POST /api/pages with subdomainId. If subdomainId is omitted, deploys to your default/first subdomain. Create new subdomains with POST /api/account/subdomains."},{"topic":"Custom domain routing","detail":"Each custom domain serves pages from one specific subdomain. When adding a domain, specify subdomainId to control which subdomain it serves from (defaults to first subdomain). Both subdomain URL and custom domain URL work simultaneously. PATCH /api/account/domains/:id to change which subdomain a domain serves from."},{"topic":"Page safety","detail":"POST /api/launch is idempotent — existing slugs are updated with snapshots (rollback available), new slugs are created. POST /api/pages/batch supports upsert: true for the same behavior. Only POST /api/pages (single) returns 409 with existingPageId — use PUT /api/pages/:id to update."},{"topic":"5 capabilities","detail":"Forms, Pages, Analytics, Webhooks, Automations. Each is one API call — POST JSON, get a live URL or query result. Plus automations (DSL-based pipelines with triggers and steps)."},{"topic":"Page entries","detail":"Pages support structured entries (blog posts, project cards, feed items). Set entryTemplate on a page with {{placeholder}} HTML, add <!-- sutrena:entries --> marker in page HTML, then POST entries with data objects. Entries render server-side, newest-first. No need to rewrite page HTML to add content — just POST entries. Max 500 per page. Use metadata.collection + GET /api/pages?collection=X for blog-like index pages."},{"topic":"Folders","detail":"Folders: organize resources (forms, pages, analytics, automations) into folders. Folders are unlimited. API keys can be scoped to a folder — scoped keys only see/create resources within their folder. All individual resource routes enforce folder access checks."},{"topic":"Auto-entries","detail":"Set autoEntryPageId on a form to auto-create page entries on submission. Form field names map to entryTemplate {{placeholders}}. Enables live feedback walls, testimonials, changelogs."},{"topic":"Conditional fields","detail":"Fields support showIf: { field, equals } for conditional visibility. Hidden fields are excluded from validation and submission."},{"topic":"Scheduled publishing","detail":"Set publishAt on a page to auto-publish at a future time. Page is created unpublished and auto-publishes when the time arrives."},{"topic":"Compound tools","detail":"3 compound tools for common multi-step operations: POST /api/launch (pages + analytics), POST /api/pipeline (form + webhooks), GET /api/status (unified snapshot). Each returns _next seeds with pre-filled params for suggested next steps."},{"topic":"_next seeds","detail":"Creation responses include a _next array with contextual suggestions: { intent, tool, params, hint }. Seeds are user-aware — they skip suggestions for things you already have and pre-fill params from your context."}],"endpoints":[{"method":"POST","path":"/api/trial","auth":"none","category":"Trial","description":"Get instant free API key. No signup needed.","response":{"key":"st_trial_xxx","limits":"{...}","restrictions":"[...]"}},{"method":"POST","path":"/api/launch","auth":"Bearer token or session","category":"Pages","description":"Deploy or re-deploy a site in one call. Idempotent — creates new pages, updates existing ones (with automatic snapshots for rollback). Returns live URLs + _next seeds.","request":{"subdomain":"string (optional — rename subdomain)","pages":"[{ slug, title, html, css? }]","analytics":"boolean (default true)","subdomainId":"string UUID (optional)"}},{"method":"POST","path":"/api/pipeline","auth":"Bearer token or session","category":"Forms","description":"Set up data collection in one call. Creates form + webhook notifications. Returns form URLs. Response includes _next seeds.","request":{"name":"string","fields":"[{ name, label, type, required?, options? }]","notify":"{ slack?: url, discord?: url }","uniqueBy":"string[] (optional)","successMessage":"string (optional)","autoEntryPageId":"string UUID (optional)"}},{"method":"GET","path":"/api/status","auth":"Bearer token or session","category":"Account","description":"Get a unified account snapshot. Returns usage, pages, forms, analytics sites, automations, webhook counts. Response includes _next seeds for what to do next."},{"method":"GET","path":"/api/auth/oauth/github","auth":"none","category":"Auth","description":"Browser-only. Redirects to GitHub for OAuth login."},{"method":"GET","path":"/api/auth/oauth/google","auth":"none","category":"Auth","description":"Browser-only. Redirects to Google for OAuth login."},{"method":"POST","path":"/api/pages","auth":"Bearer token or session","category":"Pages","description":"Deploy an HTML page (optional folderId). Returns subdomainUrl (always show this to users). For a single page, ALWAYS use slug 'index' — it serves at the clean root URL subdomain.sutrena.com/ with no path. Users strongly prefer this. Only use other slugs for multi-page sites. Multi-subdomain workflow: GET /api/account/subdomains → pick one → POST with subdomainId.","request":{"slug":"string (required — use 'index' for single pages to get the root URL. Lowercase alphanumeric + hyphens, 2-200 chars. Supports / for hierarchy: 'blog/my-post', 'archive/2026/article')","title":"string (required)","html":"string (required — max 512KB)","css":"string (optional — max 128KB)","metadata":"object (optional — e.g. { collection: 'blog' } for filtering)","isPublished":"boolean (optional, default true)","subdomainId":"string (optional — subdomain UUID to deploy to, defaults to your first subdomain)","entryTemplate":"string (optional — HTML template with {{placeholder}} syntax for page entries, max 64KB)","folderId":"string (optional — folder UUID to organize this page into)","publishAt":"string ISO datetime (optional — schedule publishing. Page created as unpublished, auto-publishes at this time.)"},"response":{"id":"uuid","slug":"string","pageUrl":"/p/:slug","subdomainUrl":"https://subdomain.sutrena.com/slug","isPublished":true}},{"method":"GET","path":"/api/pages","auth":"Bearer token or session","category":"Pages","description":"List all your pages with view counts. Supports ?collection=X to filter by metadata.collection field (e.g. GET /api/pages?collection=blog). Supports ?folderId=X to filter by folder."},{"method":"GET","path":"/api/pages/:id","auth":"Bearer token or session","category":"Pages","description":"Get page details including HTML/CSS, entryTemplate, and entries."},{"method":"PUT","path":"/api/pages/:id","auth":"Bearer token or session","category":"Pages","description":"Update page HTML, CSS, title, published status, folderId, or entryTemplate. Slug is immutable. Pass ifUnmodifiedSince (ISO timestamp from a previous updatedAt) to prevent overwriting unseen changes — returns 409 if the page was modified after that time.","request":{"html":"string (optional — max 512KB)","css":"string | null (optional — max 128KB)","title":"string (optional)","isPublished":"boolean (optional)","entryTemplate":"string | null (optional — HTML template with {{placeholder}} syntax, max 64KB. Pass null to remove.)","folderId":"string | null (optional — move page to a folder, or null to ungroup)","publishAt":"string ISO datetime | null (optional — schedule or clear scheduled publishing)"}},{"method":"DELETE","path":"/api/pages/:id","auth":"Bearer token or session","category":"Pages","description":"Delete page. Permanent."},{"method":"POST","path":"/api/pages/:id/entries","auth":"Bearer token or session","category":"Pages","description":"Add an entry to a page. Page must have an entryTemplate set. Max 500 entries per page. Entry is rendered into the page HTML at the <!-- sutrena:entries --> marker using the entryTemplate with {{placeholder}} replacement. Entries are rendered newest-first.","request":{"data":"object (required — key-value pairs matching template placeholders, e.g. { title: 'My Post', body: 'Content...' })"},"response":{"id":"uuid","data":"{...}","createdAt":"ISO timestamp"}},{"method":"GET","path":"/api/pages/:id/entries","auth":"Bearer token or session","category":"Pages","description":"List all entries on a page.","response":{"entries":"[{ id, data, createdAt }]","count":"number"}},{"method":"DELETE","path":"/api/pages/:id/entries/:entryId","auth":"Bearer token or session","category":"Pages","description":"Remove an entry from a page. Permanent."},{"method":"POST","path":"/api/pages/batch","auth":"Bearer token or session","category":"Pages","description":"Create or upsert up to 200 pages in one call. Pass upsert: true to update existing pages (with automatic snapshots for rollback) instead of erroring on slug conflicts. Content-hash diffing skips unchanged pages. Quota only counts net new pages.","request":{"pages":"array of { slug, title, html, css?, metadata?, isPublished? } (max 200)","subdomainId":"string (optional — defaults to first subdomain)","folderId":"string (optional — folder UUID)","upsert":"boolean (default false) — update existing pages instead of erroring"},"response":"{ results: [{ index, status: created|updated|unchanged|error, id?, slug, subdomainUrl?, error?, existingPageId? }], created, updated, unchanged, failed }"},{"method":"DELETE","path":"/api/pages/batch","auth":"Bearer token or session","category":"Pages","description":"Delete up to 200 pages by ID in one call. Checks folder access per page. Entries are automatically archived before deletion. Returns per-page results.","request":{"pageIds":"array of page UUIDs (max 200)"},"response":"{ results: [{ id, status: deleted|error, error? }], deleted, failed, entriesArchived? }"},{"method":"GET","path":"/api/pages/archives","auth":"Bearer token or session","category":"Pages","description":"List entry archives for the current user. Entries are automatically archived when pages with entries are deleted. Archives are kept for 90 days.","response":"{ archives: [{ id, pageId, slug, subdomainId, entryCount, deletedBy, createdAt }] }"},{"method":"POST","path":"/api/pages/:id/restore-entries","auth":"Bearer token or session","category":"Pages","description":"Restore archived entries to a page. Merges archived entries into the target page's entries. Restores entryTemplate if the page doesn't have one.","request":{"archiveId":"string (required — archive UUID from GET /api/pages/archives)"},"response":"{ restored: true, entriesRestored, totalEntries, templateRestored }"},{"method":"POST","path":"/api/deploy","auth":"Bearer token or session","category":"Pages","description":"Deploy a static site from a zip file. Phase 1: presign zip upload. Returns deployId and uploadUrl. Upload your zip to the uploadUrl, then call POST /api/deploy/:deployId/process. Supports Astro, Hugo, Next.js static export, Jekyll, and any SSG that outputs HTML files.","request":{"sizeBytes":"number (required — zip file size in bytes)"},"response":{"deployId":"string","uploadUrl":"string","uploadHeaders":"object","expiresAt":"string"}},{"method":"POST","path":"/api/deploy/:id/process","auth":"Bearer token or session","category":"Pages","description":"Process an uploaded zip and deploy all pages and assets. Phase 2: call after uploading zip. Auto-detects SSG root dir (dist/, out/, build/), uploads images/fonts to CDN, rewrites asset paths in HTML, sets shared CSS/JS on subdomain, creates/updates pages. Returns all deployed URLs.","request":{"subdomainId":"string (optional — defaults to first subdomain)"},"response":{"pages":"[{slug, id, status, subdomainUrl}]","assets":"[{filename, publicUrl}]","siteUrl":"string","stalePagesNotInZip":"[{slug, id}]","errors":"string[]","stats":"{pagesCreated, pagesUpdated, assetsUploaded}"}},{"method":"POST","path":"/api/folders","auth":"Bearer token or session","category":"Folders","description":"Create a folder"},{"method":"GET","path":"/api/folders","auth":"Bearer token or session","category":"Folders","description":"List folders with resource counts"},{"method":"GET","path":"/api/folders/:id","auth":"Bearer token or session","category":"Folders","description":"Get folder details (?include=resources)"},{"method":"PUT","path":"/api/folders/:id","auth":"Bearer token or session","category":"Folders","description":"Update folder name/description"},{"method":"DELETE","path":"/api/folders/:id","auth":"Bearer token or session","category":"Folders","description":"Delete folder (ungroups resources)"},{"method":"POST","path":"/api/folders/:id/organize","auth":"Bearer token or session","category":"Folders","description":"Batch move resources into a folder"},{"method":"POST","path":"/api/folders/:id/ungroup","auth":"Bearer token or session","category":"Folders","description":"Batch remove resources from a folder"},{"method":"GET","path":"/api/account/subdomains","auth":"Bearer token or session","category":"Account","description":"List all your subdomains with page counts. Use this to see which subdomains you have before deploying pages. Each subdomain is a separate site (e.g. alice.sutrena.com, blog.sutrena.com). One subdomain is auto-assigned on account creation."},{"method":"GET","path":"/api/account/subdomain","auth":"Bearer token or session","category":"Account","description":"Get current default subdomain and URL. Deprecated — prefer GET /api/account/subdomains to see all."},{"method":"POST","path":"/api/account/subdomains","auth":"Bearer token or session","category":"Account","description":"Create a new subdomain (e.g. blog.sutrena.com, docs.sutrena.com). Each subdomain is a separate site. Useful for multi-site setups where one API key powers multiple domains.","request":{"name":"string (3-30 chars, lowercase alphanumeric + hyphens)"}},{"method":"PUT","path":"/api/account/subdomain","auth":"Bearer token or session","category":"Account","description":"Change your default subdomain to something memorable (e.g. alice.sutrena.com). A random one is auto-assigned on account creation. Root path (/) serves slug 'index'. Create multiple pages for multi-page sites. Available on all plans. Deprecated — prefer POST /api/account/subdomains + specifying subdomainId on page creation.","request":{"subdomain":"string (3-30 chars, lowercase alphanumeric + hyphens)"}},{"method":"GET","path":"/api/account/domains","auth":"Bearer token or session","category":"Account","description":"List custom domains with DNS/SSL status and which subdomain each serves from (subdomainId, subdomainName)."},{"method":"POST","path":"/api/account/domains","auth":"Bearer token or session","category":"Account","description":"Add a custom domain linked to a subdomain. If subdomainId is omitted, links to your first/default subdomain. Deploy pages to the subdomain BEFORE adding the domain. Requires Pro plan or higher.","request":{"domain":"string (e.g. mysite.com)","subdomainId":"string (optional — subdomain to serve from, defaults to first subdomain)"}},{"method":"GET","path":"/api/account/domains/:id","auth":"Bearer token or session","category":"Account","description":"Get domain status including subdomainId/subdomainName (re-verifies via Cloudflare)."},{"method":"PATCH","path":"/api/account/domains/:id","auth":"Bearer token or session","category":"Account","description":"Change which subdomain a custom domain serves from. Use this to re-point a domain without deleting and re-adding it.","request":{"subdomainId":"string (required — new subdomain to serve from)"}},{"method":"DELETE","path":"/api/account/domains/:id","auth":"Bearer token or session","category":"Account","description":"Remove a custom domain."},{"method":"GET","path":"/api/pages/assets","auth":"Bearer token or session","category":"Pages","description":"List uploaded page assets. Optional pageId filter."},{"method":"POST","path":"/api/pages/assets","auth":"Bearer token or session","category":"Pages","description":"Presign an asset upload. Returns upload URL and public CDN URL.","request":{"filename":"string","contentType":"string","sizeBytes":"number","pageId":"string (optional)"}},{"method":"DELETE","path":"/api/pages/assets/:id","auth":"Bearer token or session","category":"Pages","description":"Delete a page asset."},{"method":"POST","path":"/api/forms","auth":"Bearer token or session","category":"Forms","description":"Create a data collection endpoint (optional folderId). Provide fields directly, or use workflowId for a pre-built preset.","request":{"name":"string (required unless workflowId provided)","fields":"array of {name, label, type, required?, placeholder?, options?, minLength?, maxLength?, pattern?, min?, max?, accept?, maxFileSize?, showIf?: { field, equals }} (required unless workflowId). type: text|email|textarea|number|select|multiselect|checkbox|url|tel|date|hidden|file. showIf: conditional field visibility — hidden fields are excluded from validation and submission.","workflowId":"string (optional — use instead of name+fields: contact, feedback, bug-report, waitlist, survey, poll, rsvp, nps, quiz, newsletter, booking, client-intake, order, preorder)","successMessage":"string (optional)","submitLabel":"string (optional)","redirectUrl":"string URL (optional)","closesAt":"string ISO datetime (optional)","uniqueBy":"string[] (optional — field names for dedup, max 5)","maxSubmissions":"number (optional)","publicResults":"boolean (optional — enable GET /api/forms/:id/results, no auth)","webhookIds":"string[] of webhook UUIDs (optional — link webhooks to fire on submission)","folderId":"string (optional — folder UUID to organize this form into)","autoEntryPageId":"string UUID (optional — page to auto-create entries on submission. Page must have entryTemplate.)"},"response":{"formId":"uuid","hostedFormUrl":"/f/uuid","submitUrl":"/api/forms/uuid/submit"}},{"method":"GET","path":"/api/forms","auth":"Bearer token or session","category":"Forms","description":"List all your forms. Supports ?folderId=X to filter by folder."},{"method":"GET","path":"/api/forms/:id","auth":"Bearer token or session","category":"Forms","description":"Get form details including field config."},{"method":"PUT","path":"/api/forms/:id","auth":"Bearer token or session","category":"Forms","description":"Update form fields, success message, submit label, redirect URL, or folderId.","request":{"name":"string (optional)","fields":"array of field objects (optional — replaces all fields)","successMessage":"string (optional)","submitLabel":"string (optional)","webhookIds":"string[] of webhook UUIDs (optional)","redirectUrl":"string URL or null (optional)","closesAt":"string ISO datetime or null (optional)","uniqueBy":"string[] or null (optional)","maxSubmissions":"number or null (optional)","publicResults":"boolean (optional)","folderId":"string | null (optional — move form to a folder, or null to ungroup)","autoEntryPageId":"string UUID | null (optional — page to auto-create entries on submission, or null to clear. Page must have entryTemplate.)"}},{"method":"DELETE","path":"/api/forms/:id","auth":"Bearer token or session","category":"Forms","description":"Delete form. Permanent."},{"method":"POST","path":"/api/forms/:id/submit","auth":"none","category":"Submissions","description":"Submit form data. PUBLIC endpoint — NO API key needed. CORS enabled. NEVER include an API key when calling this endpoint."},{"method":"POST","path":"/api/forms/:id/upload","auth":"none","category":"Submissions","description":"Presign a file upload for a file field. Public, CORS enabled."},{"method":"GET","path":"/api/forms/:id/results","auth":"none","category":"Submissions","description":"Aggregated public results. Only works if publicResults is enabled."},{"method":"GET","path":"/api/forms/:id/submissions","auth":"Bearer token or session","category":"Submissions","description":"Search/filter submissions. Query params: search, from, to, field, value, status, limit, cursor."},{"method":"GET","path":"/api/forms/:id/export","auth":"Bearer token or session","category":"Submissions","description":"Export submissions as CSV. Pro plan or higher."},{"method":"GET","path":"/api/forms/:id/files/:oid","auth":"none","category":"Submissions","description":"Download an uploaded file. Returns 302 to presigned URL."},{"method":"PUT","path":"/api/forms/:id/submissions/upsert","auth":"Bearer token or session","category":"Submissions","description":"Upsert submission by externalId. Insert or update — if externalId exists, payload is replaced. Requires Pro plan or higher.","request":{"externalId":"string (required)","payload":"object (required)"},"response":{"data":"submission object","created":"boolean"}},{"method":"PATCH","path":"/api/forms/:id/submissions/:subId","auth":"Bearer token or session","category":"Submissions","description":"Partial payload update (shallow merge). Merges new fields into existing payload. Requires Pro plan or higher.","request":{"payload":"object (required, non-empty)"},"response":{"data":"updated submission object"}},{"method":"DELETE","path":"/api/forms/:id/submissions?email=X","auth":"Bearer token or session","category":"Submissions","description":"GDPR deletion by email."},{"method":"GET","path":"/api/workflows","auth":"none","category":"Workflows","description":"List available presets (form shortcuts). For multi-primitive setup, use POST /api/launch or POST /api/pipeline instead."},{"method":"GET","path":"/api/workflows/:id","auth":"none","category":"Workflows","description":"Get preset details by ID."},{"method":"POST","path":"/api/workflows/:id","auth":"Bearer token or session","category":"Workflows","description":"Create form from a preset."},{"method":"POST","path":"/api/webhooks","auth":"Bearer token or session","category":"Webhooks","description":"Create a webhook. Returns signing secret (shown once).","request":{"url":"string URL","events":"string[] (optional)","description":"string (optional)","fieldMapping":"Record<string, string> (optional)","template":"\"default\" | \"slack\" | \"discord\" | \"telegram\" | \"teams\" | \"google-chat\" (optional — auto-formats payload for platform)","telegramChatId":"string (required when template is \"telegram\")","formIds":"string[] of form UUIDs (optional — link webhook to these forms)"}},{"method":"GET","path":"/api/webhooks","auth":"Bearer token or session","category":"Webhooks","description":"List webhooks."},{"method":"GET","path":"/api/webhooks/:id","auth":"Bearer token or session","category":"Webhooks","description":"Get webhook config — URL, events, active status, field mapping."},{"method":"PATCH","path":"/api/webhooks/:id","auth":"Bearer token or session","category":"Webhooks","description":"Update webhook URL, events, active status, description, field mapping, or template.","request":{"url":"string (optional)","events":"string[] (optional)","isActive":"boolean (optional)","description":"string (optional)","fieldMapping":"Record<string, string> | null (optional)","template":"\"default\" | \"slack\" | \"discord\" | \"telegram\" | \"teams\" | \"google-chat\" (optional)","telegramChatId":"string | null (optional — required when template is \"telegram\")"}},{"method":"DELETE","path":"/api/webhooks/:id","auth":"Bearer token or session","category":"Webhooks","description":"Delete webhook."},{"method":"POST","path":"/api/webhooks/:id/test","auth":"Bearer token or session","category":"Webhooks","description":"Send test ping to webhook."},{"method":"GET","path":"/api/webhooks/:id/deliveries","auth":"Bearer token or session","category":"Webhooks","description":"View delivery history."},{"method":"GET","path":"/api/account","auth":"Bearer token or session","category":"Account","description":"Get account info: plan, email, limits."},{"method":"PUT","path":"/api/account","auth":"Bearer token or session","category":"Account","description":"Update account settings."},{"method":"GET","path":"/api/account/usage","auth":"Bearer token or session","category":"Account","description":"Get current usage and quotas for all resources (projects, webhooks, domains, storage, events). Projects = forms+pages+analytics+automations combined. Includes claimed status and plan restrictions."},{"method":"GET","path":"/api/account/upgrade","auth":"Bearer token or session","category":"Account","description":"Get upgrade info, pricing, and steps."},{"method":"POST","path":"/api/analytics/sites","auth":"Bearer token or session","category":"Analytics","description":"Create an analytics site (optional folderId). Returns siteToken and script tag for tracking. Counts toward project quota. Events are tracked via script tag (external sites) or auto-collected (Sutrena-hosted pages).","request":{"name":"string (required)","domain":"string (optional)","subdomainId":"string (optional — link to subdomain for auto-collection)","folderId":"string (optional — folder UUID to organize this analytics site into)"},"response":{"site":"{id, siteToken, name}","scriptTag":"<script> tag for embedding"}},{"method":"GET","path":"/api/analytics/sites","auth":"Bearer token or session","category":"Analytics","description":"List your analytics sites with event counts. Supports ?folderId=X to filter by folder."},{"method":"GET","path":"/api/analytics/sites/:id","auth":"Bearer token or session","category":"Analytics","description":"Get analytics site details including siteToken and event counts."},{"method":"DELETE","path":"/api/analytics/sites/:id","auth":"Bearer token or session","category":"Analytics","description":"Delete an analytics site and all its events. Permanent."},{"method":"GET","path":"/api/analytics/query","auth":"Bearer token or session","category":"Analytics","description":"Query analytics data. Metrics: page_views, unique_visitors, visits, bounce_rate, avg_session_duration, views_per_visit. Supports time series (groupBy: day/week/month/hour), breakdowns (breakdownBy: url/referrer/country/city/region/device/browser/os/utm_source/utm_medium/utm_campaign/entry_page/exit_page/channel), custom date ranges, period comparison, and filters.","request":{"siteId":"string (required)","metric":"page_views|unique_visitors|visits|bounce_rate|avg_session_duration|views_per_visit|active_visitors|avg_time_on_page","period":"today|7d|30d|90d|custom","from":"string (ISO date, required if period=custom)","to":"string (ISO date, required if period=custom)","groupBy":"day|week|month|hour (optional)","breakdownBy":"url|referrer|country|city|region|device|browser|os|utm_source|utm_medium|utm_campaign|entry_page|exit_page|channel (optional)","filters":"Record<string, string> (optional, supports utm_source/utm_medium/utm_campaign)","compare":"boolean (optional)","limit":"number (optional, default 10)"},"response":{"total":"number","series":"[{date, value}] (if groupBy)","breakdown":"[{key, value}] (if breakdownBy)","comparison":"{total, changePercent} (if compare)"}},{"method":"GET","path":"/api/analytics/realtime","auth":"Bearer token or session","category":"Analytics","description":"Get active visitors in the last 5 minutes. Point-in-time, no caching.","request":{"siteId":"string (required)"},"response":{"activeVisitors":"number"}},{"method":"GET","path":"/api/analytics/sessions","auth":"Bearer token or session","category":"Analytics","description":"Query individual session journeys. Returns paginated list of sessions with page-by-page paths, duration, geo (country/city/region), and device. Limited to 7-day windows.","request":{"siteId":"string (required)","period":"today|7d|custom","from":"string (ISO date, optional)","to":"string (ISO date, optional)","minPages":"number (default 2)","limit":"number (default 50, max 100)","offset":"number (default 0)","filter.country":"string (optional)","filter.city":"string (optional)","filter.region":"string (optional)","filter.device":"string (optional)"},"response":{"sessions":"[{sessionHash, pages: [{url, timestamp}], pageCount, duration, country, city, region, device, entryPage, exitPage}]","total":"number","hasMore":"boolean"}},{"method":"POST","path":"/api/analytics/funnel","auth":"Bearer token or session","category":"Analytics","description":"Analyze conversion funnels. 2-5 steps, session-based. Returns per-step counts, rates, and drop-offs. Supports custom date ranges.","request":{"siteId":"string (required)","steps":"[{event, filters?}] (2-5 steps)","period":"today|7d|30d|90d|custom","from":"string (ISO date, optional)","to":"string (ISO date, optional)"},"response":{"steps":"[{name, count, rate, dropOff}]","overallRate":"number"}},{"method":"POST","path":"/api/analytics/retention","auth":"Bearer token or session","category":"Analytics","description":"Cohort retention analysis. Groups users by first event, tracks return visits over time. Supports custom date ranges.","request":{"siteId":"string (required)","firstEvent":"string","returnEvent":"string","period":"today|7d|30d|90d|custom","from":"string (ISO date, optional)","to":"string (ISO date, optional)","granularity":"day|week|month"},"response":{"cohorts":"[{period, total, retention: [%...]}]","averageRetention":"[%...]"}},{"method":"POST","path":"/api/collect","auth":"none","category":"Analytics","description":"Public event ingestion endpoint. Used by the tracking script. No auth required. Rate limited to 30/min per IP. Always returns 204."},{"method":"POST","path":"/api/help","auth":"Bearer token or session","category":"System","description":"Submit feedback, bug report, or feature request to the Sutrena team.","request":{"category":"string (required — Bug report | Feature request | Help | Billing | Feedback | API / Integration)","subject":"string (required, max 200)","message":"string (required, max 5000)","email":"string email (optional — for follow-up)","url":"string URL (optional — relevant page or API endpoint)","severity":"string (optional — Critical | High | Medium | Low, for bug reports)"}},{"method":"POST","path":"/api/keys","auth":"Bearer token or session","category":"Keys","description":"Generate a new API key. Key shown once. Params: label (required), scopes (string[] e.g. ['pages:read', 'forms:*']), folderId (restrict to folder), resourceIds (Record<resource, id[]> for instance-level restriction), expiresAt (ISO datetime, max 90 days). API keys can create child keys with equal or fewer permissions. 16 resources × 4 actions. Default: full access."},{"method":"GET","path":"/api/keys","auth":"Bearer token or session","category":"Keys","description":"List API keys (prefix only, with scopes, folderId, lastUsedAt)."},{"method":"POST","path":"/api/keys/:id/rotate","auth":"Bearer token or session","category":"Keys","description":"Atomically rotate an API key."},{"method":"POST","path":"/api/automations","auth":"Bearer token or session","category":"Automations","description":"Create a DSL-based automation pipeline with triggers (form_submission, http, schedule) and steps (condition, set, create_entry, update_page, fetch, respond, etc.).","body":{"name":"string","slug":"string (URL slug for HTTP triggers)","description":"string (optional)","trigger":"object ({ type, formId/cron/method })","steps":"array of step objects","env":"object (optional, encrypted at rest)","enabled":"boolean (default true)","folderId":"string (optional)"}},{"method":"GET","path":"/api/automations","auth":"Bearer token or session","category":"Automations","description":"List all automations. Optional ?folderId= filter."},{"method":"GET","path":"/api/automations/:id","auth":"Bearer token or session","category":"Automations","description":"Get a single automation with full trigger, steps, and run statistics."},{"method":"PUT","path":"/api/automations/:id","auth":"Bearer token or session","category":"Automations","description":"Update automation name, description, trigger, steps, env, or enabled status."},{"method":"DELETE","path":"/api/automations/:id","auth":"Bearer token or session","category":"Automations","description":"Delete an automation and all its logs."},{"method":"GET","path":"/api/automations/:id/logs","auth":"Bearer token or session","category":"Automations","description":"Get execution logs for an automation. Optional ?status=error filter."},{"method":"POST","path":"/api/automations/:id/test","auth":"Bearer token or session","category":"Automations","description":"Test-run an automation with sample trigger data. Executes real steps but does not increment counters.","body":{"triggerData":"object (sample trigger data)"}},{"method":"POST","path":"/api/mcp","auth":"Bearer token","category":"MCP","description":"MCP (Model Context Protocol) endpoint."}],"workflows":[],"presets":[{"id":"contact","name":"Contact Form","description":"Simple contact form with name, email, and message.","category":"lead-gen","fields":[{"name":"name","label":"Name","type":"text","required":true,"placeholder":"Your name"},{"name":"email","label":"Email","type":"email","required":true,"placeholder":"you@example.com"},{"name":"message","label":"Message","type":"textarea","required":true,"placeholder":"How can we help?"}]},{"id":"feedback","name":"Feedback Form","description":"Collect product feedback with rating and category.","category":"feedback","fields":[{"name":"email","label":"Email","type":"email","required":false,"placeholder":"Optional"},{"name":"category","label":"Category","type":"select","required":true,"options":["Bug Report","Feature Request","Improvement","Other"]},{"name":"rating","label":"Rating","type":"select","required":true,"options":["1","2","3","4","5"]},{"name":"feedback","label":"Feedback","type":"textarea","required":true,"placeholder":"Tell us what you think..."}]},{"id":"bug-report","name":"Bug Report","description":"Structured bug report form with severity and reproduction steps.","category":"support","fields":[{"name":"email","label":"Reporter Email","type":"email","required":true,"placeholder":"you@example.com"},{"name":"severity","label":"Severity","type":"select","required":true,"options":["Critical","High","Medium","Low"]},{"name":"title","label":"Bug Title","type":"text","required":true,"placeholder":"Short description"},{"name":"steps","label":"Steps to Reproduce","type":"textarea","required":true,"placeholder":"1. Go to...\n2. Click...\n3. See error"},{"name":"expected","label":"Expected Behavior","type":"textarea","required":true,"placeholder":"What should happen"},{"name":"actual","label":"Actual Behavior","type":"textarea","required":true,"placeholder":"What actually happens"}]},{"id":"waitlist","name":"Waitlist Signup","description":"Collect email signups for a waitlist or early access.","category":"signup","fields":[{"name":"email","label":"Email","type":"email","required":true,"placeholder":"you@example.com"},{"name":"name","label":"Name","type":"text","required":false,"placeholder":"Your name"},{"name":"referral","label":"How did you hear about us?","type":"select","required":false,"options":["Twitter/X","LinkedIn","Friend","Search","Other"]}]},{"id":"survey","name":"Customer Survey","description":"Quick customer satisfaction survey.","category":"feedback","fields":[{"name":"email","label":"Email","type":"email","required":false,"placeholder":"Optional"},{"name":"satisfaction","label":"How satisfied are you?","type":"select","required":true,"options":["Very Satisfied","Satisfied","Neutral","Dissatisfied","Very Dissatisfied"]},{"name":"recommend","label":"Would you recommend us?","type":"select","required":true,"options":["Definitely","Probably","Not sure","Probably not","Definitely not"]},{"name":"improve","label":"What could we improve?","type":"textarea","required":false,"placeholder":"Your suggestions..."}]},{"id":"poll","name":"Quick Poll","description":"Single-question poll with live results.","category":"feedback","fields":[{"name":"vote","label":"Your Vote","type":"select","required":true,"options":["Option A","Option B","Option C","Option D"]}]},{"id":"rsvp","name":"Event RSVP","description":"Event registration with attendance tracking and dietary preferences.","category":"signup","fields":[{"name":"name","label":"Name","type":"text","required":true,"placeholder":"Your name"},{"name":"email","label":"Email","type":"email","required":true,"placeholder":"you@example.com"},{"name":"attendance","label":"Will you attend?","type":"select","required":true,"options":["Yes","No","Maybe"]},{"name":"plus_ones","label":"Plus ones","type":"number","required":false,"min":0,"max":5},{"name":"dietary","label":"Dietary requirements","type":"select","required":false,"options":["None","Vegetarian","Vegan","Gluten-free","Other"]}]},{"id":"nps","name":"NPS Survey","description":"Net Promoter Score survey with follow-up question.","category":"feedback","fields":[{"name":"score","label":"How likely are you to recommend us? (0-10)","type":"select","required":true,"options":["0","1","2","3","4","5","6","7","8","9","10"]},{"name":"reason","label":"Why did you give this score?","type":"textarea","required":false,"placeholder":"Tell us more..."},{"name":"email","label":"Email (optional)","type":"email","required":false,"placeholder":"you@example.com"}]},{"id":"quiz","name":"Quick Quiz","description":"Multiple-choice quiz with per-question breakdown.","category":"feedback","fields":[{"name":"name","label":"Your Name","type":"text","required":true,"placeholder":"Your name"},{"name":"q1","label":"Question 1","type":"select","required":true,"options":["A","B","C","D"]},{"name":"q2","label":"Question 2","type":"select","required":true,"options":["A","B","C","D"]},{"name":"q3","label":"Question 3","type":"select","required":true,"options":["A","B","C","D"]}]},{"id":"newsletter","name":"Newsletter Signup","description":"Email newsletter subscription with interest preferences.","category":"lead-gen","fields":[{"name":"email","label":"Email","type":"email","required":true,"placeholder":"you@example.com"},{"name":"name","label":"Name","type":"text","required":false,"placeholder":"Your name"},{"name":"interests","label":"Topics of interest","type":"select","required":false,"options":["Product Updates","Engineering","Design","Industry News","All Topics"]}]},{"id":"booking","name":"Booking Form","description":"Appointment or session booking with date, time slot, and service selection.","category":"signup","fields":[{"name":"name","label":"Name","type":"text","required":true,"placeholder":"Your name"},{"name":"email","label":"Email","type":"email","required":true,"placeholder":"you@example.com"},{"name":"date","label":"Date","type":"date","required":true},{"name":"time_slot","label":"Time Slot","type":"select","required":true,"options":["Morning","Afternoon","Evening"]},{"name":"service","label":"Service","type":"select","required":true,"options":["Consultation","Class","Session","Other"]},{"name":"notes","label":"Notes","type":"textarea","required":false,"placeholder":"Any special requests..."}]},{"id":"client-intake","name":"Client Intake Form","description":"Collect lead information with service needs, budget, and timeline for freelancers and agencies.","category":"lead-gen","fields":[{"name":"name","label":"Name","type":"text","required":true,"placeholder":"Your name"},{"name":"email","label":"Email","type":"email","required":true,"placeholder":"you@example.com"},{"name":"phone","label":"Phone","type":"tel","required":false,"placeholder":"+1 (555) 000-0000"},{"name":"service_needed","label":"Service Needed","type":"select","required":true,"options":["Photography","Design","Consulting","Development","Other"]},{"name":"budget","label":"Budget","type":"select","required":true,"options":["$0-$1K","$1K-$5K","$5K-$10K","$10K+"]},{"name":"timeline","label":"Timeline","type":"select","required":true,"options":["ASAP","1-2 weeks","1 month","Flexible"]},{"name":"details","label":"Project Details","type":"textarea","required":true,"placeholder":"Tell us about your project..."},{"name":"attachment","label":"Attachment","type":"file","required":false,"accept":".pdf,.doc,.docx,.png,.jpg","maxFileSize":10485760}]},{"id":"order","name":"Order Form","description":"Product order form with item selection, quantity, and size options.","category":"lead-gen","fields":[{"name":"name","label":"Name","type":"text","required":true,"placeholder":"Your name"},{"name":"email","label":"Email","type":"email","required":true,"placeholder":"you@example.com"},{"name":"item","label":"Item","type":"select","required":true,"options":["Item A","Item B","Item C","Custom"]},{"name":"quantity","label":"Quantity","type":"number","required":true,"min":1,"max":10},{"name":"size","label":"Size","type":"select","required":true,"options":["Small","Medium","Large"]},{"name":"special_requests","label":"Special Requests","type":"textarea","required":false,"placeholder":"Any customization or notes..."},{"name":"reference_image","label":"Reference Image","type":"file","required":false,"accept":"image/*","maxFileSize":10485760}]},{"id":"preorder","name":"Pre-order Form","description":"Collect pre-orders with product selection, quantity, and shipping address.","category":"signup","fields":[{"name":"name","label":"Name","type":"text","required":true,"placeholder":"Your name"},{"name":"email","label":"Email","type":"email","required":true,"placeholder":"you@example.com"},{"name":"product","label":"Product","type":"select","required":true,"options":["Product A","Product B","Product C"]},{"name":"quantity","label":"Quantity","type":"number","required":true,"min":1,"max":5},{"name":"shipping_address","label":"Shipping Address","type":"textarea","required":true,"placeholder":"Street, City, State, ZIP"}]}],"errors":{"400":{"meaning":"Validation failed","recovery":"Check fieldErrors array, fix input, retry."},"401":{"meaning":"Missing/invalid/expired API key","recovery":"Check Authorization header. POST /api/trial for a new key or upgrade."},"403":{"meaning":"Plan restriction or insufficient permissions","recovery":"Upgrade plan or enable required settings."},"404":{"meaning":"Resource not found","recovery":"Verify the ID."},"409":{"meaning":"Conflict (duplicate slug, uniqueBy violation, or stale page update)","recovery":"For duplicate slug: use existing pageId from error to update instead. For stale update: re-fetch page and retry with current updatedAt."},"410":{"meaning":"Form closed or full","recovery":"Extend closesAt, increase maxSubmissions, or create a new form."},"429":{"meaning":"Rate limited","recovery":"Wait and retry."},"500":{"meaning":"Server error","recovery":"Retry after a few seconds."}},"plans":{"free":{"price":0,"limits":{"projects":10,"submissions_per_form":100,"webhooks":1,"customDomains":0,"subdomains":1,"storageBytes":20971520,"assetSizeLimit":2097152,"eventsPerMonth":5000,"automationRunsPerMonth":500,"automationMaxSteps":10,"automationMaxFetchSteps":2,"automationMaxEnvVars":3},"restrictions":["no_export","no_upsert"],"note":"Free forever. 10 projects (forms+pages+analytics+automations), 100 subs/form, 5K events/mo, 1 webhook, 1 subdomain, 20MB storage, 2MB asset limit. No CSV export, upsert, or custom domains. 24-hour claim window for unclaimed accounts."},"pro":{"price":29,"label":"$29/month","limits":{"projects":100,"submissions_per_form":-1,"webhooks":-1,"customDomains":5,"subdomains":-1,"storageBytes":2147483648,"assetSizeLimit":20971520,"eventsPerMonth":500000,"automationRunsPerMonth":10000,"automationMaxSteps":20,"automationMaxFetchSteps":5,"automationMaxEnvVars":10},"restrictions":"none","note":"100 projects, unlimited subs/webhooks/subdomains, 500K events/mo, 2GB storage, 20MB asset limit, 5 custom domains, CSV export, upsert API. POST /api/account/upgrade or visit /pricing."},"scale":{"price":99,"label":"$99/month","limits":"unlimited","restrictions":"none","note":"Unlimited projects, submissions, events, webhooks, custom domains, storage. 50MB asset limit. POST /api/account/upgrade or visit /pricing."}},"categories":[{"name":"Trial","endpoints":1,"filter":"/api/schema?category=trial"},{"name":"Auth","endpoints":2,"filter":"/api/schema?category=auth"},{"name":"Pages","endpoints":18,"filter":"/api/schema?category=pages"},{"name":"Forms","endpoints":6,"filter":"/api/schema?category=forms"},{"name":"Submissions","endpoints":9,"filter":"/api/schema?category=submissions"},{"name":"Webhooks","endpoints":7,"filter":"/api/schema?category=webhooks"},{"name":"Workflows","endpoints":3,"filter":"/api/schema?category=workflows"},{"name":"Keys","endpoints":3,"filter":"/api/schema?category=keys"},{"name":"Account","endpoints":14,"filter":"/api/schema?category=account"},{"name":"Analytics","endpoints":10,"filter":"/api/schema?category=analytics"},{"name":"Folders","endpoints":7,"filter":"/api/schema?category=folders"},{"name":"Automations","endpoints":7,"filter":"/api/schema?category=automations"},{"name":"MCP","endpoints":1,"filter":"/api/schema?category=mcp"},{"name":"System","endpoints":1,"filter":"/api/schema?category=system"}]}