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
- Uruchom swoją aplikację na porcie 3000 i sprawdź, czy trasa jest akceptowana
POST. - Rozpocznij tunel z
npx portpreview 3000. - Przełącz pulpit Lemon Squeezy w tryb testowy.
- Otwórz Ustawienia → Webhooki i dodaj
https://your-subdomain.portpreview.dev/api/webhooks/lemonsqueezy. - Wygeneruj silny losowy sekret podpisu, zapisz go jako
LEMONSQUEEZY_WEBHOOK_SECRET, i wybierz tylko te zdarzenia, które obsługuje Twoja aplikacja. - 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.
