HiLobby API v1

REST API for the PRO+ plan: profile, links, stats, donations, messages, live status and webhooks.

On this page

Quick start

Three steps are enough:

  1. In the dashboard open the "API and webhooks" tab and create a key with the permissions you need.
  2. Copy the key (it is shown only once) and store it on your server.
  3. Send a request with the Authorization header. The /api/v1 response shows the key permissions and limits.
curl -H "Authorization: Bearer lp_live_..." https://145-239-29-97.sslip.io/api/v1

Base URL: https://145-239-29-97.sslip.io/api/v1 · OpenAPI 3.1 (JSON)

Authentication

Every request (except the OpenAPI specification) needs a key in the Authorization (Bearer) or X-Api-Key header.

Authorization: Bearer lp_live_0123456789abcdef0123456789abcdef01234567
X-Api-Key: lp_live_0123456789abcdef0123456789abcdef01234567
  • Keys start with lp_live_. We store only a hash, so a lost key cannot be recovered: roll the secret or create a new key.
  • Do not use a key in website or mobile app code. The API is meant to be called from a server.
  • You can restrict a key to IP addresses (single addresses or CIDR ranges) and set an expiry date.
  • When PRO+ expires, keys stop working (plan_required error) and work again once the plan is renewed.

Permissions

Each category has a read level (:read) and, where it makes sense, a write level (:write). Write includes read.

CategoryPermissionsWhat it covers
Profileprofile:read profile:write Name, bio, address, plan; write: name, bio, message button
Linkslinks:read links:write Link list; write: add, edit, reorder, delete
Statisticsstats:read Views, clicks, sources, devices, live traffic
Donationsdonations:read donations:write History, summaries, goal; write: moderation, goal changes
Messagesmessages:read messages:write Message inbox; write: mark as read, delete
LIVE statuslive:read live:write Stream status; write: turning LIVE on and off
Webhookswebhooks:read webhooks:write List and delivery history; write: add, edit, test

Give keys only the permissions they need. For example, a stream overlay usually needs donations:read and live:read.

Rate limits

  • Up to 1000 requests per hour per key (PRO+ plan setting).
  • An additional short burst limit protects against sudden request spikes.
  • Up to 10 keys and 5 webhooks per account.
  • Every response has X-RateLimit-* headers. When you exceed the limit you get a 429 status and a Retry-After header.
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 997
X-RateLimit-Reset: 1792040400
Retry-After: 42

Response format

A successful response has a data field, and lists also have next. An error has an error field with a code and a message.

{"ok": true, "data": { ... }, "next": 1234}
{"ok": false, "error": {"code": "insufficient_scope", "message": "...", "required_scope": "donations:read"}}
  • Amounts are given in zloty (amount) and in grosze (amount_minor).
  • Dates are in UTC in ISO 8601 format, e.g. 2026-10-15T18:42:07Z.
  • Every response has an X-Request-Id header. Include it when you report a problem.

Error codes

CodeHTTPMeaning
unauthorized401No key in the request.
invalid_key401The key does not exist or has been revoked.
key_expired401The key expiry date has passed.
account_inactive403The account is blocked or inactive.
plan_required403The feature requires PRO+ (or another plan for that feature).
ip_not_allowed403The request came from an address outside the key IP allowlist.
insufficient_scope403The key lacks the required permission (see required_scope).
not_found404The resource or endpoint does not exist.
conflict409The operation does not fit the current state (e.g. the donation is not waiting for review).
invalid_json400The request body is not valid JSON.
invalid_request400Invalid request headers.
validation_error422Invalid data (see message).
rate_limited429Rate limit exceeded.
server_error500An error on our side. Try again, and if it persists, contact us with the X-Request-Id.
maintenance503Maintenance in progress. Try again later (see the Retry-After header).

Pagination

Lists return the newest items first. The limit parameter (1-100, default 25) sets the page size; pass next from the response as after to fetch the next page. When next is null, you have reached the end.

GET /api/v1/donations?limit=50
GET /api/v1/donations?limit=50&after=1234

Idempotency

Requests that change data (POST, PATCH, DELETE) can include an Idempotency-Key header (up to 100 characters). Repeating a request with the same key within 24 hours returns the stored response (Idempotent-Replayed: true header) instead of performing the operation again. Useful when retrying after a network error.

curl -X POST -H "Authorization: Bearer lp_live_..." -H "Idempotency-Key: 6f1c2a" \
  -H "Content-Type: application/json" -d '{"title":"Nowy film","url":"https://youtu.be/xyz"}' \
  https://145-239-29-97.sslip.io/api/v1/links

Endpoints

Paths are relative to /api/v1. Send request bodies as JSON (Content-Type: application/json). An asterisk marks a required field.

