Kick: Points and redeem functionality #204

Closed
opened 2026-09-12 10:55:17 -04:00 by Salastil · 1 comment
Owner

image.png

Kick has a plaque for the user's total channel points and options to redeem things from the streamer. We need to show this.

Expected behavior: Create a new plaque at the bottom of the userlist displaying the amount of channel points, when clicked it should spawn a widget pane that doesn't pass off the viewport of the that shows a list of the various redeem options. When clicked it should use the redeem API to redeem it. Ensure there is flood protection so that it cannot be flooded with several per second or strike rate limits.

![image.png](/attachments/8068f760-ff24-4f38-a517-7960016098ea) Kick has a plaque for the user's total channel points and options to redeem things from the streamer. We need to show this. Expected behavior: Create a new plaque at the bottom of the userlist displaying the amount of channel points, when clicked it should spawn a widget pane that doesn't pass off the viewport of the that shows a list of the various redeem options. When clicked it should use the redeem API to redeem it. Ensure there is flood protection so that it cannot be flooded with several per second or strike rate limits.
Author
Owner

Finished — https://git.salastil.com/Salastil/nobilis/commit/d420636, https://git.salastil.com/Salastil/moho/commit/0b99273

Verified live with the one authorised redeem. CAT PATS on tayl31gh: 201 Created,
balance 18,326 → 17,826, exactly the 500 the reward costs.

Doing that found a bug that would have made the feature fail every single time. The
redeem endpoint needs a transaction_id, and it must be a ULID, not a UUID:

  • empty body → 422, "transaction_id is required"
  • UUID → 400, "Invalid request"
  • ULID → 201

Kick wants an id shaped like its own — 48 bits of millisecond timestamp then 80
random, Crockford base32, 26 characters. It is an idempotency key, so one is
generated per call and never reused. The first draft sent {}.

Two guards, and they are different ones. Kick's is that transaction id: two requests
carrying one id are one redeem. Ours is two seconds between redeems per account —
deliberately not tuned to sit under a rate limit, because the failure worth
preventing is not a 429, it is a stuck key or a double click spending a thousand
points and shouting in a live chat twice.

Rewards are read anonymously (it is the same list on the channel's page). Refusals
carry Kick's own wording, since that is the half that says why.

The pane opens upward — the plaque is at the bottom of a full-height column, so a
list growing down would be drawn off the window. Capped at 60vh and scrolling.
Unavailable rewards are shown but not pressable, each saying why: off, paused, not
enough points, or needs typed input, which moho cannot do yet. That last one is the
only part of the issue not delivered, and it is Kick's is_user_input_required
flag — worth its own issue if those rewards matter.

558 tests green.

Finished — https://git.salastil.com/Salastil/nobilis/commit/d420636, https://git.salastil.com/Salastil/moho/commit/0b99273 **Verified live with the one authorised redeem.** CAT PATS on tayl31gh: 201 Created, balance 18,326 → 17,826, exactly the 500 the reward costs. Doing that found a bug that would have made the feature fail every single time. The redeem endpoint needs a `transaction_id`, and it must be a **ULID**, not a UUID: - empty body → 422, "transaction_id is required" - UUID → 400, "Invalid request" - ULID → 201 Kick wants an id shaped like its own — 48 bits of millisecond timestamp then 80 random, Crockford base32, 26 characters. It is an idempotency key, so one is generated per call and never reused. The first draft sent `{}`. Two guards, and they are different ones. Kick's is that transaction id: two requests carrying one id are one redeem. Ours is two seconds between redeems per account — deliberately not tuned to sit under a rate limit, because the failure worth preventing is not a 429, it is a stuck key or a double click spending a thousand points and shouting in a live chat twice. Rewards are read anonymously (it is the same list on the channel's page). Refusals carry Kick's own wording, since that is the half that says *why*. The pane opens **upward** — the plaque is at the bottom of a full-height column, so a list growing down would be drawn off the window. Capped at 60vh and scrolling. Unavailable rewards are shown but not pressable, each saying why: off, paused, not enough points, or needs typed input, which moho cannot do yet. That last one is the only part of the issue not delivered, and it is Kick's `is_user_input_required` flag — worth its own issue if those rewards matter. 558 tests green.
Salastil added the feature label 2026-09-12 11:19:23 -04:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Salastil/moho#204