Webhook

Webhook dostarcza zdarzenie GAMEMONITORING do Twojego systemu od razu po akcji na platformie. To zwykłe żądanie POST z JSON-em, dzięki któremu strona, panel lub usługa gry może reagować automatycznie.

W przypadku nagród za głosy najpierw skonfiguruj Webhook, a potem użyj osobnego scenariusza: Nagrody za głosy.

Podłączenie

Ta konfiguracja łączy projekt GAMEMONITORING z handlerem i daje token podpisu do weryfikacji przychodzących żądań.

  1. Otwórz Moje projekty, utwórz projekt albo wybierz istniejący, a potem przejdź do ustawień Webhook.
  2. Utwórz publiczny endpoint HTTPS, który przyjmuje POST z Content-Type: application/json i nie wykonuje przekierowań.
  3. W ustawieniach Webhook wpisz pełny URL handlera, na przykład https://panel.example.com/gamemonitoring-webhook, i zapisz go.
  4. Skopiuj token podpisu z tego samego bloku i wpisz go w skrypcie handlera.
  5. W handlerze sprawdź signature, obsłuż potrzebne event_type i zwróć udaną odpowiedź 2xx dopiero po przetworzeniu zdarzenia.

Po konfiguracji wyślij testowy Webhook z interfejsu i sprawdź status dostawy. Dla przykładowego URL serwer musi przyjmować POST na /gamemonitoring-webhook.

Jeśli test się nie uda, zacznij od odpowiedzi handlera: 401 oznacza problem z podpisem, 403 albo HTML challenge zwykle wskazuje WAF lub bot protection, a timeout oznacza, że URL jest niedostępny z internetu albo odpowiada za wolno.

Wymagania handlera

  • URL musi być dostępny z internetu. Lokalne adresy, prywatne sieci oraz URL z loginem lub hasłem nie nadają się do tego.
  • HTTPS jest zalecany dla produkcji. HTTP jest obsługiwany, ale słabiej chroni dane w drodze.
  • Handler musi przyjmować POST i JSON body bez przekierowań.
  • Zwracaj 2xx dopiero po przetworzeniu zdarzenia przez Twój system. Zwykle wystarczy 204.
  • Jeśli zdarzenia nie da się bezpiecznie przetworzyć, zwróć kod błędu. 3xx, 4xx, 5xx, timeout i błąd połączenia są traktowane jako nieudana dostawa.
  • Jeśli używasz firewalla, bot protection albo allowlist, dodaj adresy IP GAMEMONITORING do wyjątków.
  • Nie zwracaj w treści odpowiedzi tokenów, stack trace, błędów SQL ani innych szczegółów wewnętrznych. Odpowiedź handlera jest widoczna w interfejsie, więc tekst błędu musi być bezpieczny i zrozumiały.

Dane zdarzenia

Każdy Webhook przychodzi jako JSON z podstawowymi polami:

  • event_type — jakie zdarzenie trzeba obsłużyć.
  • event_id — unikalny ID zdarzenia. Użyj go razem z event_type do idempotencji i ochrony przed ponowną dostawą.
  • is_test — oznacza testową dostawę z interfejsu.
  • signature — podpis body zdarzenia.
Przykład zdarzenia Webhook
{
  "event_id": "9824cabb-2203-437e-9b6c-aba43dde3e4b",
  "event_type": "example.event",
  "is_test": false,
  "signature": "0ac4c97a5d934599dbd78985c4bcbb6926e77b4809d2be56333b1b25f638f064"
}

Jak czytać przykład: event_type pokazuje, jakie zdarzenie trzeba obsłużyć, event_id trzeba zapisać przed zmianą stanu, is_test: true oznacza tylko sprawdzenie dostawy, a signature służy wyłącznie do uwierzytelnienia żądania.

Logika zdarzenia zależy od event_type. Dla server.vote użyj osobnego scenariusza: Nagrody za głosy.

Jeśli is_test ma wartość true, sprawdź podpis i zwróć 2xx, ale nie zmieniaj salda ani ekwipunku.

Przykład odpowiedzi handlera

Dla każdego zdarzenia wybierz jasny wynik:

  • 204 No Content — podpis jest poprawny i zdarzenie przetworzone. Tak samo odpowiadaj na test i duplikat już obsłużonego zdarzenia.
  • 400 Bad Request — brakuje pól wymaganych. Nie uruchamiaj logiki biznesowej.
  • 401 Unauthorized — podpis jest niepoprawny. Nie wykonuj żądań API, nie zmieniaj bazy i nie przyznawaj nagród.
  • 500 Internal Server Error — baza, kolejka albo usługa wewnętrzna jest chwilowo niedostępna. Dostawa pozostaje nieudana i można ją ponowić po naprawie.

Przykład: jeśli handler sprawdził podpis, zapisał event_type + event_id i obsłużył zdarzenie, może zwrócić 204. Jeśli baza jest niedostępna, zwróć 500, żeby dostawa nie została za wcześnie oznaczona jako udana.

Weryfikacja podpisu

Podpis znajduje się w polu signature. Sprawdzaj go przed logiką biznesową, żądaniami API i zmianami w bazie.

