PolyhydraGames.API.Kick 2.5.0.70

dotnet add package PolyhydraGames.API.Kick --version 2.5.0.70
                    
NuGet\Install-Package PolyhydraGames.API.Kick -Version 2.5.0.70
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="PolyhydraGames.API.Kick" Version="2.5.0.70" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="PolyhydraGames.API.Kick" Version="2.5.0.70" />
                    
Directory.Packages.props
<PackageReference Include="PolyhydraGames.API.Kick" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add PolyhydraGames.API.Kick --version 2.5.0.70
                    
#r "nuget: PolyhydraGames.API.Kick, 2.5.0.70"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package PolyhydraGames.API.Kick@2.5.0.70
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=PolyhydraGames.API.Kick&version=2.5.0.70
                    
Install as a Cake Addin
#tool nuget:?package=PolyhydraGames.API.Kick&version=2.5.0.70
                    
Install as a Cake Tool

PolyhydraGames.API.Kick

Kick integration library for Polyhydra Games hosts and ChannelCheevos.

Documentation

Package Facts

  • PackageId: PolyhydraGames.API.Kick
  • TargetFramework: net10.0
  • Language: C#
  • Test project: test/PolyhydraGames.API.Kick.Tests

Publishing

The .github/workflows/publish-packages.yml workflow runs on pushes to main and manual workflow_dispatch runs on main; pull requests never publish. The package job runs on api-ci-kick, restores, builds, tests, and packs exactly one nupkg into publish-out/, then hands it to downstream jobs through actions/cache. The independent publish-internal mirror job and OIDC-enabled publish-nuget-org job run on the separate nuget-api-kick-publish runner role. That publish-only runner never executes build, test, or pull-request code, so compromised code on the api-ci-kick build runner cannot persist onto the host that receives the nuget.org OIDC token. Both publish jobs first clear the retained workspace, install the same pinned .NET SDK inside their own job, and restore only the run-scoped package cache; setup-dotnet uses the runner tool cache for mirrors and a fresh per-job temp directory for nuget.org publishing. The nuget.org version guard runs with isolated python3 -I. The publish-nuget-org job uses NuGet Trusted Publishing through GitHub OIDC and has no checkout or build steps. GitHub Packages and BaGet publish from the independent, non-OIDC mirror job, which cannot delay the nuget.org job and remains non-blocking. Pull-request validation uses hosted ubuntu-latest. The api-ci-kick and nuget-api-kick-publish runner roles are provisioned by lancer1977/homelab-gitops#1028 and #1029.

The package version is <VersionPrefix>.<github.run_number>. Before publishing, the nuget.org job checks that the version is greater than the highest version listed by nuget.org. Queued default-branch runs may coalesce to the newest pending run, so the newest green commit of a burst is published.

Operator setup: create a nuget.org Trusted Publishing policy for owner lancer1977, repository lancer1977/API-Kick, and workflow file publish-packages.yml.

Standalone restore uses the public packages on nuget.org and requires no package-read token:

dotnet restore API-Kick.sln

Registration

services.AddKickApi(configuration);
services.AddKickStreaming(configuration);

