API reference
Four routes make up the Embed API — webinar create/list, webinar registration, course enrollment, and course embed-token minting. All are versioned under /api/v1, same as the Send API, and share its bearer-key auth.
Authentication
Authorization: Bearer mia_live_...
A missing or invalid key returns 401 { "error": "Missing or invalid Authorization: Bearer <apiKey>" } on every route below. Keys are managed under API & Integrations in the dashboard — see the quickstart.
POST /api/v1/webinars
Creates a webinar. accessMode is always forced to "registration" — the Embed API only ever deals in public-registration sessions, never subscriber-only live sessions.
| Field | Type | Required | Notes |
| --- | --- | --- | --- |
| title | string | yes | Trimmed; empty after trimming returns 400. |
| scheduledAt | number | no | Unix ms timestamp. |
| courseId | string | no | Ties the webinar to an existing course. |
| capacity | number | no | Must be >= 0 if present. Registrations past capacity are waitlisted, not rejected. |
Returns 201 { "webinar": LiveSession }.
GET /api/v1/webinars
No body. Returns 200 { "webinars": LiveSession[] } — every session on the account with accessMode: "registration", subscriber-only sessions are filtered out.
POST /api/v1/webinars/[id]/register
Registers one end user for a webinar and sends the confirmation/waitlist email.
| Field | Type | Required | Notes |
| --- | --- | --- | --- |
| email | string | yes | Must match a basic email pattern, else 400 { "error": "A valid email is required" }. |
| name | string | yes | Trimmed, max 200 characters, else 400 { "error": "A name is required" }. |
Errors: 404 if the webinar doesn't exist or isn't yours; 400 if it isn't accessMode: "registration"; 409 if it has already ended.
Response:
{ "status": "confirmed", "joinUrl": "https://mailinapp.com/webinar/<id>/join?token=..." }
or, once capacity is reached:
{ "status": "waitlisted", "joinUrl": null }
A confirmed registration fires the webinar's registered lifecycle email; a waitlisted one gets the plain waitlist notice regardless of any binding.
POST /api/v1/courses/[id]/enroll
Grants or revokes course access for an email address, keyed to your own entitlement decision rather than a MailInApp checkout.
| Field | Type | Required | Notes |
| --- | --- | --- | --- |
| email | string | yes | Same validation as registration; lowercased and trimmed before use. |
| active | boolean | no | Defaults to true. false revokes access. |
404 if the course doesn't exist or isn't yours. Response: 200 { "subscriberId": "...", "active": true }.
A fresh grant (active: true on a subscriber who wasn't already entitled) fires the course's enrolled lifecycle email. Revoking access never emails the end user on your behalf.
POST /api/v1/courses/[id]/embed-token
Mints a short-lived (5-minute) signed token for embedding the course portal, after re-checking the subscriber is actually entitled.
| Field | Type | Required | Notes |
| --- | --- | --- | --- |
| email | string | yes | Same validation as above. |
Errors: 404 if the course doesn't exist, isn't yours, or isn't published; 409 if the account hasn't claimed a /learn/<slug> membership URL yet; 403 if this email isn't currently entitled (call enroll first).
Response: 200 { "portalUrl": "https://mailinapp.com/learn/<slug>/courses/<courseId>/embed?token=..." }. Redirect your app's iframe or a new window at portalUrl — it signs the visitor in and lands them in the ordinary course portal.
Lifecycle email bindings
A course or webinar can bind any of its lifecycle events to a studio project instead of the platform's plain confirmation copy:
| Resource | Events |
| --- | --- |
| Course | enrolled, completed (reminder accepted for parity, no automatic trigger — courses have no natural due date to fire one against) |
| Webinar (LiveSession) | registered, reminder |
Bindings are set from the course/webinar's own Lifecycle emails panel in the dashboard, not through this API — they take effect on the next event regardless of whether it was triggered by the Embed API or the equivalent dashboard/public-form action. An event with no binding (or one pointing at a deleted/foreign project) falls straight back to today's plain email — this never breaks a send. A bound event renders through renderSingleRecipientEmail exactly like the Send API's template mode: full fallback engine, interactive blocks, a personal signed live-view link, and the project's own webhook/Responses tracking, attributed to that specific lifecycle event rather than a stored contact row.
Rate limits
Two independent caps apply, per route:
- Per API key: 60 requests/minute. Exceeding it returns
429 { "error": "Rate limit exceeded" }for that key specifically. - Per account, Embed API quota: your plan includes a number of Embed API calls per calendar month, shared across all four routes above.
0on Free/Starter returns403 { "error": "The Embed API isn't included in your plan" }; exceeding a paid tier's quota returns429 { "error": "Monthly Embed API quota for your plan exceeded" }until it resets on the 1st.
Webinar creation additionally re-checks your live-streaming quota (checkLiveSessionQuota) — the same broadcast-minutes/course gate the dashboard's own create flow enforces — and returns 403 with that check's own message if it fails.
Error codes
| Status | Meaning |
| --- | --- |
| 400 | Malformed JSON or a missing/invalid required field — see each route's own table above. |
| 401 | Missing or invalid Authorization header, or the key has been revoked. |
| 403 | Embed API not on your plan, quota check failed, live-session quota exceeded, or (embed-token) the email isn't currently entitled. |
| 404 | The webinar/course doesn't exist or isn't owned by your account — deliberately the same response as "doesn't exist," same reasoning as the Send API's template-mode 404. |
| 409 | (Webinar) the session has already ended. (Embed-token) the account hasn't claimed a membership URL yet. |
| 429 | Per-key rate limit or monthly quota exceeded. |
Related
- Send API reference — the freeform/template transactional endpoint this API shares its auth model with.
- Learning membership overview — courses, subscribers and entitlement, the concepts the enroll/embed-token routes wrap.
- Live sessions & webinars — webinar registration, capacity/waitlist and join links, the concepts the webinar routes wrap.