panel.api_cat_

MethodPathPermissionDescription
GET/any keyKey, plan and limit information
GET/openapi.jsonno keyOpenAPI 3.1 specification (no key needed)
GET/eventsany keyList of webhook events

Profile

MethodPathPermissionDescription
GET/meprofile:readProfile details
PATCH/meprofile:writeUpdate name, bio and the message button
Parameters: name string, bio string, messages_enabled boolean
MethodPathPermissionDescription
GET/linkslinks:readList of links and sections in order
POST/linkslinks:writeAdd a link (optionally at a given position)
Parameters: title* string, url* string, subtitle string, tag string, enabled boolean, featured boolean, position integer
GET/links/{id}links:readA single link
PATCH/links/{id}links:writeUpdate a link: title, URL, enabled, position
Parameters: title string, url string, subtitle string, tag string, enabled boolean, featured boolean, position integer
DELETE/links/{id}links:writeDelete a link

Statistics

MethodPathPermissionDescription
GET/statsstats:readStatistics: daily views, unique visitors, clicks, sources, links, devices
Parameters: days integer, from date, to date
GET/stats/realtimestats:readLive traffic (last 30 minutes)
GET/stats/mediakitstats:readMedia kit: reach, growth, engagement, countries, devices, sources and community (aggregated data)
Parameters: days integer

Donations

MethodPathPermissionDescription
GET/donationsdonations:readList of donations (status and date filter)
Parameters: limit integer, after integer, status string, since datetime
GET/donations/summarydonations:readSummary: totals for 24 h, 7 and 30 days, top supporters, goal
GET/donations/{id}donations:readA single donation
POST/donations/{id}/approvedonations:writeApprove a donation from the review queue
POST/donations/{id}/rejectdonations:writeReject a donation from the review queue (optional reason)
GET/donations/goaldonations:readFundraising goal and progress
PATCH/donations/goaldonations:writeUpdate the fundraising goal
Parameters: enabled boolean, name string, desc string

Messages

MethodPathPermissionDescription
GET/messagesmessages:readMessages from visitors
Parameters: limit integer, after integer, unread boolean
PATCH/messages/{id}messages:writeMark a message as read or unread
Parameters: read* boolean
DELETE/messages/{id}messages:writeDelete a message

LIVE status

MethodPathPermissionDescription
GET/livelive:readLIVE status and channels
POST/livelive:writeTurn LIVE status on or off (manual mode)
Parameters: live* boolean, platform string, title string

Webhooks

MethodPathPermissionDescription
GET/webhookswebhooks:readList webhooks
POST/webhookswebhooks:writeCreate a webhook (secret returned once)
Parameters: url* string, events* array, description string
PATCH/webhooks/{id}webhooks:writeUpdate a webhook: URL, events, enabled
Parameters: url string, events array
DELETE/webhooks/{id}webhooks:writeDelete a webhook
POST/webhooks/{id}/testwebhooks:writeSend a test ping event
GET/webhooks/{id}/deliverieswebhooks:readWebhook delivery history (30 days)
Parameters: limit integer, after integer
POST/webhooks/{id}/deliveries/{delivery}/retrywebhooks:writeRedeliver a delivery

Changes saved through the API appear in the dashboard after a page refresh. If the dashboard is open, refresh it before editing so that you do not overwrite API changes.

Webhooks

A webhook sends an event to your https address as soon as something happens. Add webhooks in the dashboard or through the API. Through the API you can subscribe to an event only if the key can read that category.

EventRequired permissionDescription
donation.receiveddonations:readNew paid donation (status: approved, pending_review or rejected)
donation.approveddonations:readDonation approved from the review queue
donation.rejecteddonations:readDonation rejected from the review queue
message.receivedmessages:readNew message from a visitor
live.startedlive:readStream started (manually, automatically or via the API)
live.endedlive:readStream ended
link.createdlinks:readLink added (in the dashboard or via the API)
link.updatedlinks:readLink updated
link.deletedlinks:readLink deleted
ping–Test event from the dashboard or the API

Sample request:

POST /twoj-adres HTTP/1.1
Content-Type: application/json
User-Agent: HiLobby-Webhooks/1.0
X-HiLobby-Event: donation.received
X-HiLobby-Delivery: evt_3f9a1c0b7d2e4a6f8b1c
X-HiLobby-Timestamp: 1792003327
X-HiLobby-Signature: t=1792003327,v1=5f2b...e91a

