embedio
How it worksModulesPricing
enes
Sign in
Get started

Getting Started

Getting StartedSDK & Embed Snippet

Connections & Automation

ConnectionsValidationsResponse ActionsForm Rules

Reference

API Reference

Customization

Widget Customization

Developers

API Reference

Every endpoint embedio exposes: what authenticates it, what it accepts, and what it returns.

Authentication

Every dashboard-facing endpoint below (forms, bookings, webhooks, uploads, AI chat, and live chat management) is authenticated with your project's API key as a Bearer token. Find and regenerate your key on the API Keys page in your dashboard.

terminal
curl https://api.tryembedio.com/v1/forms \
  -H "Authorization: Bearer sk_live_..."

Endpoints reached through an opaque per-resource key in the URL — a form's submit key, a booking page's key, a chat widget's key, or a share-link token — are meant to be called directly from a visitor's browser and do not take an API key.

Rate Limits

Every public endpoint below (no API key — reached with a per-resource key or token) is rate-limited per IP address. A request over the limit gets a 429 response and standard RateLimit-Limit / RateLimit-Remaining / RateLimit-Reset response headers. Bearer-authenticated dashboard endpoints (forms, submissions, webhooks, uploads, AI Chat and Live Chat management) aren't separately rate-limited — your plan's monthly submission and storage pool (see Forms & Submissions) is the real ceiling there.

Endpoint(s)Limit
POST /v1/submit/:formKey, POST /f/:formKey20 requests / minute
GET /v1/share/:token/submissions60 requests / minute
Bookings: GET .../info, .../slots, .../manage/:token*60 requests / minute
Bookings: POST .../book20 requests / minute
AI Chat / Live Chat widget: GET .../status60 requests / minute
AI Chat / Live Chat widget: POST (start, message, escalate)20 requests / minute
GET /v1/pricing, /v1/blog, /v1/blog/:slug60 requests / minute
POST /v1/contact5 requests / minute

Forms & Submissions

Submit a form (public, no API key)

The endpoint your embedded form or the SDK actually posts to. formKey is the opaque key shown on each form's implementation page.

MethodPath
POST/v1/submit/:formKey
POST/f/:formKey (alias, also accepts a plain HTML form post)
terminal
curl -X POST https://api.tryembedio.com/v1/submit/frm_xxxxxxxxxx \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{"email": "visitor@example.com", "message": "Hello!"}'
  • _gotcha: honeypot field — leave it empty; a filled value is silently treated as spam and answered with a fake success
  • _redirect: a URL on the same origin as the submitting page; external redirects are rejected for non-JSON submissions. Optional — what happens after a submission (a custom message, or a redirect of your choice) is normally set per-form on the dashboard's "After submission" panel, no field required. This overrides the dashboard setting for one embed only.
  • file: a single file field, only accepted when the project has the Uploads module enabled
StatusBodyMeaning
200{ "ok": true, "message": string | null, "redirectUrl": string | null }Accepted — message/redirectUrl reflect the dashboard's "After submission" setting, if one is configured. A non-JSON request gets a 303 redirect directly instead, when a redirect applies.
404{ "error": "form_not_found" }Unknown formKey
402{ "error": "monthly_limit_reached" }Plan's monthly submission pool is used up
403{ "error": "uploads_module_required" }A file was sent but Uploads isn't enabled
400{ "error": "invalid_file_type" }File extension not allowed
413{ "error": "file_too_large" }File exceeds the plan's per-file limit
402{ "error": "storage_limit_reached" }Plan's storage pool is used up

Manage forms (requires API key)

MethodPathBody / notes
GET/v1/formsList your forms
POST/v1/forms{ "name", "type": "form" | "survey" | "newsletter" }
PATCH/v1/forms/:formKey/trust-level{ "trustLevel": "relaxed" | "balanced" | "strict" }
GET/v1/forms/:formKey/submissionsPaginated submissions for one form
GET/v1/submissionsPaginated submissions across all forms
PATCH/v1/forms/:formKey/submissions/:id/unflagClear a spam flag

Share Links

A share link lets you hand a client or teammate read-only access to one form's submissions without giving them your API key.

MethodPathAuth
POST/v1/forms/:formKey/share-linkAPI key — generates a token
DELETE/v1/forms/:formKey/share-linkAPI key — revokes it
GET/v1/share/:token/submissions?page=&pageSize=Public — the token is the credential

Bookings

