Skip to content

Twitch: EventSub Subscription Management Command #270

@danielhe4rt

Description

@danielhe4rt

Parent

#266 — Twitch EventSub: ingestão de eventos via webhook (data lake)

What to build

An Artisan command that creates Twitch EventSub subscriptions for a broadcaster, backed by a comprehensive enum of all subscribable event types. This is the final piece that connects the transport layer to the webhook endpoint — once subscriptions are created, Twitch starts sending events.

End-to-end behavior

After this slice, running php artisan twitch:subscribe <broadcaster_user_id> --all iterates through all EventSub event types, creates a webhook subscription for each via the Helix API, and reports results. Twitch sends a verification challenge to the webhook endpoint (from Slice 2) for each subscription. Events that require scopes the broadcaster hasn't authorized are reported as failed (403) without interrupting the rest.

What changes

New — Enum:

  • TwitchEventSubType in Enums/ — string-backed enum with all subscribable event types. Each case provides:
    • version(): the subscription version string ("1" or "2")
    • condition(string $broadcasterId, ?string $userId = null): the condition array for subscription creation
    • Full list includes: stream.online/offline, channel.update, channel.follow, channel.subscribe/.gift/.message/.end, channel.cheer, channel.raid, channel.ban/unban, channel.moderator.add/remove, channel.channel_points_custom_reward_redemption.add/update, channel.poll.begin/progress/end, channel.prediction.begin/progress/lock/end, channel.hype_train.begin/progress/end, channel.goal.begin/progress/end, channel.shield_mode.begin/end, channel.shoutout.create/receive, channel.ad_break.begin, channel.chat.message

New — Command:

  • SubscribeTwitchEventsCommand in Console/ with signature twitch:subscribe {broadcaster_user_id} {--type= : Specific event type} {--all : Subscribe to all types}
  • Lists existing subscriptions via ListSubscriptions request to avoid duplicates
  • Iterates TwitchEventSubType::cases() (or specific type with --type)
  • Calls CreateSubscription request for each, passing broadcaster_user_id in condition and webhook callback URL + secret in transport
  • Handles 403 gracefully (missing scopes) — reports in output, continues to next type
  • Displays results table: type, version, status (created/already_exists/failed + reason)
  • Registers command in IntegrationTwitchServiceProvider

Acceptance criteria

  • TwitchEventSubType enum covers all documented EventSub types with correct versions
  • Each enum case returns correct condition array (some need only broadcaster_user_id, others also need moderator_user_id)
  • php artisan twitch:subscribe <id> --all attempts to create all subscription types
  • php artisan twitch:subscribe <id> --type=stream.online creates a single subscription
  • Command skips already-existing subscriptions (checks via ListSubscriptions)
  • Command handles 403 (missing scopes) gracefully — logs the failure, continues to next type
  • Command displays a summary table with type, version, and result status
  • Tests: enum version() and condition() methods return correct values
  • Tests: command creates subscriptions (mocked Helix API)
  • Tests: command handles 403 and duplicate scenarios
  • vendor/bin/pint --dirty --format agent passes
  • php artisan test --compact --filter=Twitch passes

Blocked by

Metadata

Metadata

Assignees

No one assigned

    Labels

    ready-for-agentFully specified, ready for an AFK agent

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions