Twitch webhook subscription gets created successfully but not receiving updates

I am able to receive challenge call and return 200 status code with plain text.

I don’t see any notifications and calling https://api.twitch.tv/helix/webhooks/subscriptions
returns empty
{
“total”: 0,
“data”: [],
“pagination”: {}
}

topic url: https://api.twitch.tv/helix/streams?user_id={0}

Here is my controller code dotnet core code hosted in azure. I can hit both get & post endpoint from internet. What am I missing ?

[Route("/notice/twitch")]
[Produces("application/json")]
[ApiController]
public class TwitchNotificationsController : ControllerBase
{
    private const string V1 = "v1";
    private const string ChallengeKey = "hub.challenge";

    private readonly ILogger logger;
    private readonly IVideoGameStreamsNoticeManager noticeManage;
  
    public TwitchNotificationsController(IVideoGameStreamsNoticeManager noticeManager, ILogger logger = null)
    {
        noticeManager.ThrowIfNull(nameof(noticeManager));
        this.noticeManage = noticeManager;
        this.logger = logger ?? NullLogger.Instance;
    }


    [HttpPost("{streamerId}")]
    public async Task<IActionResult> ProcessStreamsChangeNoticeAsync(string streamerId, CancellationToken cancellationToken)
    {
        var eventName = $"{nameof(TwitchNotificationsController)}.ProcessStreamsChangeNotice";
        var telemetryContext = new EventContext(Guid.NewGuid());

        return await this.logger.LogTelemetryAsync(eventName, telemetryContext, async () =>
        {
            TwitchStreamEvent twitchStreams = null;
            telemetryContext.AddContext(nameof(streamerId), streamerId);
            IActionResult result = null;
            try
            {
                telemetryContext.AddContext(nameof(twitchStreams), twitchStreams);
                if (twitchStreams == null)
                {
                    result = this.BadRequest(twitchStreams);
                }
                else
                {
                    var headerSignature = this.Request.Headers["X-Hub-Signature"].FirstOrDefault();
                    if (!this.noticeManage.IsAuthorized(headerSignature, twitchStreams.ToJson()))
                    {
                        result = this.BadRequest(twitchStreams);
                    }
                    else
                    {
                        var stream = new VideoGameStream()
                        {
                            StreamerId = streamerId,
                        };

                        if (twitchStreams?.Data?.Any() == true)
                        {
                            var firstStreams = twitchStreams.Data[0];
                            stream.Id = firstStreams.Id;
                            stream.StreamerId = firstStreams.UserName;
                            stream.StreamerMetadataId = firstStreams.UserId;
                            stream.CurrentViewers = firstStreams.ViewerCount;
                            stream.Title = firstStreams.Title;
                            stream.ProviderVideoGameId = firstStreams.GameId;
                            stream.Language = firstStreams.Language;
                            stream.ImageUrl = firstStreams.ThumbnailUrl;
                            stream.StartTime = firstStreams.StartedAt;
                            stream.Type = firstStreams.Type;
                            stream.Status = StreamStatus.Live;
                        }
                        else if (twitchStreams?.Data?.Any() == false)
                        {
                            stream.Status = StreamStatus.Offline;
                        }

                        await this.noticeManage.EnqueueVideoGameStreamAsync(stream, cancellationToken);
                        result = this.Ok();
                    }
                }
            }
            catch (Exception exc)
            {
                // We should return okay also when is there internal server, but track it in our telemetry.
                telemetryContext.AddError(exc);
                result = this.Ok();
            }

            return result;
        });
    }


    [HttpGet("{streamerId}")]
    public Task<string> ReturnChallengeTokenAsync(string streamerId, CancellationToken cancellationToken)
    {
        var eventName = $"{nameof(TwitchNotificationsController)}.ReturnTwitchChallengeToken";
        var telemetryContext = new EventContext(Guid.NewGuid());
        return this.logger.LogTelemetryAsync(eventName, telemetryContext, async () =>
        {
            telemetryContext.AddContext(nameof(streamerId), streamerId);
            this.Request.ThrowIfNull(nameof(this.Request));

            string token = this.Request.Query["hub.challenge"];
            telemetryContext.AddContext(nameof(token), token);

            return token;
        });
    }
}

Whats your “create subscription” request look like?

Here is the screenshot of debug sessions and below is the code

public async Task SubscribeAsync(TwitchSubscriptionContext context, CancellationToken cancellationToken)
{
context.ThrowIfNull(nameof(context));
context.Callback.ThrowIfNullOrWhiteSpace(nameof(context.Callback));
var subscriptionPayLoad = new TwitchSubscription(context.StreamerMetadataId, this.clientSecret, context.Action, context.LeaseSeconds, context.Callback);
using (StringContent requestBody = TwitchClient.CreateJsonContent(subscriptionPayLoad.ToJson()))
{
using (var clientBuilder = new RestClientBuilder())
{
await this.AddCredentialHeadersAsync(clientBuilder, cancellationToken);
var client = clientBuilder.Build();
var requestUri = new Uri(TwitchClient.WebooksUrl);
var response = await client.PostAsync(requestUri, requestBody, cancellationToken);
if (response?.Content == null || !response.IsSuccessStatusCode)
{
return null;
}

                return new SubscriptionInfo()
                {
                    Subscribed = true,
                    ExpirationDateTime = DateTime.UtcNow.AddSeconds(subscriptionPayLoad.LeaseSeconds),
                    StartDateTime = DateTime.UtcNow,
                };
            }
        }
    }

Your callback is returning

"theHubChallenge"

instead of

theHubChallenge

Your have wrapped the challenge in "

Thank you!
[Produces(“application/json”)] header on my controller was wrapping challenge token with “”

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.