Do weryfikacji weź wszystkie pola body poza signature, posortuj klucze alfabetycznie i zbuduj ciąg key=value połączony przez &. Wartości boolean zapisuj jako true albo false.

Ciąg do podpisu
event_id=9824cabb-2203-437e-9b6c-aba43dde3e4b&event_type=example.event&is_test=false

Dla przykładu powyżej ciąg podpisu buduje się tylko z event_id, event_type i is_test. Następnie oblicz HMAC-SHA256 tokenem z ustawień Webhook i porównaj z signature z żądania.

Gotowe podpisy w przykładach są policzone dla tokena demonstracyjnego paste-webhook-token-here. W swoim handlerze użyj tokena z ustawień Webhook.

Po swojej stronie:

  • zbuduj ciąg do podpisu z posortowanych kluczy;
  • oblicz HMAC-SHA256 z tokenem podpisu;
  • porównaj wynik z signature funkcją o stałym czasie porównania: hash_equals w PHP, timingSafeEqual w Node.js albo compare_digest w Pythonie;
  • zwróć 401, jeśli podpis jest nieprawidłowy.

Minimalny handler

Ten przykład przyjmuje dowolny Webhook: czyta JSON, sprawdza signature, obsługuje testową dostawę, waliduje podstawowe pola i zwraca 204. Logikę konkretnego zdarzenia dodaj po weryfikacji podpisu.

php
<?php
$secret = 'paste-webhook-token-here';

$event = json_decode(file_get_contents('php://input'), true) ?: [];
$isTest = ($event['is_test'] ?? false) === true;
$signingData = array_replace($event, ['is_test' => $isTest ? 'true' : 'false']);

$fields = array_values(array_filter(array_keys($event), fn($field) => $field !== 'signature'));
sort($fields, SORT_STRING);

$signing = implode('&', array_map(fn($field) => $field . '=' . (string) ($signingData[$field] ?? ''), $fields));
$expected = hash_hmac('sha256', $signing, $secret);
$actual = (string) ($event['signature'] ?? '');

if (!hash_equals($expected, $actual)) {
    http_response_code(401);
    exit;
}

if ($isTest) {
    http_response_code(204);
    exit;
}

$eventType = (string) ($event['event_type'] ?? '');
$eventId = (string) ($event['event_id'] ?? '');

if ($eventType === '' || $eventId === '') {
    http_response_code(400);
    exit;
}

error_log('Accepted webhook event ' . $eventType . ' #' . $eventId);

http_response_code(204);

Ponowna dostawa i deduplikacja

Webhook działa w modelu at-least-once: to samo zdarzenie może przyjść więcej niż raz. Każda akcja zmieniająca stan Twojego systemu musi być idempotentna po event_type + event_id.

Zapisuj parę event_type i event_id w tabeli z unikalnym kluczem. Jeśli rekord już istnieje, zdarzenie było już obsłużone: zwróć 204 i nie zmieniaj stanu ponownie.

Tabela obsłużonych zdarzeń Webhook
CREATE TABLE gamemonitoring_webhooks (
  event_type varchar(64) NOT NULL,
  event_id varchar(100) NOT NULL,
  created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (event_type, event_id)
);

Gdy Webhook zmienia Twoją bazę, zapisuj zdarzenie i wykonuj akcję w jednej transakcji. Jeśli handler wydaje nagrodę, zapis event_type + event_id i aktualizacja nagrody muszą zakończyć się razem. Jeśli zapis nie utworzył nowego wiersza, zdarzenie było już obsłużone.

Nie używaj nicku, ID użytkownika ani ID serwera jako klucza deduplikacji: jeden użytkownik może wywołać różne zdarzenia albo później powtórzyć dozwoloną akcję. Kluczem musi być event_type + event_id.

Przykład: handler wydał nagrodę, ale połączenie zerwało się przed otrzymaniem przez GAMEMONITORING 204. Przy ponowieniu to samo zdarzenie przyjdzie jeszcze raz. Handler musi znaleźć zapisane event_type + event_id, nie wydać nagrody ponownie i zwrócić 204.

Jeśli handler tymczasowo nie może przetworzyć zdarzenia, zwróć nieudaną odpowiedź. Po usunięciu przyczyny dostawę można ponowić z interfejsu, jeśli ponowienie jest dostępne dla tego zdarzenia.

Testy i ponowienie

Dostawa testowa (is_test: true) sprawdza URL handlera, podpis i odpowiedź HTTP. Handler powinien przejść tę samą ścieżkę przetwarzania: odczytać JSON, sprawdzić signature, rozpoznać is_test i zwrócić udaną odpowiedź 2xx.

Zdarzenie testowe nie może zmieniać balansu, ekwipunku, ról, subskrypcji ani innych danych produkcyjnych. Do testu wystarczy techniczny log i odpowiedź 204.

Jeśli dostawa zakończy się błędem, interfejs pokazuje status, kod HTTP i odpowiedź handlera. Po naprawieniu przyczyny nieudaną dostawę można wysłać ponownie, jeśli ponowienie jest dostępne dla tego zdarzenia.