Wszystkie artykuły
Zdarzenia webhooka subskrypcji i licencji przepływające przez tunel HTTPS do zweryfikowanego lokalnego obsługującego środowiska deweloperskiego.
Lemon Squeezywebhookssubscriptionslocal testing

Testowanie webhooków Lemon Squeezy na localhost

Aby przetestować webhooki Lemon Squeezy na localhost, uruchom swoją aplikację, udostępnij jej trasę webhooka przez publiczny tunel HTTPS, utwórz webhook w trybie testowym w Ustawienia → Webhooki i zweryfikuj surowe ciało żądania względem X-Signature nagłówek. Użyj testowego koszyka do rzeczywistych danych zamówienia oraz kontrolki symulacji subskrypcji Lemon Squeezy do zdarzeń cyklu życia, na które trudno czekać.

Jak wygląda poprawna lokalna konfiguracja

Lemon Squeezy wysyła HTTP POST ze swojej infrastruktury, więc nie może dotrzeć localhost na twoim komputerze. Tunel kończy publiczny TLS i przekazuje niezmienioną metodę, ciało i nagłówki do lokalnej trasy, takiej jak http://localhost:3000/api/webhooks/lemonsqueezy.

Kompletny test składa się z czterech części: trybu testowego Lemon Squeezy, publicznego adresu URL do wywołań zwrotnych, tego samego sekretu podpisu w panelu kontrolnym i środowisku lokalnym oraz obsługi, która weryfikuje dane przed zmianą stanu subskrypcji lub licencji. Jest to bardziej użyteczne niż przesyłanie skopiowanego JSON z curl, ponieważ prawdziwa dostawa testuje zarówno trasowanie, jak i podpis wygenerowany przez dostawcę.

Utwórz webhook i wyślij zdarzenie testowe

  1. Uruchom swoją aplikację na porcie 3000 i sprawdź, czy trasa jest akceptowana POST.
  2. Rozpocznij tunel z npx portpreview 3000.
  3. Przełącz pulpit Lemon Squeezy w tryb testowy.
  4. Otwórz Ustawienia → Webhooki i dodaj https://your-subdomain.portpreview.dev/api/webhooks/lemonsqueezy.
  5. Wygeneruj silny losowy sekret podpisu, zapisz go jako LEMONSQUEEZY_WEBHOOK_SECRET, i wybierz tylko te zdarzenia, które obsługuje Twoja aplikacja.
  6. Utwórz testowy zakup lub użyj dostępnej akcji symulacji subskrypcji w trybie testowym, a następnie sprawdź dziennik dostawy i swoją lokalną odpowiedź.

Oficjalny Dokumentacja webhooka Lemon Squeezy pozwala Ci na przeglądanie ostatnich payloadów i ponowne wysyłanie zapisanych webhooków ze strony ustawień. Ponowne wysyłanie jest przydatne do testów regresyjnych, ale Twoja aplikacja musi traktować je jako duplikat, a nie jako drugie zdarzenie biznesowe.

Zweryfikuj X-Signature przed analizą JSON

Lemon Squeezy oblicza skrót HMAC-SHA256 nad treścią żądania przy użyciu sekretu podpisu i wysyła skrót w formacie szesnastkowym w X-Signature. Oblicz skrót na podstawie dokładnych surowych bajtów ciała i porównaj bufory o tej samej długości za pomocą funkcji działającej w czasie stałym. Główny dokumentacja żądań podpisu zawiera przykłady dla Node, PHP, Pythona i Ruby.

// app/api/webhooks/lemonsqueezy/route.ts
import crypto from 'node:crypto';
import { NextRequest, NextResponse } from 'next/server';

export async function POST(request: NextRequest) {
  const secret = process.env.LEMONSQUEEZY_WEBHOOK_SECRET;
  if (!secret) return new NextResponse('server misconfigured', { status: 500 });

  const rawBody = await request.text();
  const suppliedHex = request.headers.get('x-signature') ?? '';

  if (!/^[0-9a-f]{64}$/i.test(suppliedHex)) {
    return new NextResponse('invalid signature', { status: 401 });
  }

  const expected = crypto
    .createHmac('sha256', secret)
    .update(rawBody)
    .digest();
  const supplied = Buffer.from(suppliedHex, 'hex');

  if (supplied.length !== expected.length ||
      !crypto.timingSafeEqual(supplied, expected)) {
    return new NextResponse('invalid signature', { status: 401 });
  }

  const event = JSON.parse(rawBody);
  await acceptEvent(event);
  return NextResponse.json({ received: true });
}

Nie dzwonić request.json() pierwsze. Ponowne serializowanie wynikowego obiektu może zmienić bajty wyglądające na nieistotne i złamać HMAC. Sprawdzenie długości jest również niezbędne, ponieważ Node timingSafeEqual rzuca, gdy długości buforów się różnią. Oficjalny Lemon Squeezy Samouczek webhooków Next.js podąża za tą samą surową sekwencją ciała.

Zrozum ładunek zanim zaktualizujesz swoją bazę danych

Ciało jest obiektem zasobu JSON:API. meta.event_name identyfikuje wydarzenie, meta.custom_data przenosi dane przekazane podczas realizacji zamówienia, oraz data zawiera zasób zamówienia, subskrypcji lub klucza licencyjnego. Lemon Squeezy wysyła również X-Event-Name; traktuj podpisane ciało jako autorytatywne dane wejściowe i używaj nagłówka do diagnostyki trasowania.

Zamówienia i tożsamość klienta

Dla order_created, przypisz zakup do wewnętrznego użytkownika za pomocą identyfikatora wygenerowanego przez serwer w danych niestandardowych podczas realizacji zamówienia. Nie ufaj identyfikatorowi użytkownika podanemu przez klienta bez sprawdzenia jego własności. Zachowaj identyfikator zasobu i identyfikator wariantu Lemon Squeezy, aby późniejsze zdarzenia subskrypcji lub zwrotu mogły zostać skonsolidowane.

Subskrypcje są maszyną stanów

Uchwyt subscription_created, subscription_updated, subscription_cancelled, subscription_resumed, i subscription_expired jako odrębne przejścia. Anulowanie może oznaczać, że dostęp pozostaje ważny do końca okresu rozliczeniowego; wygaśnięcie jest silniejszym sygnałem, że subskrypcja zakończyła się. Modeluj daty i status zamiast przełączania jednej wartości logicznej.

Niepowodzenia płatności i odzyskiwanie

Przetestowano nieudane i odzyskane procesy odnowienia tam, gdzie tryb testowy je obsługuje. Nieudana płatność nie powinna koniecznie natychmiast cofać dostępu; zastosuj okres karencji określony w polityce produktu i pozwól, aby późniejsze płatności lub zdarzenia subskrypcji doprowadziły konto do najnowszego stanu dostawcy.

Ponowne próby wymagają przetwarzania niezmienniczego

Zgodnie z Lemon Squeezy odnośnik żądania webhook, a 200 znaki odpowiedzi rejestrują jako udane. Inne statusy są ponawiane do trzech razy z rosnącymi opóźnieniami wynoszącymi około 5, 25 i 125 sekund. Panel ponownie wysyła tworzenie, co powoduje, że ten sam logiczny zdarzenie może pojawić się więcej niż raz.

Zbuduj klucz idempotentności z stabilnych podpisanych pól ładunku. Praktycznym podejściem jest unikalny wiersz w bazie danych dla identyfikatora zasobu webhooka, nazwy zdarzenia i znacznika czasu zdarzenia lub hash surowego podpisanego ciała, gdy nie ma dedykowanego identyfikatora zdarzenia. Wstaw ten dowód i zaktualizuj stan aplikacji w jednej transakcji. Zwróć 200 dla uprzednio wykonanego duplikatu.

BEGIN;
INSERT INTO webhook_receipts (fingerprint, received_at)
VALUES ($1, now())
ON CONFLICT DO NOTHING;
-- Continue only if one row was inserted.
UPDATE subscriptions SET provider_status = $2 WHERE provider_id = $3;
COMMIT;

Nie włączaj dostarczania e-maili ani wolnego wywołania API zewnętrznego dostawcy jako części ścieżki potwierdzenia. Zapisz zadanie w tej samej transakcji, odpowiedz i pozwól pracownikowi obsłużyć efekty uboczne. Szerzej przewodnik po ponawianiu webhooków i idempotencji obejmuje ten wzorzec.

Rozwiązywanie problemów z testami webhooków Lemon Squeezy na localhost

Żadne żądanie nie dociera do aplikacji

