Webinars
Create webinars from your own systems, with their schedule, registration and public page.
A webinar is a scheduled session, or a series of them, with a public page where people register and join. Webinars you create through the API are owned by the account the API key belongs to. They show up in the studio like any other webinar, and you run them from the studio when it's time to go live.
The API grows one endpoint at a time. Today you can create a webinar (webinars:write), update one (webinars:write), list your webinars and get one (webinars:read, which webinars:write includes).
Create one
curl https://vapi.vidyst.com/public/v1/webinars \
-H "Authorization: Bearer $VIDYST_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"title": "Product launch: what'\''s new in Q4",
"licenceKey": "VDL-M4A05-TKY9Q-0A5V6-WMR8H",
"scheduledAt": "2026-12-01T21:00:00+05:30",
"timezone": "Asia/Kolkata",
"durationMinutes": 45,
"access": "registration",
"reminders": ["confirmation", "day_before", "hour_before"]
}'The answer is 201 Created with the webinar. Share its pageUrl: that's where people register and join.
The licence
Every webinar runs on a licence, which sets how many people can attend and what the webinar may use. Pass its key as licenceKey: the VDL-XXXXX-XXXXX-XXXXX-XXXXX code you copy in the studio under Licences. Case and dashes don't matter, and a mistyped key is caught before anything is looked up (invalid_request). You must hold the licence, or own it while nobody else holds it, and it must be active. Otherwise the API answers licence_not_found, licence_assigned or licence_inactive.
Draft or scheduled
scheduled(the default) publishes the webinar straight away. Its page goes live and, withaccess: "registration", registration opens. It needsscheduledAt.draftkeeps it private. Nobody can see its page until you schedule it in the studio.scheduledAtis optional.
Times and time zones
- Send
scheduledAtin ISO 8601 with an offset:2026-12-01T15:30:00Zor2026-12-01T21:00:00+05:30. A time without an offset is refused, because it's ambiguous. timezone(IANA, such asAsia/Kolkata, defaultUTC) is how the webinar is shown to people. A series also repeats by it: a weekly 9:00 session stays at 9:00 local time across daylight-saving changes.- Every time the API returns is in UTC (
…Z).
Series
Set repeat to make a series:
repeat | Sessions |
|---|---|
none | One, at scheduledAt (the default). |
daily, weekly, monthly | repeatCount of them (2–52, default 2), starting at scheduledAt. |
custom | On the weekdays in repeatDays (0 = Sunday … 6 = Saturday), repeatCount of them. |
The webinar's occurrences lists every session, nextSessionAt the one on now or the next, and sessionsLeft how many are left.
Registration
- With
access: "open", anyone with the link joins. Withaccess: "registration", people register on the page first. questionsadds up to 20 questions to the registration form:short_text,long_text,multiple_choice,checkboxoryes_no. Acheckboxquestion needs at least twooptions.registrationLimitcaps registrations. The licence's own limits apply as well.reminderspicks the emails registrants get:confirmation, the timed ones before each session (day_before,three_hours_before,hour_before,thirty_minutes_before,fifteen_minutes_before,ten_minutes_before) andreplay. Leave it out and no emails are sent.passcodeasks attendees for a passcode before they join. It's never returned: the webinar sayspasscodeProtected: true.
List and find webinars
GET /webinars returns the webinars your account owns (not ones it only helps run), newest first, 20 to a page (up to 100 with limit):
curl "https://vapi.vidyst.com/public/v1/webinars?status=scheduled,live&sort=scheduledAt&limit=50" \
-H "Authorization: Bearer $VIDYST_API_KEY"{
"data": [{ "id": "01929c5e-8f3a-7b21-9d4e-5a6b7c8d9e0f", "title": "Product launch: what's new in Q4", "status": "scheduled", "…": "…" }],
"nextCursor": "eyJ2IjoyLCJzIjoic2NoZWR1bGVkQXQifQ",
"hasMore": true
}Filters combine (a webinar must match all of them):
| Parameter | Matches |
|---|---|
status | Any of a comma list: draft, scheduled, live, ended. |
access | open or registration. |
licenceKey | Webinars on that licence. |
search | Titles containing the text (2–100 characters, any case; % and _ are plain characters). |
startsAfter, startsBefore | Webinars with a session starting in the range. For a series, any of its sessions counts, so a weekly series shows up in every week it has a session. |
sort orders the list: -createdAt (newest first, the default), createdAt, scheduledAt (the soonest first session first) or -scheduledAt. Drafts without a date come last in both schedule orders.
Pass nextCursor back as cursor, with the same filters and sort, for the next page; see Pagination. Every filter and sort is backed by an index, so a page answers as fast on the thousandth page as on the first.
GET /webinars/{webinarId} returns one webinar. One that doesn't exist, or that your account doesn't own, is a 404; the two look the same, so ids from other accounts can't be probed.
Update one
PATCH /webinars/{webinarId} changes a webinar your account owns. Send only what changes:
curl -X PATCH https://vapi.vidyst.com/public/v1/webinars/01929c5e-8f3a-7b21-9d4e-5a6b7c8d9e0f \
-H "Authorization: Bearer $VIDYST_API_KEY" \
-H "Content-Type: application/json" \
-H 'If-Match: "3"' \
-d '{ "title": "Product launch: Q4 recap", "durationMinutes": 60, "passcode": null }'- A field you leave out stays as it is.
nullclears the fields that can be empty:description,registrationLimit,passcodeandscheduledAt. RemovingscheduledAtmakes a scheduled webinar a draft again.- Lists (
reminders,agenda,faqs,questions,repeatDays) are replaced whole: send the full new list ([]empties it). statusmoves it betweendraftandscheduled. Going live and ending happen in the studio.licenceKeymoves it to another licence you can host on. Not while a session is live.- While a session is live you can still change its details. An ended webinar can't change (
410 webinar_ended). - Changes to the schedule replan its reminder emails. Registrants aren't sent a separate email about the change.
Editing safely
Every webinar response (create, get, update) has an ETag header, the webinar's version, which changes with every edit. Send it back as If-Match on an update. If someone changed the webinar since you read it (another integration, or someone in the studio), your update is refused with 412 precondition_failed and nothing changes, instead of silently overwriting their change. Read it again, apply your change to the new version, and retry.
If-Match is optional; without it the update applies to whatever is there.
Not in the API yet
Speakers and co-hosts, the cover image, the long (formatted) description, room settings, auto-recording and the replay setting are set in the studio for now. Leaving them out of a request is fine, but sending one is refused: unknown fields are an invalid_request, so a typo never goes unnoticed.
Retries
Create requests take an Idempotency-Key. Send one, and retry with the same key after a timeout or a 5xx: you'll get the webinar from the first attempt instead of a second webinar. See Idempotency.
Versioning
What can change within v1, and what won't.
Verify an API key GET
Checks the API key in the `Authorization` header and returns the key's name, scopes, expiry and rate-limit status. Use it to test a new key, to see which permissions a key has, or as a cheap health check for your integration. It needs no scope, and counts against the key's rate limit like any other request. A key that isn't valid gets a `401` (missing, invalid, expired or revoked) or a `403` (valid, but API access isn't enabled for the account or the request comes from outside the key's IP allowlist). The `code` field says which.