Skip to content

API

Overview

The public API at https://dev.api.sparkwebinar.io/public/v1, by your organization's token.

Everything your organization has on the dashboard — its webinars, their sessions, registrations and ratings, its VSLs, the sales counted to them, its surveys and their responses, its pages, its webhooks — is read and, where it makes sense, written through the public API, so your own systems and the tools you wire together can work with it.

https://dev.api.sparkwebinar.io/public/v1

Every request carries your organization’s API token as a bearer:

Authorization: Bearer <token>

The token is made on the dashboard, under Settings, by an owner of the organization. It is shown whole only once, as it is generated — copy it then: afterwards the dashboard shows only its first characters, to tell which one is in use. Lost, or leaked, generate a new one there; the old one stops working at once. The token names the organization, so no route does: everything you read and write is your organization’s, and anything else is answered as not found.

Status infoCode Why
401 UNAUTHENTICATED No bearer in the request, or a header not of that form.
401 API_TOKEN_INVALID A token that names no organization — generated anew since, or never ours.
403 ORGANIZATION_UNAVAILABLE The organization is not served — suspended, locked, or with no plan.
403 ORGANIZATION_BLACKLISTED The organization’s access to the API was blocked. Contact support.

Call it from a server. There is no CORS on the public API: a page in a browser cannot call it, and should not — the token would be in the page.

Every answer is JSON in the same envelope. The status is on the wire; the body is data, and metadata where there is more to say.

{ "data": { "id": 12, "name": "Growth webinar", "..." : "..." } }

A list answers a page of items, and in metadata.list the page it is and how many there are in all:

{
"data": [ { "id": 41, "...": "..." }, { "id": 40, "...": "..." } ],
"metadata": { "list": { "pagination": { "page": 1, "size": 20 }, "total": 57 } }
}

A failure is data: null, and an infoCode where there is one to give:

{ "data": null, "metadata": { "infoCode": "WEBINAR_NOT_FOUND" } }
Status infoCode Why
400 VALIDATION_FAILED A body, a query string or an id that does not fit the route. For a body or a query string, metadata.details.issues says what (below).
404 <RESOURCE>_NOT_FOUND Nothing of your organization’s by that id — WEBINAR_NOT_FOUND, WEBINAR_REGISTRATION_NOT_FOUND, SURVEY_NOT_FOUND, SURVEY_RESPONSE_NOT_FOUND, CUSTOM_PAGE_NOT_FOUND, ORGANIZATION_WEBHOOK_NOT_FOUND, WEBINAR_TICKET_ORDER_NOT_FOUND, AB_TEST_NOT_FOUND, VSL_NOT_FOUND.
409 … The request is well-formed and cannot be done as things are; each route says its codes.
429 TOO_MANY_REQUESTS Over the limit below.

A body or a query string that does not fit names each field that was wrong, the first twenty at most: path is its keys joined by dots, empty for the whole body, and message what was wrong with it, in English. An id in the path that is not one answers VALIDATION_FAILED alone.

{
"data": null,
"metadata": {
"infoCode": "VALIDATION_FAILED",
"details": { "issues": [{ "path": "email", "message": "Invalid email address" }] }
}
}

A route that deletes answers 200 with data: null.

A list takes its page in the query string: page, from 1, and size, up to 100 — twenty by default. Its filters go beside them, each a query parameter named after the field it narrows by; a filter not sent is not applied. Text filters such as a name or an e-mail match inside the value, whatever the case. An instant is filtered as a span: …From is on or after it, …To before it, either alone or both. Every list is newest first, but a webinar’s sessions, which are in the order they start.

GET/public/v1/webinar-registrations?webinarId=12&createdAtFrom=2026-10-01T00:00:00Z&size=100&page=2

Every id is a whole number. Every instant is an ISO 8601 string in UTC, 2026-11-03T22:00:00.000Z, and is sent the same way — with an offset, if not Z.

Every organization may make 120 requests a minute, over the whole public API, whatever its plan. Each answer says where you stand:

Header What it says
X-RateLimit-Limit The limit, 120.
X-RateLimit-Remaining How many are left in this minute.
X-RateLimit-Reset Seconds until the minute turns over.

Over it, the answer is 429 with TOO_MANY_REQUESTS and a Retry-After in seconds. Reading a list in pages of 100 stays well under it.

One address may also make 600 requests a minute, whatever tokens they carry, counted before the token is checked. Over that it is the same 429.

© 2026 Sparkwebinar. All rights reserved.