Fidelidade
Consultar e operar o programa de fidelidade de um cliente — saldo, extrato, cupons, crédito, débito livre e resgate. Idempotência e resolução por phone/external_id.
A API de Fidelidade expõe o programa, o saldo, o extrato e os cupons de um cliente, e permite creditar/debitar pontos e validar/resgatar cupons.
- Leituras exigem o escopo
loyalty:read. - Escritas exigem
loyalty:write. - Uma chave
loyalty:readchamando um endpoint de escrita recebe403 INSUFFICIENT_SCOPE.
Todos os endpoints usam o mesmo envelope de erro do restante da API:
{ "error": { "code": "...", "message": "..." } }. A referência completa de
schemas está no OpenAPI.
Consulta on-demand (polling)
Hoje o ERP consulta o saldo quando precisa (polling). Não há webhook que
empurre mudanças de saldo da OnmIA para o ERP — esse push (order.created para
fidelidade) está no roadmap (UCP-INT-v121-W-C). Por ora, leia o saldo
on-demand via GET /loyalty/balance.
Resolução do cliente
As rotas que operam sobre um cliente o localizam por phone ou
external_id (a chave do cliente no seu ERP, em customers.external_id). A
busca é somente leitura (find-only): a fidelidade atua sobre um cliente já
existente — nunca cria cliente. Cliente não encontrado retorna
404 CUSTOMER_NOT_FOUND.
phone: aceito em qualquer formato (+55 (37) 99112-9034,37991129034,5537991129034); o servidor normaliza para E.164 BR e tolera a variação do nono dígito.external_id: tem precedência quando enviado; se não casar e você também mandouphone, cai para a busca por telefone.
Leitura (loyalty:read)
Programa + níveis
curl -sS https://api.onmia.com.br/integration/v1/loyalty/program \
-H "X-API-Key: $ONMIA_API_KEY"Retorna o programa ativo (merchant-wide) e os tiers. Nenhum programa ativo:
404 NO_PROGRAM.
Saldo do cliente
curl -sS "https://api.onmia.com.br/integration/v1/loyalty/balance?phone=5537991129034" \
-H "X-API-Key: $ONMIA_API_KEY"{
"customer_id": "6c57c2e8-…",
"enrolled": true,
"points_balance": 320,
"points_lifetime": 1180,
"cashback_balance": 0,
"tier": { "name": "Prata", "level": 2, "multiplier": 1.2 },
"referral_code": "JADER10"
}Cliente existente mas não inscrito: enrolled: false com saldos zerados e
tier: null. Falta phone/external_id: 400 VALIDATION_ERROR.
Extrato
curl -sS "https://api.onmia.com.br/integration/v1/loyalty/transactions?phone=5537991129034&limit=50" \
-H "X-API-Key: $ONMIA_API_KEY"limit de 1 a 100 (default 50), mais recente primeiro. Cada item traz type,
points, reason, order_id, created_at.
Cupons do cliente
curl -sS "https://api.onmia.com.br/integration/v1/loyalty/coupons?external_id=ERP-CLI-3310" \
-H "X-API-Key: $ONMIA_API_KEY"Lista os cupons ativos visíveis ao cliente. A lista honra o escopo de loja da
chave: cupons de loja só aparecem se a loja estiver no store_ids da chave;
cupons merchant-wide (store_id: null) aparecem sempre.
Escrita (loyalty:write)
Creditar / debitar pontos (idempotente)
curl -sS https://api.onmia.com.br/integration/v1/loyalty/points \
-H "X-API-Key: $ONMIA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"phone": "5537991129034",
"points": 100,
"reason": "Bonus aniversario",
"idempotency_key": "erp-bonus-2026-06-13-3310"
}'points é um inteiro com sinal (+ credita, - debita; não pode ser zero) —
alternativamente type (credit/debit) + amount positivo.
| Campo | Obrigatório | Regras |
|---|---|---|
phone / external_id | sim (um dos dois) | Resolução do cliente. |
points | sim* | Inteiro com sinal. *Alternativa: type + amount. Não pode ser zero. |
reason | não | Descrição do lançamento. |
idempotency_key | recomendado | Mesma chave reaplicada = um único efeito (replay). |
order_id | não | UUID do pedido associado ao débito (resgate). |
O idempotency_key torna o lançamento seguro para retry: reenviar a mesma chave
não credita/debita de novo (retorna idempotent_replay: true com o saldo
inalterado).
{
"new_balance": 420,
"points_applied": 100,
"idempotent_replay": false,
"transaction": { "id": "…", "points": 100, "created_at": "2026-06-13T14:10:00.000Z" }
}Débito livre vs. resgate:
- Débito livre (
points < 0semorder_id) = ajuste manual de saldo (ex.: correção, estorno). Débito maior que o saldo →422 INSUFFICIENT_BALANCE. - Débito com
order_id= resgate de pontos vinculado a um pedido.
Corrida concorrente no crédito: 409 CONFLICT (re-tente).
O saldo de pontos é um valor financeiro. Use sempre idempotency_key por
lançamento — retries de rede nunca devem duplicar crédito ou débito.
Validar cupom
curl -sS https://api.onmia.com.br/integration/v1/loyalty/coupons/validate \
-H "X-API-Key: $ONMIA_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "code": "BEMVINDO10", "phone": "5537991129034", "order_total": 90.0 }'Retorna { valid, discount, reason, coupon }. Não consome o cupom — só checa
as regras (validade, mínimo, limites). phone/external_id são opcionais
(validação anônima permitida; informe o cliente quando o cupom tiver limite por
cliente). Cupom inválido → valid: false com reason; cupom inexistente →
404 COUPON_INVALID.
Resgatar cupom (idempotente)
curl -sS https://api.onmia.com.br/integration/v1/loyalty/coupons/redeem \
-H "X-API-Key: $ONMIA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"code": "BEMVINDO10",
"phone": "5537991129034",
"order_id": "949e4706-c108-4a6c-b9cd-4e89c043935d",
"discount": 8.8,
"idempotency_key": "erp-redeem-4412"
}'Marca o uso do cupom para o cliente + pedido. Idempotente por
(cupom, order_id). Resposta: { redeemed, idempotent_replay, discount_applied }.
- Cupom de loja fora do escopo da chave:
403 FORBIDDEN_STORE. - Cupom inexistente:
404 COUPON_INVALID. - Cupom inativo/expirado ou limite atingido:
422 COUPON_INVALID.
Códigos de erro da fidelidade
| Código | Status | Significado |
|---|---|---|
VALIDATION_ERROR | 400 | Falta phone/external_id, payload inválido, points zero. |
CUSTOMER_NOT_FOUND | 404 | Cliente não localizado (find-only — a API não cria cliente). |
NO_PROGRAM | 404 | Nenhum programa de fidelidade ativo. |
INSUFFICIENT_BALANCE | 422 | Débito maior que o saldo de pontos. |
COUPON_INVALID | 404/422 | Cupom inexistente (404) ou inativo/expirado/limite atingido (422). |
FORBIDDEN_STORE | 403 | Cupom de loja fora do escopo da chave (resgate). |
CONFLICT | 409 | Corrida concorrente no crédito de pontos; re-tente. |
INSUFFICIENT_SCOPE | 403 | Chave sem loyalty:read/loyalty:write para a operação. |
POINTS_UNAVAILABLE / COUPON_UNAVAILABLE | 503 | Indisponível por falha transitória; re-tente com backoff. |