Dokumentacja API Walaora
Połącz system POS, sklep internetowy lub system wewnętrzny. JSON przez HTTPS, jeden klucz API na integrację.
Uwierzytelnianie
Utwórz klucz w Panel → API i webhooki (plan Biznes lub Enterprise). Wysyłaj go z każdym żądaniem. Klucze są wyświetlane tylko raz; jeśli wyciekną, unieważnij je. Limit: 120 żądań na minutę na klucz.
Authorization: Bearer wl_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxEndpointy
Base URL: https://walaora.com/api/v1
| GET | /programsLista programów lojalnościowych. |
| GET | /customers?phone=0551234567&tag=vipWyszukiwanie klientów (50 na stronę, ?page=2…). ?tag=vip zwraca klientów z tym tagiem; każdy klient zawiera swoje tagi. |
| POST | /customersZapisanie klienta do programu. Treść: { programId, name, phone, email?, marketingConsent?, locale? }. Zwraca 201 po utworzeniu, 200 jeśli klient jest już zapisany. |
| GET | /cards/{serial}Karta według kodu z karty klienta / kodu QR. |
| POST | /cards/{serial}/earnProgramy pieczątkowe: { stamps?: 1–10 }. Programy punktowe: { amount } w walucie przestrzeni roboczej. Opcjonalnie { branchId }. Karty wielu pieczątek: wyślij setId — jeden z zestawów karty. |
| POST | /cards/{serial}/redeemRealizacja jednej dostępnej nagrody lub wyślij {"rewardId"}, aby zrealizować nagrodę z katalogu wycenioną w pieczątkach/punktach. |
| POST | /cards/{serial}/sellPakiety przedpłacone: sprzedaje pakiet, którego użycia trafiają na kartę (płatność przy Twojej kasie). Webhook: package.sold. |
| POST | /cards/{serial}/usePakiety przedpłacone: odejmuje jedno użycie (odmowa, gdy brak lub wygasł). Karty pracownika: zapisuje przywilej w dziennym limicie. Webhooki: package.used, perk.used. |
| GET | /coupons/{code}Sprawdzenie kuponu bez jego użycia: jego oferta, czy można go użyć, a jeśli nie — dlaczego (wykorzystany, wygasły lub wstrzymany). |
| POST | /coupons/{code}/redeemJednorazowe użycie kuponu. Opcjonalnie { amount } (kwota sprzedaży w walucie przestrzeni roboczej) i { branchId }. 409, gdy kupon został już wykorzystany lub oferta się zakończyła. Webhook: coupon.redeemed. |
| GET | /coupon-offersLista ofert kuponowych z wartością, datą końca i informacją, czy można teraz tworzyć kody (usable). |
| POST | /coupon-offers/{id}/couponsTworzy kody oferty. { customerId } daje temu klientowi jeden kod (widoczny na stronie jego karty); albo { count: 1–500 } nieprzypisanych kodów do wydruku lub udostępnienia. 201 z kodami; 409, gdy oferta jest wstrzymana lub zakończona. |
curl -X POST https://walaora.com/api/v1/cards/ABCDE23456/earn \
-H "Authorization: Bearer wl_live_…" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: receipt-10045" \
-d '{"stamps": 1}'Ponawianie i idempotentność
W żądaniach POST wysyłaj nagłówek Idempotency-Key (dowolny unikalny ciąg, np. numer paragonu). Ponowienie z tym samym kluczem w ciągu 24 godzin zwraca pierwotną odpowiedź zamiast dodawać pieczątkę drugi raz.
Błędy
Błędy zwracają treść JSON { error: { code, message } } ze statusem HTTP: 401 nieprawidłowy klucz · 403 plan_required · 404 nie znaleziono · 409 cooldown / no_reward / program_inactive · 422 błąd walidacji · 429 przekroczony limit żądań.
Webhooki
Dodaj endpoint HTTPS w panelu i wybierz zdarzenia. Każde doręczenie to żądanie POST z JSON { id, type, createdAt, data } i nagłówkami: Walaora-Event, Walaora-Delivery oraz Walaora-Signature. Odpowiedz kodem 2xx w ciągu 10 sekund. Nieudane doręczenia są ponawiane po 1 min, 5 min, 30 min, 2 h i 12 h.
Zdarzenia
customer.enrolledcard.earnedreward.unlockedreward.redeemedcard.adjustedcustomer.deletedfeedback.receivedpackage.soldpackage.usedperk.usedcoupon.redeemed
Weryfikacja podpisów (Node.js)
import crypto from "node:crypto";
// rawBody: the exact request body string; header: req.headers["walaora-signature"]
export function verifyWalaora(rawBody, header, secret) {
const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
const t = Number(parts.t);
if (!t || Math.abs(Date.now() / 1000 - t) > 300) return false; // replay window
const expected = crypto.createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex");
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1 ?? ""));
}