{
    "id": "evt_3f9a1c0b7d2e4a6f8b1c",
    "type": "donation.received",
    "created_at": "2026-10-15T18:42:07Z",
    "api_version": "1.0",
    "data": {
        "id": 1234,
        "amount": 25,
        "amount_minor": 2500,
        "currency": "PLN",
        "nick": "Kuba",
        "message": "Pozdrawiam!",
        "email": null,
        "status": "approved",
        "reject_reason": null,
        "provider": "BLIK / przelew",
        "thanked": false,
        "created_at": "2026-10-15T18:41:50Z",
        "paid_at": "2026-10-15T18:42:07Z"
    }
}
  • Respond with a 2xx status within 8 seconds. Do heavy work later (in a queue) to avoid timeouts.
  • Failed deliveries are retried after: 1 min, 5 min, 30 min, 2 h, 6 h, 12 h. After that the delivery is marked "failed" and you can redeliver it manually in the dashboard or through the API.
  • After 15 failed events in a row the webhook is disabled and we send you an e-mail.
  • An event may arrive more than once or out of order. The id field is unique, so use it to skip duplicates.
  • We only send to public https addresses, without following redirects.
  • Deprecated headers: headers carrying the old brand name (from before the switch to X-HiLobby-*) have been removed - every event is now signed exclusively with X-HiLobby-* headers.

Signature verification

The X-HiLobby-Signature header looks like t=<unix time>,v1=<hex>. Compute HMAC SHA-256 of t + "." + body with the webhook secret and compare it with v1 in constant time. Reject events older than 5 minutes.

Node.js

const crypto = require('crypto');

// rawBody: tresc zadania jako tekst (przed JSON.parse)
function verify(rawBody, header, secret) {
  const p = Object.fromEntries(header.split(',').map(x => x.split('=')));
  const mac = crypto.createHmac('sha256', secret).update(p.t + '.' + rawBody).digest('hex');
  const fresh = Math.abs(Date.now() / 1000 - Number(p.t)) < 300;
  return fresh && crypto.timingSafeEqual(Buffer.from(mac), Buffer.from(p.v1));
}

PHP

<?php
$raw = file_get_contents('php://input');
parse_str(str_replace(',', '&', $_SERVER['HTTP_X_HILOBBY_SIGNATURE'] ?? ''), $p);
$mac = hash_hmac('sha256', ($p['t'] ?? '') . '.' . $raw, getenv('HILOBBY_WEBHOOK_SECRET'));
if (!hash_equals($mac, $p['v1'] ?? '') || abs(time() - (int) ($p['t'] ?? 0)) > 300) {
    http_response_code(400);
    exit;
}
$event = json_decode($raw, true);
// ... obsluga $event['type'] i $event['data']
http_response_code(200);

Python

import hmac, hashlib, time

def verify(raw_body: bytes, header: str, secret: str) -> bool:
    p = dict(x.split('=', 1) for x in header.split(','))
    mac = hmac.new(secret.encode(), (p['t'] + '.').encode() + raw_body, hashlib.sha256).hexdigest()
    return abs(time.time() - int(p['t'])) < 300 and hmac.compare_digest(mac, p['v1'])

Examples

Latest approved donations

curl -H "Authorization: Bearer $LP_KEY" "https://145-239-29-97.sslip.io/api/v1/donations?status=approved&limit=10"

Donation summary (e.g. for an overlay)

curl -H "Authorization: Bearer $LP_KEY" https://145-239-29-97.sslip.io/api/v1/donations/summary

Turning LIVE status on from your own script

curl -X POST -H "Authorization: Bearer $LP_KEY" -H "Content-Type: application/json" \
  -d '{"live": true, "platform": "twitch", "title": "Granie z widzami"}' https://145-239-29-97.sslip.io/api/v1/live

Hiding a link

curl -X PATCH -H "Authorization: Bearer $LP_KEY" -H "Content-Type: application/json" \
  -d '{"enabled": false}' https://145-239-29-97.sslip.io/api/v1/links/a1b2c3d4e5

Adding a webhook

curl -X POST -H "Authorization: Bearer $LP_KEY" -H "Content-Type: application/json" \
  -d '{"url": "https://example.com/hooks/hilobby", "events": ["donation.received", "order.paid"]}' \
  https://145-239-29-97.sslip.io/api/v1/webhooks

Versions and changes

Current version: 1.0. New fields and endpoints are added without changing the version, so ignore unknown fields. Breaking changes will go to a new path (e.g. /api/v2), and we will announce the retirement of an old version in advance.

Cookie settings

The session, form security and saving this choice. Always on, because the site doesn't work without them.
Remembering the light or dark theme.
A random browser identifier (13 months) used to count return visits and visit paths. Basic statistics (location from IP, device, screen, visit time) work without this consent and without cookies.
Remembering the campaign source until sign-up (30 days). We don't show ads or share this data with advertisers.

We save your choice for 12 months and you can change it in the footer. Details and the cookie list