Inbound direction: your system (Make, Zapier, CRM, custom backend) sends a POST to Webivio and creates a registration for a chosen session - same side effects as the registration form (notifications, CRM, and optional outbound webinar.registration.created).
This is not the same as outbound webhooks (Webivio -> your URL).
For webinar series, see Series registration below.
For WooCommerce (one URL, register for the next session without selectedDate), see WooCommerce webhook.
Where to get the URL
- Webinar creator -> Finish step -> registration webhook section, or
- Settings -> Integrations -> Webhooks -> registration API / documentation section.
URL shape:
https://webivio.com/api/public/registration-webhook?webinarId={webinar-uuid}&token={secret}
webinarId- webinar UUIDtoken- per-webinar secret in the query string (no account Bearer / API key)
Interactive docs in the panel: /auth/settings/integrations/registration-api (you can paste your URL with token).
Endpoint
| Method | POST (also OPTIONS for CORS) |
| Path | /api/public/registration-webhook |
| Auth | Query: webinarId + token |
| Content-Type | application/json |
| CORS | Access-Control-Allow-Origin: * |
Body - single participant
Required: email and exactly one way to pick the session time.
| Field | Required | Aliases | Description |
|---|---|---|---|
email | Yes | buyer_email, customer_email, e-mail, mail | Participant email |
name | No | first_name, firstName, imie | First name |
surname | No | last_name, lastName, nazwisko | Last name |
phone | No | phone_number, phoneNumber, telefon | Phone |
selectedDate | Yes* | selected_date, webinarDate, date | ISO datetime with offset (preferred) |
instanceId | Yes* | instance_id | Existing instance UUID |
instanceDate + instanceTime | Yes* | instance_date, instance_time | YYYY-MM-DD + HH:mm |
userTimezone | No | user_timezone, timezone, timeZone | e.g. Europe/Warsaw |
utm_source etc. | No | camelCase (utmSource…) | Campaign UTMs |
urlParameters, referrer | No | snake_case | Extra context |
*Pick one session variant.
Example (single)
{
"email": "jane@example.com",
"name": "Jane",
"surname": "Doe",
"phone": "+48123456789",
"selectedDate": "2026-07-10T18:00:00+02:00",
"userTimezone": "Europe/Warsaw",
"utm_source": "make",
"utm_campaign": "july-campaign"
}
Body - bulk
{
"participants": [
{
"email": "anna@example.com",
"name": "Anna",
"selectedDate": "2026-07-10T18:00:00+02:00"
},
{
"email": "bob@example.com",
"name": "Bob",
"instanceId": "existing-instance-uuid"
}
]
}
Limit: max 50 participants per request.
Success response (single, HTTP 200)
{
"success": true,
"participantId": "550e8400-e29b-41d4-a716-446655440000",
"accessCode": "a1b2c3d4",
"instanceId": "660e8400-e29b-41d4-a716-446655440001",
"playerUrl": "https://player.webivio.com/start/?code=a1b2c3d4"
}
Bulk response (HTTP 200 when the request itself is valid)
{
"success": true,
"summary": { "success": 1, "failed": 1 },
"results": [
{
"email": "anna@example.com",
"success": true,
"participantId": "…",
"accessCode": "…",
"instanceId": "…",
"playerUrl": "…"
},
{
"email": "bad@example.com",
"success": false,
"error": "INVALID_EMAIL"
}
]
}
Root success is true when at least one registration succeeded.
Error codes
| HTTP | Meaning |
|---|---|
| 400 | Missing email, bad JSON, missing session, empty / too large participants |
| 403 | Bad token or inactive webinar |
| 404 | Webinar / instance not found |
200 + alreadyRegistered: true | Email already registered for that session (soft duplicate — do not retry) |
| 429 | Rate limit: RATE_LIMIT_EXCEEDED (+ Retry-After; reason: minute / hour / day) |
| 500 | Server error |
Default limits (per webinar, UTC): 50 / min, 500 / h, plus a working cap of 10,000 / day. Paid accounts: 500 / min, 10,000 / h, same 10,000 / day. Bulk: max 50 people per request.
Call examples
curl
curl -X POST \
"https://webivio.com/api/public/registration-webhook?webinarId=YOUR_WEBINAR_ID&token=YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"email":"jane@example.com","name":"Jane","selectedDate":"2026-07-10T18:00:00+02:00"}'
PowerShell
$body = @{
email = "jane@example.com"
name = "Jane"
selectedDate = "2026-07-10T18:00:00+02:00"
} | ConvertTo-Json
Invoke-RestMethod `
-Method Post `
-Uri "https://webivio.com/api/public/registration-webhook?webinarId=YOUR_WEBINAR_ID&token=YOUR_TOKEN" `
-ContentType "application/json" `
-Body $body
Zapier (Zapier -> Webivio)
- Copy the registration webhook URL from the Webivio panel (with
webinarIdandtoken). - In Zapier: action Webhooks by Zapier -> POST (or Code if you build JSON manually).
- URL = the Webivio URL.
- Payload Type: JSON.
- Map fields from the previous step (Typeform / Sheets ->
email,name,selectedDate).
Make: HTTP -> Make a request -> POST to the same URL with a JSON body.
On success Webivio behaves like a form signup (email / SMS / CRM per webinar settings) and may emit outbound webinar.registration.created.
Security
- Treat
tokenlike a password - do not commit it to public repos. - A URL with token is enough to register on that webinar; do not expose it on a public front-end without controls.
- Token rotation in the UI may be limited - if you suspect a leak, contact support or regenerate per current panel options.
Series registration
Same pattern (token in URL, single/bulk, rate limit), but no date selection — Webivio computes sessions from the series schedule (FIXED / ROLLING).
Where to get the URL
- Series creator → Finish step → registration webhook section, or
- Series dashboard → Links → registration webhook section.
https://webivio.com/api/public/series-registration-webhook?seriesId={series-uuid}&token={secret}
seriesId— series UUIDtoken— per-series secret (registrationWebhookToken)
Endpoint
| Method | POST (also OPTIONS for CORS) |
| Path | /api/public/series-registration-webhook |
| Auth | Query: seriesId + token |
| Content-Type | application/json |
Body — single participant
Required: email. Webinar date (selectedDate / instanceId) is not required — the series schedule is calculated automatically.
userTimezone (IANA, e.g. Europe/Warsaw) is optional. If missing, UTC, or invalid, the server uses the series zone (rollingTimeZone from the creator; default Europe/Warsaw). Zapier/Make can omit the field and still create valid instances.
Optional: firstSessionDate (YYYY-MM-DD in the participant's time zone). When the series has first-session choice enabled (allowFirstSessionChoice), this field is required and must be one of the available upcoming day-1 dates. Without the field (or when choice is off), the server picks the next slot.
{
"email": "john@example.com",
"name": "John",
"surname": "Smith",
"phone": "+15551234567",
"userTimezone": "America/New_York",
"firstSessionDate": "2026-07-14",
"utm_source": "make",
"utm_campaign": "series-launch"
}
Body — bulk
{
"participants": [
{ "email": "anna@example.com", "name": "Anna" },
{ "email": "bartek@example.com", "name": "Bartek", "userTimezone": "Europe/Warsaw" }
]
}
Limit: max 50 participants per request. Rate limit same as webinars (min/h/day, per series).
Success response (single)
{
"success": true,
"seriesRegistrationId": "550e8400-e29b-41d4-a716-446655440000",
"redirectUrl": "https://webivio.com/series-thankyou-page/…",
"sessions": [
{
"sortOrder": 1,
"participantId": "…",
"startTime": "2026-07-10T16:00:00.000Z",
"accessCode": "a1b2c3d4",
"playerUrl": "https://player.webivio.com/start/?code=a1b2c3d4"
}
]
}
On success Webivio behaves like a series form signup (series confirmation email, day-1 CRM integrations, outbound webinar.registration.created for day 1 with series_id / series_registration_id).
Series unregistration
Same token (registrationWebhookToken) and query auth (seriesId + token), different path:
https://webivio.com/api/public/series-unregistration-webhook?seriesId={series-uuid}&token={secret}
| Method | POST (also OPTIONS for CORS) |
| Path | /api/public/series-unregistration-webhook |
| Auth | Query: seriesId + token (same as registration) |
| Content-Type | application/json |
Does not require ACTIVE series status — you can unregister after the series has ended.
Body — single participant
Required: email (aliases: buyer_email, customer_email, etc.).
{
"email": "john@example.com"
}
Body — bulk
{
"participants": [
{ "email": "anna@example.com" },
{ "buyer_email": "bart@example.com" }
]
}
Limit: max 50 per request. Rate limit same as series registration (min/h/day).
Response — success (HTTP 200)
{
"success": true,
"unregistered": true,
"email": "john@example.com",
"seriesRegistrationId": "550e8400-e29b-41d4-a716-446655440000",
"removedParticipantCount": 3
}
Response — email not registered (HTTP 200, idempotent)
{
"success": true,
"unregistered": false,
"email": "john@example.com",
"code": "NOT_REGISTERED"
}
Removes the series registration and participants from all days (hard delete). Does not send emails or outbound webhooks.
See also
- Outbound webhooks
- Panel:
/auth/settings/integrations/registration-api
Future ideas (non-production)
Today the API covers creating a participant / series registration (single/bulk). Ideas under consideration (no dates):
- account-level API key (Bearer) instead of query token only
- token rotation in the UI
- GET participants list / status
- update participant data
Idempotency-Keyheader
These are not product promises - only directions we collect from integration users.
Idempotency, time zones and duplicates
The endpoint does not support an Idempotency-Key header. Do not assume a retry after timeout is safe: store the result on your side and avoid automatic parallel retries.
When the same email is already registered for the same webinar instance, the API returns HTTP 200 with success: true and alreadyRegistered: true (not 409). It does not update the existing record. Treat this as success — Make/Zapier should not retry.
selectedDate and userTimezone do not simply override each other: the new time-zone system uses them together. If selectedDate has an offset, the code converts its time into userTimezone; without an offset, it treats the date and time as local in userTimezone. Send consistent values, preferably an offset-qualified ISO value and its matching IANA zone.