Documentation

API & Webhooks

Read and change your server's Lio settings over a REST API with per-server keys, and receive signed webhooks when tickets open, members verify or level up.

Overview

The Lio API gives your website, panel or scripts access to one server's Lio data. Every key belongs to exactly one server, so a leaked key never exposes other servers.

API keys and webhooks are part of Plus. You manage both under Dashboard → Developers. The base URL is https://api.lio.gg/v1.

Authentication

  1. Open Dashboard → Developers on your server.
  2. Create a key with a name. Tick Write only if the integration should change module settings.
  3. Copy the key right away. Lio stores only a hash and cannot show it again.
  4. Send it with every request as Authorization: Bearer <key>.
curl https://api.lio.gg/v1/guild \
  -H "Authorization: Bearer lio_live_xxxxxxxxxxxxxxxx"
Tip

Keep keys on your server. Never put them in browser code or a public repository. Revoke a key in the dashboard and it stops working immediately.

Endpoints

  • GET /v1/guild: plan, member count and the list of enabled modules.
  • GET /v1/modules: every module with its on/off state.
  • GET /v1/modules/{key}: one module with its full configuration.
  • PATCH /v1/modules/{key}: change config fields and/or turn the module on or off. Needs the Write scope.
  • GET /v1/leaderboard?limit=25: XP leaderboard (up to 100 entries).
  • GET /v1/stats?days=30: daily member count, joins and leaves (up to 90 days).
  • GET /v1/health: the server health score and open issues from the dashboard.
  • POST /v1/flows/trigger: start automations that use the Incoming webhook trigger. Needs the Write scope.
curl -X PATCH https://api.lio.gg/v1/modules/welcome \
  -H "Authorization: Bearer lio_live_xxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{ "enabled": true, "config": { "channelId": "123456789012345678" } }'

Changes made through the API

PATCH merges the fields you send into the current configuration. Fields you leave out stay as they are.

Every change shows up in Dashboard → Change history as "API · <key name>", and you can restore it like any dashboard save.

Integrations with Automations

Automations connect Lio to outside tools in both directions, so GitHub, Twitch, Notion or Google Calendar can work through Zapier, Make, n8n or your own code.

Incoming: add the Incoming webhook trigger to a flow and give it an event name. Calling POST /v1/flows/trigger with that name starts the flow within about 15 seconds. Anything you send in data is available to the flow, and data.userId becomes the member the flow acts on.

Outgoing: the Send HTTP request action posts the event to an HTTPS URL, either as JSON or as a Discord webhook message. Placeholders like {user} and {level} work in the message.

curl -X POST https://api.lio.gg/v1/flows/trigger \
  -H "Authorization: Bearer lio_live_xxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{ "event": "github.release", "data": { "userId": "234567890123456789", "tag": "v2.1.0" } }'
Tip

The Automations module must be on. Otherwise the endpoint answers 409 automations_disabled.

Limits and errors

  • 120 requests per minute per key. Responses carry RateLimit headers.
  • Up to 5 API keys and 5 webhooks per server.
  • Errors are JSON: { "error": "code" }.
  • 401 missing_api_key / invalid_api_key, 403 missing_scope / plus_required, 404 unknown_module, 429 rate_limited.

Webhooks

Add an HTTPS URL under Dashboard → Developers → Webhooks and pick the events. Lio sends a POST with a JSON body within seconds of the event.

  • ticket.created, ticket.closed: Tickets and Helpdesk.
  • member.joined, member.left, member.verified.
  • level.up, moderation.case, giveaway.ended, suggestion.created.
  • module.toggled, settings.changed: dashboard and API changes.
POST /your-endpoint
X-Lio-Event: ticket.created
X-Lio-Delivery: 5b0f…
X-Lio-Signature: t=1760000000,v1=4c1e…

{
  "id": "5b0f…",
  "type": "ticket.created",
  "guildId": "123456789012345678",
  "createdAt": "2026-10-18T12:00:00.000Z",
  "data": { "actorId": "234567890123456789", "channelId": "345678901234567890" }
}

Verify the signature

Every delivery is signed with the secret you saw when you created the webhook. Compute an HMAC-SHA256 of "<t>.<raw body>" and compare it with v1. Reject deliveries older than five minutes.

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

export function verifyLio(rawBody, header, secret) {
  const { t, v1 } = Object.fromEntries(header.split(",").map((p) => p.split("=")));
  if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return false;
  const expected = createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex");
  return timingSafeEqual(Buffer.from(expected), Buffer.from(v1));
}

Retries and failures

  • Answer with any 2xx status within 5 seconds. Redirects count as failures.
  • Failed deliveries are retried after 10 seconds and again after 1 minute.
  • After 25 failures in a row Lio turns the webhook off. Turn it back on in the dashboard once your endpoint works.
  • The dashboard shows the last 20 deliveries with status code and duration. Send test fires a webhook.test event.