protect.vet → sayzoo.pl

Dokumentacja Integracji PackPoints

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.

HMAC SHA-256REST APIIdempotentneJSON

Poniższe wartości muszą być ustawione przez administratora po obu stronach:

ParametrWartość / Opis
X-PackPoints-Appprotect_vet — stały identyfikator aplikacji w każdym nagłówku
PACKPOINTS_SYNC_SECRETWspółdzielony sekret HMAC — musi być taki sam po obu stronach. Ustalić z administratorem protect.vet.
SAYZOO_PACKPOINTS_API_BASEBase 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}.

POST/packpointsGetBalance

Zwraca 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

json
{
  "email": "jan.kowalski@example.com",  // znormalizowany (lowercase, trimmed)
  "source_app": "protect_vet"
}

Response (200 OK)

json
// 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" }

POST/packpointsGetHistory

Zwraca historię transakcji PackPoints użytkownika. Używane w zakładce PackPoints w panelu klienta.

Request Body

json
{
  "email": "jan.kowalski@example.com",
  "source_app": "protect_vet",
  "limit": 50                           // max liczba rekordów
}

Response (200 OK)

json
{
  "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
}

POST/packpointsReserve

Rezerwuje 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

json
{
  "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)

json
{
  "ok": true,
  "reservation_id": "res_xyz789"        // ID rezerwacji — wymagany do commit/release
}

POST/packpointsCommit

Zatwierdza 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

json
{
  "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)

json
{
  "ok": true,
  "balance_after": 1200                 // saldo po odliczeniu (opcjonalne)
}

POST/packpointsRelease

Zwalnia rezerwację — punkty wracają do available_balance. Wywoływany gdy płatność nie doszła do skutku lub użytkownik zrezygnował.

Request Body

json
{
  "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)

json
{
  "ok": true
}

POST/packpointsCredit

Nalicza 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

json
{
  "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)

json
{
  "ok": true,
  "balance_after": 1600                 // nowe saldo po naliczeniu
}
protect.vet × sayzoo.pl