Skip to main content

API documentation

A REST API over your own Loopinglive data. Everything is JSON, everything is authenticated with a bearer token, and every list is paginated.

Base URL

https://loopinglive.com/api/public/v1

Authentication

Send your key in the Authorization header. Create one under Settings → API keys. Keys are shown once at creation — we store only a hash, so a lost key has to be revoked and replaced.

curl https://loopinglive.com/api/public/v1/webinars \
  -H "Authorization: Bearer ll_live_your_key_here"

Rate limits

100 requests per minute per key. Every response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset. Exceeding the limit returns 429 with a Retry-After header.

Endpoints

GET/webinars

Lists the webinars belonging to the key's owner.

ParameterTypeRequiredDescription
statusstringnodraft, published, or all (default)
pageintegerno1-based page number
limitintegerno1–100, default 25
curl https://loopinglive.com/api/public/v1/webinars \
  -H "Authorization: Bearer ll_live_your_key_here"

Response

{
  "webinars": [
    {
      "id": "0f8c…",
      "title": "The 3-Offer Framework",
      "status": "published",
      "video_duration_seconds": 2880,
      "created_at": "2026-08-30T12:00:00Z"
    }
  ],
  "total": 1,
  "page": 1,
  "limit": 25
}
GET/webinars/{id}

One webinar, with its recent sessions and registrant count.

curl https://loopinglive.com/api/public/v1/webinars/{id} \
  -H "Authorization: Bearer ll_live_your_key_here"

Response

{
  "webinar": {
    "id": "0f8c…",
    "title": "The 3-Offer Framework",
    "status": "published",
    "registrantCount": 128,
    "sessions": [
      { "id": "a1b2…", "starts_at": "2026-09-04T19:00:00Z", "status": "scheduled" }
    ]
  }
}
GET/webinars/{id}/registrants

Registrants for one webinar.

ParameterTypeRequiredDescription
segmentstringnoFilter by watch-depth segment
boughtOnlybooleannoOnly people who bought
pageintegerno1-based page number
limitintegerno1–100, default 25
curl https://loopinglive.com/api/public/v1/webinars/{id}/registrants \
  -H "Authorization: Bearer ll_live_your_key_here"

Response

{
  "registrants": [
    {
      "id": "9c3d…",
      "full_name": "Sarah Okonkwo",
      "email": "sarah@example.com",
      "attended": true,
      "watch_percentage": 63,
      "bought": false
    }
  ],
  "total": 128,
  "page": 1,
  "limit": 25
}
POST/webinars/{id}/registrants

Registers someone programmatically.

ParameterTypeRequiredDescription
full_namestringyes2–100 characters
emailstringyesA valid email address
phonestringnoDigits, spaces, + ( ) -
country_codestringnoISO 3166-1 alpha-2
session_iduuidnoDefaults to the next session
curl -X POST https://loopinglive.com/api/public/v1/webinars/{id}/registrants \
  -H "Authorization: Bearer ll_live_your_key_here"

Response

{
  "registrant": { "id": "9c3d…", "email": "sarah@example.com" }
}
GET/sessions

Sessions across every webinar the key can see.

ParameterTypeRequiredDescription
webinar_iduuidnoRestrict to one webinar
statusstringnoscheduled, live, or ended
curl https://loopinglive.com/api/public/v1/sessions \
  -H "Authorization: Bearer ll_live_your_key_here"

Response

{
  "sessions": [
    { "id": "a1b2…", "webinar_id": "0f8c…", "starts_at": "2026-09-04T19:00:00Z", "status": "scheduled" }
  ],
  "total": 12,
  "page": 1,
  "limit": 25
}

Errors

400The request was malformed — usually a missing parameter.
401The API key is missing, invalid, revoked or expired.
403The account is suspended.
404No such resource, or it belongs to someone else.
422The body failed validation. The response lists each issue.
429Rate limit exceeded. Retry-After says how long to wait.
500Something went wrong on our side.

Webhooks

Loopinglive can POST to a URL of yours whenever something happens. Configure endpoints under Settings → Webhooks. Failed deliveries retry five times with increasing backoff — 5 minutes, 30 minutes, 2 hours, then 8 hours.

registrant.createdSomeone registers
registrant.attendedSomeone joins the room
registrant.completedSomeone watches 90% or more
registrant.clicked_offerSomeone clicks the offer
registrant.boughtSomeone is marked as bought
registrant.no_showSomeone registered but never showed
session.startedA session goes live
session.endedA session finishes

Payload

{
  "event": "registrant.created",
  "timestamp": "2026-09-03T09:14:22.000Z",
  "data": {
    "registrantId": "9c3d…",
    "name": "Sarah Okonkwo",
    "email": "sarah@example.com",
    "webinarTitle": "The 3-Offer Framework",
    "registeredAt": "2026-09-03T09:14:21.880Z"
  }
}

Verifying the signature

Every request carries X-Loopinglive-Signature: an HMAC-SHA256 of the raw request body, keyed with your endpoint’s signing secret. Hash the bytes you received — re-serialising the parsed JSON can reorder keys and produce a different digest.

import { createHmac, timingSafeEqual } from "node:crypto";

export function verify(rawBody, signatureHeader, secret) {
  const expected = createHmac("sha256", secret).update(rawBody).digest("hex");
  const a = Buffer.from(expected);
  const b = Buffer.from(signatureHeader);
  return a.length === b.length && timingSafeEqual(a, b);
}

SDKs

None yet. The API is plain REST with bearer auth, so any HTTP client works.