Entrar no painel
Índice

(09) Receber pagamentos

Cupões

Descontos em percentagem ou valor fixo, aplicados pela loja ou escritos pelo comprador no checkout, e nas subscrições.

O que é um cupão

Um cupão é um código que dá um desconto: uma percentagem (de 1 a 99) ou um valor fixo numa moeda, que só vale nessa moeda. Cria-se no painel, em Cupões, ou pela API, e é de um modo: um cupão de teste não vale em produção.

  • O código é único por comerciante e por modo, com letras, números, - e _, e guarda-se em maiúsculas.
  • Tem, se quiseres, um limite de usos (max_redemptions) e uma data de fim (expires_at).
  • O desconto não muda depois de criado. Mudam o nome, o limite, a data de fim e o ativo; um desconto novo é um cupão novo. Um cupão não se apaga: desativa-se, e quem já o tem fica com ele.
  • Em kwanzas, o desconto de uma percentagem arredonda para baixo, ao kwanza inteiro. Um desconto que dê zero, ou que leve o valor todo, é recusado.
Terminal
curl -s "$VIBRA_API_URL/v1/coupons" \
  -H "Authorization: Bearer $VIBRA_SECRET_KEY" \
  -H "Idempotency-Key: cupao-bemvindo10" \
  -H "Content-Type: application/json" \
  -d '{"code": "BEMVINDO10", "name": "Boas-vindas", "percent_off": 10, "duration": "repeating", "duration_cycles": 3, "max_redemptions": 100}'
201 Created
{
  "id": "cpn_test_8Kq2Lm4Rt8Vx1Zb6Nc3Kd0Ab",
  "object": "coupon",
  "mode": "test",
  "code": "BEMVINDO10",
  "name": "Boas-vindas",
  "percent_off": 10,
  "amount_off": null,
  "duration": "repeating",
  "duration_cycles": 3,
  "max_redemptions": 100,
  "times_redeemed": 0,
  "expires_at": null,
  "active": true,
  "valid": true,
  "metadata": {},
  "created_at": "2026-11-29T08:55:00Z",
  "updated_at": "2026-11-29T08:55:00Z"
}

GET /v1/coupons lista-os (com ?code= para procurar um), GET /v1/coupons/cpn_... lê um, e PATCH /v1/coupons/cpn_... muda o que se pode mudar. Um código repetido dá 409 codigo_repetido.

Aplicar um cupão

ComoO que se faz
A tua loja aplica-ocoupon na sessão, com o código (ou o cpn_...). Um cupão que não serve (não existe, desativado, expirado, esgotado, noutra moeda, ou que não desconta neste valor) dá 422 cupao_invalido.
O comprador escreve-oallow_promotion_codes: true na sessão, ou a caixa Aceitar códigos de desconto num link de cobrança. O checkout mostra o campo do código, com o preço riscado e o total novo.
Terminal
curl -s "$VIBRA_API_URL/v1/checkout/sessions" \
  -H "Authorization: Bearer $VIBRA_SECRET_KEY" \
  -H "Idempotency-Key: pedido-1042" \
  -H "Content-Type: application/json" \
  -d '{"amount": 1500000, "currency": "AOA", "description": "Vestido de capulana", "coupon": "BEMVINDO10"}'
Na sessão
"amount": {"amount": 1500000, "currency": "AOA"},
"discount": {
  "coupon": {"id": "cpn_test_8Kq2...", "code": "BEMVINDO10", "name": "Boas-vindas", "percent_off": 10,
             "amount_off": null, "duration": "repeating", "duration_cycles": 3},
  "amount": {"amount": 150000, "currency": "AOA"}
},
"allow_promotion_codes": false

O amount da sessão continua a ser o preço; o comprador paga amount menos discount.amount. Um pagamento leva um cupão só, e os dois modos não vão juntos.

Com os SDK
// Go
cupao, err := cliente.CreateCoupon(ctx, &vibra.CouponParams{
	Code: "BEMVINDO10", PercentOff: 10, Duration: vibra.CouponRepeating, DurationCycles: 3,
})
sessao, err := cliente.CreateCheckoutSession(ctx, &vibra.CheckoutSessionParams{
	Amount: 1500000, Currency: vibra.AOA, Description: "Vestido", AllowPromotionCodes: true,
})

// JavaScript
const cupao = await vibra.createCoupon({ code: "BEMVINDO10", percent_off: 10, duration: "repeating", duration_cycles: 3 });
const sessao = await vibra.createCheckoutSession({ amount: 1500000n, currency: "AOA", description: "Vestido", allow_promotion_codes: true });

O dinheiro, a taxa e o limite

  • O pagamento nasce com o valor descontado. O payment.succeeded traz esse valor em amount, o discount com o cupão, e a fee, que é sobre o valor pago, depois do desconto.
  • O recibo mostra o preço, a linha do desconto e o código.
  • O limite conta as sessões pagas com o cupão e as abertas que ainda se podem pagar: dois compradores com o último uso, um fica com ele e o outro é recusado. Uma sessão que expira devolve o uso. times_redeemed são as pagas.

Numa subscrição

durationO desconto vale
onceNo primeiro ciclo. As renovações cobram o preço cheio.
repeatingNos primeiros duration_cycles ciclos (de 2 a 1000), contando com o primeiro, e a seguir o preço cheio.
foreverEm todos os ciclos.

A subscrição guarda o cupão em discount (coupon, amount e cycles, nulo quando são todos), e vale o que o comprador aceitou mesmo que depois desatives o cupão. Num pagamento único, qualquer cupão vale uma vez. Um cupão não vai com o first_cycle_amount de um plano.

Subscrições semanais com cartão

O cartão renova-se sozinho no gateway, que conta os descontos repetidos em meses. Por isso, uma subscrição semanal que se pode pagar com cartão recusa um cupão repeating; o once e o forever servem.