All three endpoints below are public — the booking page's key is the credential, and requests are rate-limited.

MethodPathNotes
GET/v1/bookings/:key/infoPage name, timezone, slot length, booking window
GET/v1/bookings/:key/slots?date=YYYY-MM-DDAvailable slots for one day
POST/v1/bookings/:key/book{ "name", "email", "notes"?, "startAt" } — 409 slot_taken if it just got booked

Webhooks

Webhook endpoints are managed with your API key (create, list, delete, view delivery logs, resend, and send a test event). embedio delivers submission.created to every enabled endpoint whenever a form on your project receives a real submission.

delivery payload
POST <your endpoint URL>
Content-Type: application/json
X-Embedio-Event: submission.created
X-Embedio-Delivery: 5f2b1c3a-...
X-Embedio-Signature: sha256=<hmac-sha256 of the raw body, hex-encoded>

{
  "event": "submission.created",
  "data": {
    "submissionId": "...",
    "formKey": "frm_xxxxxxxxxx",
    "formName": "Contact form",
    "formType": "form",
    "data": { "email": "visitor@example.com", "message": "Hello!" },
    "sourceUrl": "https://yoursite.com/contact",
    "flagged": false,
    "createdAt": "2026-01-01T12:00:00.000Z"
  },
  "deliveryId": "5f2b1c3a-...",
  "createdAt": "2026-01-01T12:00:00.000Z"
}

Verify a delivery by computing HMAC-SHA256 of the exact raw request body, keyed with the endpoint's secret (shown once on the Webhooks page, format whsec_...), and comparing it to the hex digest after sha256= in X-Embedio-Signature.

verify.js
const crypto = require("crypto");

function isValidDelivery(rawBody, signatureHeader, secret) {
  const expected = crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
  const provided = signatureHeader.replace("sha256=", "");
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(provided));
}
MethodPathNotes
GET / POST/v1/webhooksList / create endpoints
PATCH / DELETE/v1/webhooks/:idUpdate (URL, enabled) / remove
POST/v1/webhooks/:id/testFires a synthetic test event
GET/v1/webhooks/deliveriesPaginated delivery log
POST/v1/webhooks/deliveries/:id/resendRetry one delivery

Uploads

There's no separate upload endpoint — a file rides along with a normal form submission as a multipart file field (see Forms & Submissions above). Everything here is for managing files afterward, with your API key.

MethodPathNotes
GET/v1/uploadsList uploaded files
GET/v1/uploads/:id/downloadDownload one file
DELETE/v1/uploads/:idDelete a file

AI Chat Widget

Public endpoints scoped by your project's AI chat widget key (found on the AI Chat settings page), rate-limited. Messages are limited to 4,000 characters and each conversation stores at most 200 messages.

MethodPathBody
GET/v1/ai-chat/widget/:widgetKey/status—
POST/v1/ai-chat/widget/:widgetKey/conversations{ "visitorId", "name", "email"?, "message" }
POST.../conversations/:id/messages{ "visitorId", "message" }
GET.../conversations/:id/messages?visitorId=—
POST.../conversations/:id/escalate{ "visitorId" } — hands off to a human on Live Chat

Live Chat Widget

Public endpoints scoped by your project's live chat widget key (found on the Live Chat settings page), rate-limited and polling-based. Messages are limited to 4,000 characters and each conversation stores at most 200 messages.

MethodPathBody
GET/v1/chat/widget/:widgetKey/status—
POST/v1/chat/widget/:widgetKey/conversations{ "visitorId", "name", "email"?, "message" } — 409 if nobody is online
GET.../conversations/:id/messages?visitorId=&since=Poll for new messages
POST.../conversations/:id/messages{ "visitorId", "body" }

Related documents

Getting StartedEmbed SDKWidget CustomizationYour API key

Contents

  1. Authentication
  2. Rate Limits
  3. Forms & Submissions
  4. Share Links
  5. Bookings
  6. Webhooks
  7. Uploads
  8. AI Chat Widget
  9. Live Chat Widget
embedio

Your website. Our backend.

Product

  • Modules
  • Pricing
  • Changelog
  • Status

Developers

  • Docs
  • Getting started
  • API reference
  • SDK
  • Connections
  • Widget customization

Company

  • About
  • Blog
  • Contact

© 2026 embedio. All rights reserved.

Privacy PolicyTerms of ServiceAcceptable UseAI Disclosure
GitHubX