Riferimento API di Walaora
Collega un POS, un e-commerce o un sistema interno. JSON su HTTPS, una chiave API per ogni integrazione.
Autenticazione
Crea una chiave in Dashboard → API e webhook (piano Business o Enterprise). Inviala a ogni richiesta. Le chiavi vengono mostrate una sola volta; revocale se vengono esposte. Limite: 120 richieste al minuto per chiave.
Authorization: Bearer wl_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxEndpoint
Base URL: https://walaora.com/api/v1
| GET | /programsElenca i programmi fedeltà. |
| GET | /customers?phone=0551234567&tag=vipCerca clienti (50 per pagina, ?page=2…). ?tag=vip elenca i clienti con quell’etichetta; ogni cliente include le sue etichette. |
| POST | /customersIscrive un cliente a un programma. Corpo: { programId, name, phone, email?, marketingConsent?, locale? }. Restituisce 201 se creato, 200 se già iscritto. |
| GET | /cards/{serial}Carta tramite il codice sulla carta / QR del cliente. |
| POST | /cards/{serial}/earnProgrammi a timbri: { stamps?: 1–10 }. Programmi a punti: { amount } nella valuta dello spazio di lavoro. Facoltativo { branchId }. Carte multi-timbro: invia setId, una delle serie della carta. |
| POST | /cards/{serial}/redeemRiscatta un premio disponibile, oppure invia {"rewardId"} per riscattare un premio del catalogo con prezzo in timbri/punti. |
| POST | /cards/{serial}/sellPacchetti prepagati: vende un pacchetto i cui utilizzi si aggiungono alla carta (pagamento alla tua cassa). Webhook: package.sold. |
| POST | /cards/{serial}/usePacchetti prepagati: scala un utilizzo (rifiutato se esaurito o scaduto). Carte dipendente: registra il vantaggio entro il limite giornaliero. Webhook: package.used, perk.used. |
| GET | /coupons/{code}Verifica un coupon senza usarlo: la sua offerta, se può essere usato e, in caso contrario, perché (già riscattato, scaduto o in pausa). |
| POST | /coupons/{code}/redeemUsa un coupon una sola volta. { amount } (la vendita, nella valuta dello spazio di lavoro) e { branchId } facoltativi. 409 se già usato o se l’offerta è terminata. Webhook: coupon.redeemed. |
| GET | /coupon-offersElenca le offerte coupon con valore, data di fine e se ora si possono creare codici (usable). |
| POST | /coupon-offers/{id}/couponsCrea codici di un’offerta. { customerId } dà un codice a quel cliente (compare nella pagina della sua carta); oppure { count: 1–500 } codici non assegnati da stampare o condividere. 201 con i codici; 409 se l’offerta è in pausa o terminata. |
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}'Nuovi tentativi e idempotenza
Per le richieste POST, invia un header Idempotency-Key (qualsiasi stringa univoca, ad esempio il numero dello scontrino). Un nuovo tentativo con la stessa chiave entro 24 ore restituisce la risposta originale invece di aggiungere un secondo timbro.
Errori
Gli errori restituiscono un corpo JSON { error: { code, message } } con uno stato HTTP: 401 chiave non valida · 403 plan_required · 404 non trovato · 409 cooldown / no_reward / program_inactive · 422 validazione · 429 limite di richieste superato.
Webhooks
Aggiungi un endpoint HTTPS nella dashboard e scegli gli eventi. Ogni consegna è una POST con JSON { id, type, createdAt, data } e questi header: Walaora-Event, Walaora-Delivery e Walaora-Signature. Rispondi con 2xx entro 10 secondi. Le consegne non riuscite vengono ritentate dopo 1 min, 5 min, 30 min, 2 h e 12 h.
Eventi
customer.enrolledcard.earnedreward.unlockedreward.redeemedcard.adjustedcustomer.deletedfeedback.receivedpackage.soldpackage.usedperk.usedcoupon.redeemed
Verifica delle firme (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 ?? ""));
}