TipPage Developer API
Build your own integrations on top of a TipPage: read tip history, watch and control the TTS queue and media queue, and receive signed webhooks the moment things happen. Every tip produces one TTS entry and, optionally, one media entry.
Download the spec
This entire reference is generated from one OpenAPI 3.1 document: openapi.yaml. Import it into Postman, Insomnia, or Bruno, or feed it to a client generator.
Authentication
Every request needs an API key sent as a bearer token:
Authorization: Bearer tp_live_...
Keys are created by the streamer in Dashboard → Settings → Developer (owner and super admins only). The key identifies the streamer, so there is no account id anywhere in these paths. Each key carries scopes - the operations below name the scope they need. Keys are server-side credentials: never embed one in a browser page or show it on stream.
Rate limits
240 requests/min per IP and 120 requests/min per key. Limit state is
returned in standard RateLimit-* headers; exceeding it returns 429.
Errors
Errors are JSON: { "error": "<human message>", "code": "<machine_code>" }.
Webhooks
Register endpoint URLs (here or in the dashboard) and TipPage POSTs a JSON event envelope to them. See the Webhooks section at the bottom for every event type and payload.
Verify every delivery before trusting it. Your endpoint is a public
URL - anyone who discovers it can POST a perfectly-shaped envelope. The
TipPage-Signature header is the only proof a request came from
TipPage; every other header and the envelope itself are plain text anyone
can forge, and source-IP allowlisting doesn’t work (delivery IPs are not
stable). Each request carries:
| Header | Value |
|---|---|
TipPage-Signature |
t=<unix seconds>,v1=<hex HMAC-SHA256> - the proof of origin |
TipPage-Event |
the event type (e.g. tip.created) - informational |
TipPage-Event-Id |
the envelope id (evt_...) - informational |
TipPage-Delivery |
the delivery id (wd_..., or ping for tests) - informational |
TipPage-Attempt |
delivery attempt number (1-8); a value above 1 means this is a retry of the same event, byte-identical body - informational |
The MAC is HMAC-SHA256 over <t>.<raw request body> with your endpoint’s
signing secret (whsec_..., shown once at creation). Verify against the
raw body bytes (before any JSON parser touches the request), reject
t more than ~5 minutes from your clock (blocks replays of captured
deliveries), and compare MACs in constant time:
import crypto from "node:crypto";
function verify(secret, header, rawBody, toleranceSec = 300) {
const parts = Object.fromEntries(
(header || "").split(",").map((p) => p.split("="))
);
if (!parts.t || !parts.v1) return false;
if (!(Math.abs(Date.now() / 1000 - Number(parts.t)) <= toleranceSec)) return false;
const mac = crypto.createHmac("sha256", secret)
.update(`${parts.t}.${rawBody}`).digest("hex");
const got = Buffer.from(parts.v1, "hex");
const want = Buffer.from(mac, "hex");
return got.length === want.length && crypto.timingSafeEqual(got, want);
}
On a failed check, respond 401 and do nothing else with the request.
Retries re-sign the byte-identical body with a fresh t, so verify every
request, not once per event id - and since delivery is at-least-once,
dedupe verified events by the envelope id. The full verification guide
(with an Express example and common pitfalls) is at
docs.tippage.com/developer-api.
Delivery is at-least-once with no ordering guarantee. Non-2xx responses
retry with backoff for up to ~44 hours (8 attempts); an endpoint that keeps
failing is disabled automatically and the streamer is notified. Endpoint
URLs must be public https:// - private and internal addresses are
rejected. Answer with any 2xx as fast as possible and do real work async.
https://api.tippage.com/v1Identity
Key introspection and API discovery.
TTS queue
The pending TTS queue and its played history. Reads need tts:read; controls need tts:control. The start/finish pair is the same protocol the stream overlay speaks - an external consumer can claim a TTS, play it its own way, and finish it into history. Full pattern: claim, do your thing, finish.
- GETPending TTS queue
/tts/queue - GETPlayed TTS history
/tts/history - GETWhat's playing right now
/tts/now - POSTPause the TTS queue
/tts/pause - POSTResume the TTS queue
/tts/resume - POSTSkip the currently-playing TTS
/tts/skip - POSTClear the whole TTS queue
/tts/clear - DELETERemove one queued TTS
/tts/{orderId} - POSTReplay a TTS from history
/tts/{orderId}/replay - POSTClaim a TTS as now playing
/tts/{orderId}/start - POSTFinish a TTS
/tts/{orderId}/finish - POSTRelease a claimed TTS back to the queue
/tts/{orderId}/release
Media queue
The media (video request) queue, its played history, live playback status, and direct video queueing. Reads need media:read; controls and queueing need media:control.
- GETPending media queue
/media/queue - GETPlayed media history
/media/history - GETWhat's playing right now
/media/now - POSTQueue a video
/media - POSTPause the media queue
/media/pause - POSTResume the media queue
/media/resume - POSTSkip the currently-playing media
/media/skip - DELETERemove one queued media item
/media/{orderId} - POSTReplay a media item from history
/media/{orderId}/replay - POSTClaim a media item as now playing
/media/{orderId}/start - POSTFinish a media item
/media/{orderId}/finish - POSTRelease a claimed media item back to the queue
/media/{orderId}/release - POSTShow the media player
/media/show - POSTHide the media player
/media/hide
Tipping
Tips themselves: create manual tips (tips:create), the accept-new-tips switch (status readable by any valid key, opening/closing via tipping:control), and the supporter leaderboard (any valid key).
- POSTCreate a manual tip
/tips - GETIs tipping open
/tipping - POSTOpen tipping
/tipping/open - POSTClose tipping
/tipping/close - GETTop supporters
/leaderboard
AI voices
AI voice TTS (closed beta): the curated voice catalog with per-voice enabled flags, this month’s character usage, and toggles for the whole feature or individual voices. Needs ai_voices:manage. Every endpoint answers 404 unless AI voices are enabled for your account - the feature is invite-only while in beta.
- GETList AI voices
/ai-voices - POSTEnable AI voices
/ai-voices/enable - POSTDisable AI voices
/ai-voices/disable - POSTEnable one voice
/ai-voices/{voiceId}/enable - POSTDisable one voice
/ai-voices/{voiceId}/disable
Viewers
Viewer management for the sub-rewards system. A viewer is someone who has signed in to the tip page with Twitch - list them with their first sign-in dates and credit balances (viewers:read), read one viewer’s grant ledger and sub-reward usage, and grant or revoke credits (viewers:manage). Everywhere a {user} appears in a path you can pass either the Twitch user id or the viewer’s name (login or display name, case-insensitive). Someone who has never signed in can’t be looked up or granted credits - those requests answer 404 viewer_not_signed_in.
- GETList signed-in viewers
/viewers - GETOne viewer in full
/viewers/{user} - GETA viewer's sub-reward history
/viewers/{user}/rewards - POSTGrant credits
/viewers/{user}/credits/grant - POSTRevoke credits
/viewers/{user}/credits/revoke
Channel points
Resolve channel point redemptions on Twitch. Needs channel_points:manage. Only works for TipPage-managed rewards - Twitch restricts redemption resolution to the app that created the reward. Pair with the twitch.channel_point_redemption webhook, whose is_managed flag says whether a redemption is resolvable.
- POSTMark a redemption fulfilled
/channel-points/redemptions/{redemptionId}/fulfill - POSTCancel a redemption (refund the points)
/channel-points/redemptions/{redemptionId}/cancel
Webhook endpoints
Manage where events get delivered. Needs webhooks:manage. Endpoints can also be managed in the dashboard.
- GETList endpoints
/webhook-endpoints - POSTAdd an endpoint
/webhook-endpoints - GETGet one endpoint
/webhook-endpoints/{endpointId} - DELETEDelete an endpoint
/webhook-endpoints/{endpointId} - PATCHUpdate an endpoint
/webhook-endpoints/{endpointId} - POSTRotate the signing secret
/webhook-endpoints/{endpointId}/rotate-secret - POSTSend a test event
/webhook-endpoints/{endpointId}/ping - GETRecent deliveries
/webhook-endpoints/{endpointId}/deliveries - POSTRedeliver a delivery
/webhook-deliveries/{deliveryId}/redeliver