Sprawdź, czy tunel nadal działa, czy callback zawiera sufiks trasy i czy twój framework ma obsługę POST pod tym dokładnym adresem. Wywołaj samodzielnie publiczny punkt końcowy. Błąd 502 tunelu wskazuje na lokalny port; błąd 404 frameworka wskazuje na umiejscowienie trasy.

Każdy podpis jest nieważny

Potwierdź, że tryb testowy i tryb na żywo nie używają różnych rekordów webhooka ani sekretów. Odczytaj ciało raz jako tekst lub bajty, nie przycinaj ani ciała, ani sekretu i upewnij się, że globalny middleware JSON nie działa jako pierwszy. Sprawdź, czy X-Signature przybyło, ale nigdy nie drukuj sekretu podpisu.

Dostawa ciągle próbuje ponownie

Lemon Squeezy oczekuje 200, a nie przekierowanie na stronę logowania. Wyłącz ścieżkę webhooka z middleware CSRF i sesji użytkownika, zachowując weryfikację podpisu. Przechwytuj błędy bazy danych, utrzymuj krótki kod i upewnij się, że odpowiedź o powodzeniu jest faktycznie zwracana w każdej obsługiwanej gałęzi zdarzenia.

Symulacja subskrypcji jest niedostępna

Kontrole symulacji wymagają odpowiednich danych subskrypcji w trybie testowym. Niektóre symulacje płatności wymagają historii odnowień. Najpierw utwórz wymaganą subskrypcję testową lub testowy zakup, a następnie skorzystaj z menu akcji subskrypcji opisanego w Lemon Squeezy's. przewodnik dla deweloperów webhook.

Lista kontrolna bezpieczeństwa i uruchomienia

  • Wygeneruj losowy sekret podpisu, przechowuj go w konfiguracji środowiska i zmieniaj go w razie ujawnienia.
  • Zweryfikuj HMAC dla surowego ciała przed analizą JSON, zapisami w bazie danych, generowaniem licencji lub zmianami dostępu.
  • Użyj porównania bezpiecznego pod względem czasu i odrzuć brakujące lub nieprawidłowe podpisy.
  • Trzymaj tryb testowy oraz sekrety i rekordy webhooków na żywo oddzielnie.
  • Zezwalaj tylko na POST, egzekwuj rozsądny limit rozmiaru treści, ograniczaj ilość nieprawidłowych żądań i ukrywaj dane klientów w logach.
  • Przetestuj duplikaty, zdarzenia cyklu życia występujące w nieznanej kolejności, przestoje bazy danych i odzyskiwanie po przekroczeniu limitu czasu przed zastąpieniem tunelu swoim produkcyjnym adresem URL.

Udane przejście przez proces realizacji zamówienia na ścieżce szczęśliwego przebiegu dowodzi jedynie, że jedno zdarzenie dotarło. Integracja gotowa do produkcji dowodzi odrzucenia podpisu, bezpieczeństwa przed duplikatami, zbieżności cyklu życia oraz odzyskiwania po odpowiedzi innej niż 200. W przypadku podstawowych pułapek kryptograficznych, zobacz przewodnik weryfikacji podpisu.

Najczęściej zadawane pytania

Jak przetestować webhooki Lemon Squeezy na localhost?
Udostępnij swoją lokalną trasę webhooka za pomocą tunelu HTTPS, utwórz webhook, gdy panel jest w trybie testowym, użyj tego samego sekretu podpisu lokalnie i wywołaj testowy checkout lub symulację obsługiwanej subskrypcji.
Jak weryfikuje się podpis webhooka Lemon Squeezy?
Oblicz skrót HMAC-SHA256 dla dokładnie surowego ciała żądania za pomocą swojego sekretu podpisu, zdekoduj szesnastkową wartość X-Signature i porównaj bufory o tej samej długości przy użyciu funkcji bezpiecznej czasowo.
Czy Lemon Squeezy ponawia nieudane webhooki?
Tak. Jego dokumentacja mówi, że odpowiedzi inne niż 200 są ponawiane do trzech dodatkowych razy z wykładniczym opóźnieniem, mniej więcej po 5, 25 i 125 sekundach.
Czy mogę symulować odnawianie subskrypcji Lemon Squeezy w trybie testowym?
Tryb testowy zapewnia symulację działań dla obsługiwanych zdarzeń subskrypcji. Niektóre symulacje związane z płatnościami wymagają istniejącej testowej subskrypcji i danych dotyczących odnowienia, więc najpierw utwórz potrzebny stan testowy.