protect.vet → sayzoo.pl
Ten dokument opisuje co musi zaimplementować zespół sayzoo.pl po swojej stronie, aby integracja PackPoints działała poprawnie. protect.vet jest integratorem — to SayZoo jest źródłem prawdy dla sald.
Poniższe wartości muszą być ustawione przez administratora po obu stronach:
| Parametr | Wartość / Opis |
|---|---|
X-PackPoints-App | protect_vet — stały identyfikator aplikacji w każdym nagłówku |
PACKPOINTS_SYNC_SECRET | Współdzielony sekret HMAC — musi być taki sam po obu stronach. Ustalić z administratorem protect.vet. |
SAYZOO_PACKPOINTS_API_BASE | Base URL API SayZoo, np. https://api.sayzoo.pl/packpoints — SayZoo przekazuje tę wartość protect.vet |
Action items dla SayZoo:
1. Przekazać do protect.vet: SAYZOO_PACKPOINTS_API_BASE (base URL waszego API)
2. Uzgodnić wspólny sekret HMAC i wpisać go u siebie pod nazwą PACKPOINTS_SYNC_SECRET
3. Zaimplementować 5 endpointów opisanych poniżej
Wszystkie endpointy przyjmują POST, Content-Type application/json. Base URL ustawia SayZoo — protect.vet woła {BASE_URL}/{endpointName}.
/packpointsGetBalanceZwraca aktualne saldo PackPoints użytkownika na podstawie jego emaila. Wywoływany przy każdym otwarciu zakładki PackPoints w panelu klienta oraz w kalkulatorze polisy.
protect.vet przechowuje te dane lokalnie jako cache. Jeśli użytkownik nie ma konta w SayZoo — zwróć 404 z code: "user_not_found". protect.vet poinformuje użytkownika żeby się zarejestrował.
Request Body
{
"email": "jan.kowalski@example.com", // znormalizowany (lowercase, trimmed)
"source_app": "protect_vet"
}Response (200 OK)
// Konto istnieje:
{
"ok": true,
"user_id": "sayzoo_user_abc123", // ID użytkownika w SayZoo
"balance": 1500, // łączne saldo PP
"reserved_balance": 100, // zarezerwowane (oczekuje na commit)
"available_balance": 1400 // dostępne = balance - reserved
}
// Konto nie istnieje (email nie zarejestrowany w SayZoo):
HTTP 404
{ "ok": false, "code": "user_not_found", "error": "User not found" }/packpointsGetHistoryZwraca historię transakcji PackPoints użytkownika. Używane w zakładce PackPoints w panelu klienta.
Request Body
{
"email": "jan.kowalski@example.com",
"source_app": "protect_vet",
"limit": 50 // max liczba rekordów
}Response (200 OK)
{
"ok": true,
"transactions": [
{
"id": "tx_abc123",
"type": "earn", // "earn" lub "redeem"
"points": 100, // dodatnie dla earn, ujemne dla redeem
"description": "Zakup na sayzoo.pl - zamówienie #123",
"source": "sayzoo_purchase", // dowolny string
"created_at": "2026-07-15T10:30:00Z",
"balance_after": 1500
}
],
"total_count": 12
}/packpointsReserveRezerwuje punkty przed płatnością za polisę (blokuje availability). Użytkownik wybrał rabat PackPoints w kalkulatorze — points są zablokowane na 30 minut.
external_event_id jest idempotency key — jeśli ta sama wartość przyjdzie drugi raz, zwróć ten sam reservation_id bez duplikowania operacji.
Request Body
{
"external_event_id": "protect_vet:discount_reserved:quote_1721306400000",
"email": "jan.kowalski@example.com",
"protect_user_id": "user_abc123", // ID użytkownika w protect.vet
"quote_id": "quote_1721306400000",
"points": 200, // liczba punktów do zablokowania
"expires_at": "2026-07-18T16:47:00Z", // wygaśnięcie rezerwacji (30 min)
"source_app": "protect_vet"
}Response (200 OK)
{
"ok": true,
"reservation_id": "res_xyz789" // ID rezerwacji — wymagany do commit/release
}/packpointsCommitZatwierdza rezerwację — trwale odlicza zarezerwowane punkty. Wywoływany po potwierdzeniu płatności za polisę.
Idempotentne — external_event_id identyfikuje tę operację unikalnie. Bezpieczne do ponowienia.
Request Body
{
"external_event_id": "protect_vet:discount_committed:policy_abc456",
"reservation_id": "res_xyz789", // z odpowiedzi /packpointsReserve
"policy_id": "policy_abc456", // ID polisy w protect.vet
"payment_id": "pi_stripe_123", // ID płatności Stripe (może być pusty)
"email": "jan.kowalski@example.com",
"source_app": "protect_vet"
}Response (200 OK)
{
"ok": true,
"balance_after": 1200 // saldo po odliczeniu (opcjonalne)
}/packpointsReleaseZwalnia rezerwację — punkty wracają do available_balance. Wywoływany gdy płatność nie doszła do skutku lub użytkownik zrezygnował.
Request Body
{
"external_event_id": "protect_vet:discount_released:quote_1721306400000",
"reservation_id": "res_xyz789",
"email": "jan.kowalski@example.com",
"reason": "payment_failed", // lub "user_cancelled", "expired"
"source_app": "protect_vet"
}Response (200 OK)
{
"ok": true
}/packpointsCreditNalicza punkty za aktywację polisy protect.vet. Wywoływany automatycznie gdy polisa zmienia status na 'active'. Domyślnie 100 PP za polisę (konfigurowalne przez admina protect.vet).
external_event_id jest idempotency key — ta sama polisa może naliczone punkty otrzymać tylko raz. Jeśli external_event_id już istnieje, zwróć ok: true bez duplikowania punktów.
Request Body
{
"external_event_id": "protect_vet:policy_paid:policy_abc456",
"email": "jan.kowalski@example.com",
"protect_user_id": "user_abc123",
"policy_id": "policy_abc456",
"policy_number": "PV-2026-001234", // czytelny numer polisy
"points": 100, // liczba PP do naliczenia
"description": "PackPointy za zakup nowej polisy protect.vet",
"source_app": "protect_vet"
}Response (200 OK)
{
"ok": true,
"balance_after": 1600 // nowe saldo po naliczeniu
}