Integração Clube — App do Consumidor
Guia para desenvolvedores que vão construir um aplicativo ou portal web para o consumidor final integrado ao EloFiel. O consumidor usa este app para ver seu saldo, histórico e QR Code.
Autenticação
A API Clube usa JWT Bearer — sem X-Api-Key. O fluxo de login usa PIN enviado por WhatsApp ou e-mail:
1. POST /clube/auth/solicitar-pin → envia PIN ao cliente
2. POST /clube/auth/login → troca PIN por JWT
3. (manter token vivo) POST /clube/auth/renovar
Exemplo completo de login
- JavaScript
const BASE = 'https://api.elofiel.com.br/api/v1';
// 1. Solicitar PIN
async function solicitarPin(cpf, canal = 'whatsapp') {
const res = await fetch(`${BASE}/clube/auth/solicitar-pin`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ cpf, canal }),
});
return res.json(); // { dados: { destinoMascarado, whatsappIndisponivel } }
}
// 2. Login com PIN
async function loginComPin(cpf, pin) {
const res = await fetch(`${BASE}/clube/auth/login`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ cpf, pin }),
});
const data = await res.json();
if (!data.sucesso) throw new Error(data.erros[0] ?? data.mensagem);
return data.dados; // { token, expiraEm, nome, cpf, qrToken }
}
// 3. Uso posterior — bearer token
async function getSaldo(token) {
const res = await fetch(`${BASE}/clube/saldo`, {
headers: { 'Authorization': `Bearer ${token}` },
});
return res.json();
}
Tratamento do WhatsApp indisponível
Se o número do cliente não estiver no WhatsApp, whatsappIndisponivel: true é retornado. Ofereça o canal e-mail como fallback:
const { dados } = await solicitarPin(cpf, 'whatsapp');
if (dados.whatsappIndisponivel) {
// Oferecer e-mail como alternativa
await solicitarPin(cpf, 'email');
}
Exibindo saldo
const { dados: lojas } = await getSaldo(token);
for (const loja of lojas) {
console.log(`${loja.lojaNome}: R$ ${loja.saldoCashback.toFixed(2)} disponível`);
if (loja.saldoPendente > 0) {
console.log(` + R$ ${loja.saldoPendente.toFixed(2)} pendente`);
}
}
Exiba saldoPendente separado e com aviso de que não está disponível para resgate ainda. Misturar os dois valores confunde o cliente.
Histórico paginado
async function getHistorico(token, pagina = 1, tamanho = 20) {
const res = await fetch(
`${BASE}/clube/historico?pagina=${pagina}&tamanho=${tamanho}`,
{ headers: { 'Authorization': `Bearer ${token}` } }
);
const { dados } = await res.json();
return dados; // { paginacao: { pagina, tamanho, totalRegistros }, data: [...] }
}
QR Code
Gere o QR Code a partir do qrToken recebido no login. O cliente apresenta o QR no PDV para ser identificado sem digitar o CPF.
import QRCode from 'qrcode';
// qrToken vem do login: data.dados.qrToken
const qrDataUrl = await QRCode.toDataURL(qrToken);
document.getElementById('qr-img').src = qrDataUrl;
Para gerar um novo QR (ex.: botão "Atualizar QR" por segurança):
async function renovarQr(token) {
const res = await fetch(`${BASE}/clube/cliente/renovar-qr`, {
method: 'POST',
headers: { 'Authorization': `Bearer ${token}` },
});
const { dados } = await res.json();
return dados.qrToken; // novo UUID
}
Rate limiting
| Endpoint | Limite |
|---|---|
POST /solicitar-pin | 3 req/min por IP |
POST /login | 5 req/min por IP |
Ao receber HTTP 429, mostre: "Muitas tentativas. Aguarde antes de tentar novamente."
Checklist de implementação
- Solicitar PIN por WhatsApp; oferecer fallback por e-mail se
whatsappIndisponivel: true - Armazenar o JWT de forma segura (ex.:
SecureStorageem mobile,httpOnly cookieem web) - Renovar token antes de expirar (< 7 dias):
POST /clube/auth/renovar - Exibir
saldoCashbackesaldoPendenteseparados - Gerar QR Code a partir do
qrToken - Tratar HTTP 429 com mensagem amigável
- Tratar HTTP 401 redirecionando para login