Video call REST API
Schedule and control video meetings with the REST API
The Meeto REST API at https://api.meeto.me/api/v1 lets your server create one-off and recurring video meetings, invite email guests with reminder emails, run host controls in live rooms and fetch recordings and AI summaries. It authenticates with a secret mk_secret_… key and needs the key owner on Pro or a paid Team seat; other accounts get 402 plan_required. The embeddable widget stays free on every plan.
What can the Meeto API do?
It covers the full life of a meeting your product schedules: create it, invite people, move or cancel dates, control the room while the call runs and collect the recording and AI summary afterwards. All paths below are relative to https://api.meeto.me/api/v1.
| Group | Endpoints |
|---|---|
| Meetings | POST /meetings, GET /meetings, GET · PATCH · DELETE /meetings/{id}, POST /meetings/{id}/reschedule, GET /meetings/{id}/ics |
| Invitations | GET · PUT /meetings/{id}/participants for Meeto accounts; email guests through the guests field |
| Calendar feed | GET /calendar?from=…&to=… expands series into dates, up to 62 days per request |
| Rooms | GET /rooms, GET /rooms/{slug}, live participants, join, settings (open, knock or password), end the session |
| Host controls | mute one, mute all, promote to co-host, remove and let back in, knock queue and POST /knocks/{id}/decide |
| Capture | recording start, stop and extend; AI summary start, stop and the live summary |
| Materials | GET /recordings, GET /notes, then /materials/{token} to read, download video or audio, change sharing or delete |
Recurring meetings use a subset of the iCalendar RRULE: DAILY, WEEKLY, MONTHLY or YEARLY; an interval up to 99; one or more weekdays for a weekly rule; for a monthly rule the 1st–4th or last weekday, the start's own day of the month or the last day; and COUNT or UNTIL. A yearly rule repeats on the start's own date. Dates keep their local time across daylight-saving changes in the meeting's IANA time zone, with the same rules the Meeto app offers when you schedule a meeting.
The API sees only what its key created. Meetings that guests book on your booking page are not listed here; their events reach your server through webhooks.
How does authentication work?
Send a secret server key as a bearer token. Create a website widget key in Settings → Website widget; the server key mk_secret_… is shown once, when the key is created. The public mk_live_… key belongs in browser code and cannot call this API (401 invalid_key).
Authorization: Bearer mk_secret_…Each key is its own scope. It can read and change only the meetings, rooms and materials created through it; two keys of one account do not see each other's meetings, and a key never reaches billing, team settings or other rooms of the account. Revoking the key in the dashboard ends API access at once and stops new joins to its rooms. Keep the secret on your server, out of browser bundles, URLs and logs.
Which plan does the API need?
The owner of the key must be on Pro ($6.99/month or $69/year) or hold a paid active Team seat ($11.99 per seat per month). Every /api/v1 route checks this on each request:
HTTP/1.1 402 Payment Required
{"code":"plan_required","error":"plan_required","requestId":"…","retryable":false}The free parts stay free: the public widget key, the widget's own instant rooms and POST /api/embed/rooms without scheduling fields work on every plan, as described in the widget developer docs.
Create a recurring meeting with email guests
Creation requires an Idempotency-Key header: 1–200 printable ASCII characters, no spaces, one per business operation. Repeat the same key and body after a timeout and you get the original meeting back instead of a duplicate; the same key with a different body answers 409 idempotency_conflict.
curl https://api.meeto.me/api/v1/meetings \
-H "Authorization: Bearer $MEETO_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: crm-appointment-872" \
-d '{
"title": "Weekly project review",
"startsAt": "2027-03-22T10:00:00+02:00",
"durationMin": 45,
"timezone": "Europe/Tallinn",
"rrule": "FREQ=WEEKLY;BYDAY=MO,TH;COUNT=8",
"guests": ["sam@example.com"],
"guestReminders": [1440, 60]
}'The answer is 201 (trimmed here). Share joinUrl unchanged: its k parameter is the room access key. Give hostSecret only to staff who should run the meeting.
{
"meeting": {
"id": "<meeting UUID>",
"roomSlug": "misty-fox-a18f493cb027fe823cb6",
"title": "Weekly project review",
"startsAt": "2027-03-22T08:00:00Z",
"durationMin": 45,
"timezone": "Europe/Tallinn",
"repeat": "custom",
"rrule": "FREQ=WEEKLY;BYDAY=MO,TH;COUNT=8",
"seriesEndsAt": "2027-04-15T07:45:00Z",
"guests": ["sam@example.com"],
"status": "scheduled",
"joinUrl": "https://meeto.me/misty-fox-a18f493cb027fe823cb6?k=<room access key>"
},
"hostSecret": "<host credential>"
}| Field | Rules |
|---|---|
| title | Up to 200 characters |
| startsAt / durationMin | RFC 3339 with an offset; 1–1440 minutes |
| timezone / rrule | IANA zone (default UTC); the start must be one of the rule's dates |
| guests | Up to 25 email addresses, no Meeto account needed; each gets a private calendar invitation |
| guestReminders | Minutes before each date: 15, 60 and/or 1440, at most two. Off unless you send it; not echoed in responses |
| participantUserIds | Up to 50 registered Meeto accounts to invite |
| callMode / region | audio or video (default video); optional preferred media region |
Email guests need the owner's address to be verified by Google or Apple sign-in (403 guests_need_verified_email otherwise). Invitations, updates and cancellations count against the account's guest-mail budget; past it, creation answers 429 guest_limit and nothing is created. Reminder emails do not count against that budget.
How do I move or cancel one date of a series?
Send occurrence, the date as it stands, with the new startsAt. Only that date moves; it becomes a meeting of its own with a new ID and keeps the same room link, and guests get an updated invitation.
curl -X PATCH https://api.meeto.me/api/v1/meetings/$MEETING_ID \
-H "Authorization: Bearer $MEETO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"occurrence": "2027-03-25T08:00:00Z",
"startsAt": "2027-03-26T10:00:00+02:00"
}'Leave occurrence out to edit the whole series. scope: "following", which changes a date and every later one, works from the first date of a series (where it means the whole series); from a later date it is not enabled yet and answers 409 split_unavailable. Add expectedRevision to refuse a stale edit. DELETE /meetings/{id}?occurrence=… removes one date; DELETE without it cancels the meeting, which stays readable with "status": "canceled".
Control the live room and collect recordings
The meeting's roomSlug addresses the room routes. The secret key acts as host for its own rooms, so your backend can mute everyone, promote a co-host or remove someone without the host secret. Moderation needs a live identity from GET /rooms/{slug}/participants; a person who has left answers 404 participant_not_found. A removed person cannot rejoin that session until you allow them back.
curl -X POST https://api.meeto.me/api/v1/rooms/misty-fox-a18f493cb027fe823cb6/recording/start \
-H "Authorization: Bearer $MEETO_API_KEY"
# → 201 { "id": "…", "status": "…", "startedAt": 1805702460,
# "notesStarted": true, "pageToken": "…" }
curl https://api.meeto.me/api/v1/recordings?limit=20 \
-H "Authorization: Bearer $MEETO_API_KEY"Recording starts the MP4 recording and the AI summary together. If the summary cannot start, the video continues and the answer carries notesError, so you can retry notes/start. Recording and AI summary have separate stop endpoints. Call it while the meeting is in progress; everyone in the call sees a capture indicator.
Rate limits, errors and retries
Request rate
Each client IP has a bucket of 60 requests that refills by one per second. Meeting creation has its own bucket per key: 60, then one every 5 seconds.
Retry-After
Every 429 and 5xx answer has retryable: true; 429 and 503 also carry Retry-After. Retry a create with the same idempotency key.
Tracing
Every answer has X-Request-ID. Keep it with your own operation ID when you contact support.
| Status | Codes |
|---|---|
| 400 | bad_json, bad_time, bad_duration, bad_timezone, bad_rrule, rrule_start_mismatch, bad_guest, too_many_guests, idempotency_key_required, bad_pagination |
| 401 · 402 · 403 | invalid_key · plan_required · account_unavailable, guests_need_verified_email |
| 404 · 409 · 410 | not_found (missing or created by another key) · idempotency_conflict, meeting_changed, occurrence_moved, split_unavailable · key_revoked |
| 429 · 502 · 503 | rate_limited, guest_limit · livekit_error from the media service · auth_unavailable, service_unavailable |
Errors share one shape: code, error (the same code), requestId, retryable and, for creation, the failing field. Lists take limit (1–100, default 50) and offset, and return hasMore with nextOffset. Media is encrypted in transit; Meeto is not end-to-end encrypted. See security for how calls are handled.
Frequently asked questions
Is there a server SDK for the REST API?
No. The API is plain HTTPS with JSON bodies, so any HTTP client works. The npm packages and the iOS and Android libraries are for the embeddable call widget, not for /api/v1.
Do meetings created through the API appear in the Meeto app?
Yes. The account that owns the key is the organizer, so the meeting appears in its web and mobile calendar and the owner can sign in and host it with normal host rights on any device.
How long and how far ahead can an API meeting be?
durationMin is an integer from 1 to 1440 minutes. startsAt must be in the future and less than three years ahead. A series may have up to 730 occurrences with COUNT, or end with UNTIL no later than 2100.
What happens when the key owner leaves Pro?
Every /api/v1 call answers 402 plan_required until the owner is on Pro or a paid Team seat again. The public widget key keeps working on every plan, and calls in the owner's rooms follow the Free limits.
Can the API send webhooks for meetings it creates?
Webhook events follow bookings made on a Meeto booking page. For meetings created through the API, read GET /meetings/{id}, GET /notes and GET /recordings to learn what happened.
Put it to work
Open your Meeto account to set it up, or explore the working product first.