The optional Kick fact mapper can be registered independently with AddKickFactMapper(); it does not require streaming services. The optional neutral provider event mapper can also be registered independently with AddKickProviderEventMapper(); it maps webhook events to the public PolyhydraGames.Streaming.Events contract. Gifted channel subscriptions map to gift, while Kicks gifted map to cheer (Kick's bits-equivalent). See the capability host boundary for the library/runtime responsibility split and event kind mapping.

Use AddKickApi for channel, livestream, OAuth, webhook, and health-check services only. Use AddKickStreaming when the host also needs chat listener, inbound source, outbound sink, and hosted streaming services; it calls AddKickApi internally, so callers do not need to register both.

Explicit-token event subscriptions

IKickEventSubscriptionsClient is a stateless client for hosts that already own account authority and token persistence. Register it without starting streaming workers or configuring a process-wide access token:

services.AddKickEventSubscriptions(new Uri("https://api.kick.com"))
    .ConfigureHttpClient(client => client.Timeout = TimeSpan.FromSeconds(10));

var result = await subscriptions.SubscribeAsync(ownerAccessToken, broadcasterUserId,
    [new KickEventSubscriptionRequest("chat.message.sent", 1)], cancellationToken);

The registration extension is in PolyhydraGames.API.Kick.Setup, the interface in .Interfaces, and request/result types in .Models. Inject the interface as subscriptions; the host must establish the owner's authority before providing their token. ListAsync takes the same explicit token and broadcaster ID. Each request sets its own bearer header; no shared credential binding or configured-token fallback occurs. Existing AddKickApi/AddKickStreaming behavior is unchanged.

Results distinguish Ok, Unauthorized, Forbidden, Rejected, and Unknown. HTTP 200 with all events refused is Rejected; mixed acceptance/refusal is Unknown and requires reconciliation. Malformed/missing create acknowledgement, transport failure, server error, or client timeout is unknown; a mutation may have executed. Caller cancellation propagates and also does not establish non-execution. There are no automatic retries. Reconcile with a list query before repeating an unconfirmed create. An empty list is authoritative only when its outcome is Ok. The client accepts explicit event/version pairs; event selection and reconciliation lifecycle belong to the host. See Kick's subscription documentation.

Explicit-token public chat sends

IKickPublicChatClient sends a message through Kick's official POST /public/v1/chat endpoint. AddKickApi(configuration) registers the typed client using Kick:ApiBaseUrl; each send supplies the caller-owned access token and broadcaster ID explicitly:

var result = await publicChat.SendAsync(ownerAccessToken, broadcasterUserId, "Hello!", cancellationToken);

The client does not retain credentials or retry. A confirmed data.is_sent response produces Sent; provider HTTP rejection or data.is_sent: false produces Rejected; malformed, incomplete, server-error, and otherwise ambiguous responses produce Unknown with a failure code. When Kick includes a nonblank string data.message_id in an affirmative acknowledgement, the result exposes it as ProviderMessageId; omitted or malformed IDs remain null. Caller cancellation propagates, while the configured HttpClient timeout returns Unknown with send_timeout. Unknown means the caller cannot establish whether the message was sent.

For verified chat.message.sent webhooks, KickWebhookEvent.MessageId and the outer normalized event ID remain Kick's signed header delivery/replay ID. ChatMessageId is the separate payload message_id; neutral chat payloads use it when present. Older manually constructed webhook DTOs without ChatMessageId retain the legacy nested-payload fallback to MessageId, which is not evidence that the delivery and chat identities were verified as equal.

Credential-free fixture validation (including concurrent owners and cancellation):

dotnet test test/PolyhydraGames.API.Kick.Tests/PolyhydraGames.API.Kick.Tests.csproj --filter FullyQualifiedName~KickEventSubscriptionsClientTests
dotnet test test/PolyhydraGames.API.Kick.Tests/PolyhydraGames.API.Kick.Tests.csproj --filter 'FullyQualifiedName!~.Integration.'

Credential ownership and 2.0 migration

Version 2.0 removes mutable factory binding. Supply each owner's credentials for each operation; the library never stores a process-wide “currently bound” owner. Register an IKickCredentialProvider that resolves your host user ID to that user's Kick credentials:

var credentials = new KickCredentials(streamerOAuthToken, RefreshToken: streamerRefreshToken,
    ChannelSlug: streamerKickSlug, ChannelId: streamerKickId) { OwnerId = "stable-host-user-id" };
var client = kickApiClientFactory.CreateClient(credentials);
await chatSender.SendMessageAsync(credentials, streamerKickSlug, "Hello!");

Set OwnerId to a stable identity when callers rotate tokens. A successful send retires blocked state for earlier tokens associated with that owner. Without an OwnerId, a blocked token's snapshot remains until it ages out.

KickOutboundSink asks the provider for credentials using the message channel's owner ID and checks the target channel against the credential's configured Kick channel. Missing credentials and owner/channel mismatches fail explicitly. Hosts must register their provider after AddKickApi/AddKickStreaming to replace the default provider, which fails outbound sends.

The configured Kick:AccessToken remains available for single-account webhook auto-subscription. Owner-bound chat sends always use the credentials passed for that operation. InitializeAsync and BoundUserId were removed; migrate 1.x consumers to per-call credentials and an owner credential provider before upgrading. See CHANGELOG.

Configuration

{
  "Kick": {
    "Enabled": true,
    "BaseUrl": "https://kick.com",
    "ApiBaseUrl": "https://api.kick.com",
    "ClientId": "",
    "ClientSecret": "",
    "AccessToken": "",
    "RefreshToken": "",
    "ApplicationName": "PolyhydraGames",
    "Auth": {
      "RedirectUri": "https://localhost:5001/auth/kick/callback"
    },
    "Webhook": {
      "Enabled": true,
      "CallbackPath": "/api/kick/webhook",
      "PublicUrl": "https://example.ngrok-free.app/api/kick/webhook",
      "PublicKey": "",
      "AutoSubscribe": false,
      "EventTypes": "chat.message.sent,channel.followed,channel.subscription.new,channel.subscription.renewal,channel.reward.redemption.updated"
    },
    "Chat": {
      "Enabled": true,
      "OwnerUserId": "your-polyhydra-user-id",
      "ChannelSlug": "your-kick-channel",
      "ChannelId": null,
      "AutoDiscoverActiveStream": true,
      "EnableOutboundChat": true,
      "ReconnectDelay": "00:00:05",
      "MaxReconnectDelay": "00:01:00"
    }
  }
}

Configuration Reference

Key Type Description
Enabled bool Enable/disable entire Kick integration
BaseUrl string Kick website base URL
ApiBaseUrl string Kick API base URL
ClientId string OAuth client ID. Required for channel and livestream lookups (app access token)
ClientSecret string OAuth client secret. Required for channel and livestream lookups (app access token)
AccessToken string OAuth access token used by explicit single-account webhook auto-subscription
RefreshToken string OAuth refresh token
ApplicationName string User-Agent application name
Auth:RedirectUri string OAuth redirect URI for code exchange
Webhook:Enabled bool Enable webhook parsing and validation
Webhook:CallbackPath string Local webhook callback route
Webhook:PublicUrl string Public webhook URL for Kick subscription config
Webhook:PublicKey string Optional webhook signature public key
Webhook:AutoSubscribe bool Auto-subscribe to configured webhook events
Webhook:EventTypes string Comma-separated webhook event types
Chat:Enabled bool Enable/disable chat listener
Chat:OwnerUserId string Platform owner user ID for message routing
Chat:ChannelSlug string Kick channel slug to monitor
Chat:ChannelId string Alternative channel identifier
Chat:AutoDiscoverActiveStream bool Add active streamId metadata when available
Chat:EnableOutboundChat bool Enable outbound chat messaging
Chat:ReconnectDelay timespan Initial reconnect delay
Chat:MaxReconnectDelay timespan Maximum reconnect delay

Notes

  • Keep the docs aligned with the actual Kick and chat integration surface.
  • Prefer concrete configuration and integration notes over implied behavior.
  • Webhook ingestion uses KickLib's signature validation and webhook event parser.
  • Source and test projects consume their shared Polyhydra dependencies as NuGet packages, so the restore/test path works from a standalone clone. An empty-cache restore resolves these published dependencies from nuget.org without a package-read token.
Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
2.5.0.70 784 11/11/2026
2.4.0.69 108 10/31/2026
2.4.0.68 8,474 10/15/2026
2.4.0.67 101 10/15/2026
2.4.0.66 1,226 10/12/2026
2.3.0.65 104 10/12/2026
2.3.0.64 102 10/11/2026
2.2.1.63 3,802 10/10/2026
2.2.0.62 2,123 10/8/2026
2.1.1.61 108 10/8/2026
2.1.1.60 149 10/6/2026
2.1.0.59 107 10/6/2026
2.0.8.58 103 10/6/2026
2.0.8.56 110 10/6/2026
2.0.8.54 835 10/6/2026
2.0.7.53 123 10/5/2026
2.0.6.52 102 10/5/2026
2.0.5.51 107 10/5/2026
2.0.4.50 108 10/5/2026
2.0.3.49 246 10/5/2026
Loading failed