Começar
- Crie uma chave secreta no console (
clube-console.usecoins.tech› Mobilidade › Clube no app › Integração). Ela fica só no seu servidor. - Abra o clube: seu servidor chama
POST /v1/sessionse o app abre olaunchUrlnuma webview. - Envie eventos (ex.: corrida concluída) com
POST /v1/events. O clube credita as moedas pelas suas regras.
Endereço base: https://clube-api.usecoins.tech. Toda chamada leva a chave no cabeçalho:
Authorization: Bearer ck_live_…
Teste a chave: GET /v1/ping devolve o clube, o ambiente e o plano.
Chaves
| Tipo | Onde usar | O que pode |
|---|---|---|
ck_live_… secreta | Só no servidor do app | Abrir sessões, enviar eventos, consultar saldo (conforme as permissões da chave) |
pk_live_… pública | Pode ir dentro do app (SDK) | Só ler a marca (GET /v1/config) |
Nunca coloque a chave secreta dentro do aplicativo. Quem tiver a chave abre o clube como qualquer usuário. Guardamos só um resumo (hash): a chave inteira aparece uma única vez, ao ser criada. Revogar vale na hora.
Abrir o clube para um usuário
Permissão sessions:write. O usuário não tem senha: a identidade é a do seu app. O primeiro acesso cria o cadastro dele no clube.
{
"user": {
"id": "8812", // ID do usuário no seu app (obrigatório)
"audience": "PASSENGER", // público: PASSENGER, DRIVER ou outro criado no console
"name": "Paula Souza", // opcional
"phone": "+5531999990000" // opcional
},
"startPath": "/app/cupons" // opcional: tela inicial (começa com /app)
}
Resposta 201:
{
"launchUrl": "https://clube.usecoins.tech/clube/entrar#t=…",
"launchToken": "…",
"expiresAt": "2026-11-07T12:02:00.000Z",
"user": { "id": "…", "externalUserId": "8812", "audience": "PASSENGER", "created": true }
}
O link vale 2 minutos e uma vez só: peça um novo a cada abertura. A sessão no clube dura 1 dia. O mesmo id com outro audience é outra pessoa (ex.: o passageiro e o motorista).
Webview e avisos para o app
Abra o launchUrl numa webview com JavaScript e cookies ligados. O clube manda avisos para o app como JSON { "source": "clube-coins", "type": … }:
| Aviso | Quando | O que o app faz |
|---|---|---|
ready | Clube aberto (path) | Esconder o carregando |
navigate | Troca de tela (path) | Opcional (ex.: estatística) |
session_expired | Link usado/vencido ou sessão terminou | Pedir um launchUrl novo e reabrir |
close | Pessoa tocou em "Voltar ao app" | Fechar a webview |
Como receber
| Plataforma | Canal |
|---|---|
| Android | addJavascriptInterface(obj, "ClubeCoinsAndroid") com @JavascriptInterface postMessage(String json) |
| iOS (WKWebView) | userContentController.add(handler, name: "clubeCoins") |
| React Native | <WebView onMessage={…} /> (ReactNativeWebView.postMessage) |
| Flutter | JavaScriptChannel(name: 'ClubeCoinsFlutter', …) |
Os SDKs (Android primeiro) fazem tudo isso por você: pedem o link ao seu servidor, abrem a webview e tratam os avisos.
Eventos
Permissão events:write. Envie quando algo acontece no app. Idempotente: o mesmo type + id nunca credita duas vezes (a repetição responde 200 com "duplicate": true).
{
"type": "ride.completed", // ex.: ride.completed, order.delivered
"id": "OS-10293", // ID único do evento no seu app
"user": { "id": "8812", "audience": "PASSENGER" },
"amountCents": 2550, // opcional: valor em centavos
"distanceMeters": 7300, // opcional
"occurredAt": "2026-11-07T11:58:00-03:00", // opcional
"data": { "cidade": "BH" } // opcional: guardado junto
}
Resposta: { "status": "CREDITED" | "NO_REWARD" | "REJECTED", "coins": 25, "reason": null, "duplicate": false, … }.
ride.completed usa as Campanhas de Coins do clube; os outros tipos usam as Regras de ganho (fixo e/ou por R$, valor mínimo, teto por dia).
Saldo do usuário
Permissão users:read. Para mostrar o saldo fora do clube (ex.: no menu do app).
{ "user": { "externalUserId": "8812", "audience": "PASSENGER" }, "balance": 48,
"coinName": { "singular": "Moeda 53", "plural": "Moedas 53" },
"expiring": [{ "expiresAt": "2027-02-04T…", "amount": 48 }] }
Marca do clube
Funciona com a chave pública. Devolve nome, cores, logo, nome da moeda e públicos — útil para o app pintar o botão de entrada.
Webhooks
Cadastre o endereço (https) e gere o segredo no console. Avisos enviados hoje: coins.earned (moedas creditadas) e webhook.test. Falhas são reenviadas.
Cabeçalhos: Clube-Event e Clube-Signature: t=<unix>,v1=<hmac>, onde hmac = HMAC-SHA256(segredo, t + "." + corpo) em hexadecimal. Confira a assinatura e recuse avisos com t muito antigo.
// Node.js
const [t, v1] = header.split(',').map(p => p.split('=')[1]);
const ok = crypto.timingSafeEqual(
Buffer.from(v1, 'hex'),
crypto.createHmac('sha256', SEGREDO).update(`${t}.${corpoBruto}`).digest());
Erros e limites
Erros vêm como { "error": "mensagem", "code": "CODIGO" }.
| HTTP | code | O que fazer |
|---|---|---|
| 401 | INVALID_KEY | Chave ausente, errada, vencida ou revogada |
| 403 | CLUB_SUSPENDED | Clube suspenso: fale com o Clube Coins |
| 403 | SECRET_KEY_REQUIRED / SCOPE_MISSING | Use a chave secreta com a permissão certa |
| 400 | AUDIENCE, START_PATH… | Corrija o corpo da chamada |
| 403 | USER_BLOCKED | Usuário bloqueado no console |
| 429 | RATE_LIMITED | Espere Retry-After segundos (cabeçalhos RateLimit-*) |
| 429 | QUOTA_EXCEEDED / MAU_LIMIT | Limite do plano no mês |