Pular para o conteúdo
walaoraWalaora

Referência da API do Walaora

Conecte um PDV, uma loja virtual ou um sistema interno. JSON via HTTPS, uma chave de API por integração.

Só envie dados de clientes com o conhecimento deles e defina marketingConsent como true somente quando o cliente tiver concordado explicitamente.

Autenticação

Crie uma chave em Painel → API e webhooks (plano Empresarial ou Corporativo). Envie-a em todas as requisições. As chaves são exibidas uma única vez; revogue-as se forem expostas. Limite: 120 requisições por minuto por chave.

Authorization: Bearer wl_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Endpoints

Base URL: https://walaora.com/api/v1

GET/programs

Lista os programas de fidelidade.

GET/customers?phone=0551234567&tag=vip

Busca clientes (50 por página, ?page=2…). ?tag=vip lista os clientes com essa etiqueta; cada cliente inclui suas etiquetas.

POST/customers

Cadastra um cliente em um programa. Corpo: { programId, name, phone, email?, marketingConsent?, locale? }. Retorna 201 quando criado e 200 se o cliente já estiver cadastrado.

GET/cards/{serial}

Cartão pelo código no cartão / QR do cliente.

POST/cards/{serial}/earn

Programas de carimbos: { stamps?: 1–10 }. Programas de pontos: { amount } na moeda do espaço de trabalho. Opcional: { branchId }. Cartões multisselos: envie setId, uma das séries do cartão.

POST/cards/{serial}/redeem

Resgata uma recompensa disponível, ou envie {"rewardId"} para resgatar uma recompensa do catálogo com preço em carimbos/pontos.

POST/cards/{serial}/sell

Pacotes pré-pagos: vende um pacote e soma seus usos ao cartão (o pagamento é feito no seu caixa). Webhook: package.sold.

POST/cards/{serial}/use

Pacotes pré-pagos: desconta um uso (recusado se vazio ou expirado). Cartões de funcionário: registra o benefício dentro do limite diário. Webhooks: package.used, perk.used.

GET/coupons/{code}

Verifica um cupom sem usá-lo: sua oferta, se pode ser usado e, se não, por quê (resgatado, expirado ou pausado).

POST/coupons/{code}/redeem

Usa um cupom uma vez. Opcional: { amount } (a venda, na moeda do espaço de trabalho) e { branchId }. 409 quando já foi usado ou a oferta foi encerrada. Webhook: coupon.redeemed.

GET/coupon-offers

Lista as ofertas de cupom com valor, data de término e se é possível criar códigos agora (usable).

POST/coupon-offers/{id}/coupons

Cria códigos de uma oferta. { customerId } dá um código a esse cliente (aparece na página do cartão dele); ou { count: 1–500 } códigos sem cliente para imprimir ou compartilhar. 201 com os códigos; 409 se a oferta estiver pausada ou tiver terminado.

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}'

Novas tentativas e idempotência

Em requisições POST, envie um cabeçalho Idempotency-Key (qualquer texto único, por exemplo o número do seu cupom). Repetir a requisição com a mesma chave em até 24 horas retorna a resposta original, em vez de carimbar duas vezes.

Erros

Os erros retornam um corpo JSON { error: { code, message } } com um status HTTP: 401 chave inválida · 403 plan_required · 404 não encontrado · 409 cooldown / no_reward / program_inactive · 422 validação · 429 limite de requisições excedido.

Webhooks

Adicione um endpoint HTTPS no painel e escolha os eventos. Cada entrega é um POST com JSON { id, type, createdAt, data } e estes cabeçalhos: Walaora-Event, Walaora-Delivery e Walaora-Signature. Responda com 2xx em até 10 segundos. Entregas com falha são reenviadas após 1 min, 5 min, 30 min, 2 h e 12 h.

Eventos

Verificação de assinaturas (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 ?? ""));
}