Descontos e cupons

Aplicar cupom

Aplica um cupom a uma assinatura que já está ativa. Serve para desconto recorrente (percentual ou em reais por algumas cobranças) e para período grátis — por exemplo, "indicou um amigo, ganhou um mês".

POST/v1/subscriptions/:subscriptionId/coupons
Base URL Produção:https://api.validapay.com.br
Base URL Sandbox:https://sandbox.validapay.com.br

Como usar para indicação ou cortesia: crie uma vez um cupom do tipo EXTRA_PERIOD (em Cupons), por exemplo INDICACAO com 1 mês. Quando o cliente ganhar o benefício, aplique esse código na assinatura dele.

A partir de quando vale (applyTo):

  • NEXT_CYCLE (padrão): a cobrança atual não muda; o cupom vale a partir da próxima. No período grátis, a próxima cobrança é adiada.
  • CURRENT_CYCLE: vale já para a cobrança atual.
    • Se ela ainda não foi gerada, o cupom entra quando for gerada.
    • Se já foi gerada por Pix ou boleto e está em aberto, ela é reemitida. No desconto, com o valor novo; no período grátis, com o mesmo valor e o vencimento adiado pelo período.
    • Se ela está vencida: no desconto, envie um dueDate posterior a hoje, que vira o vencimento da nova cobrança. No período grátis, não envie dueDate: a nova cobrança vence hoje mais o período do cupom.

Regras:

  • Uma assinatura tem um cupom por vez. Se já houver cupom em vigor, a resposta é COUPON_ALREADY_ACTIVE; aplique o próximo quando ele terminar.
  • Cupom e desconto recorrente (Aplicar desconto em uma cobrança com cycles) não valem juntos. Com desconto recorrente em vigor, encerre-o antes de aplicar o cupom.
  • Valem as mesmas regras do checkout: validade, limite de usos, produtos permitidos e primeiro uso.
  • CURRENT_CYCLE só reemite cobrança de Pix ou boleto. Se a cobrança atual é de cartão e já foi gerada, ou se já foi paga, use NEXT_CYCLE.
  • Um desconto manual já lançado na cobrança atual impede o cupom de desconto com CURRENT_CYCLE. Remova o desconto ou use NEXT_CYCLE.
  • dueDate só vale quando a cobrança atual é reemitida com desconto. Com cupom de período grátis, ou com a cobrança atual ainda não emitida, a resposta é DUE_DATE_NOT_APPLICABLE.
  • No boleto, o boleto antigo não é cancelado ao reemitir, a menos que você envie cancelOpenBoleto: true.
  • No Pix Automático, o valor de um débito não muda depois que a instrução foi enviada ao banco do pagador. Se a instrução do ciclo onde o cupom começaria já foi enviada, a resposta é PIX_AUTOMATICO_INSTRUCTED. Isso vale também para NEXT_CYCLE, quando o débito da próxima cobrança já foi instruído.

Erros:

  • COUPON_ALREADY_ACTIVE: já há um cupom em vigor na assinatura.
  • COUPON_NOT_FOUND, COUPON_INACTIVE, COUPON_NOT_STARTED, COUPON_EXPIRED, COUPON_EXHAUSTED, PRODUCT_NOT_ELIGIBLE, COUPON_FIRST_TIME_ONLY: o cupom não vale para esta assinatura.
  • COUPON_NOT_APPLICABLE: a assinatura é uma venda avulsa (ONE_TIME), ou o cupom é só para cobranças avulsas.
  • SUBSCRIPTION_NOT_CHANGEABLE: a assinatura está encerrada.
  • CYCLE_ALREADY_SETTLED: a cobrança onde o cupom começaria já foi paga.
  • NO_OPEN_DOCUMENT: com CURRENT_CYCLE, a cobrança atual já foi gerada e não tem Pix ou boleto em aberto para reemitir.
  • COUPON_CONFLICTS_WITH_DISCOUNT: com CURRENT_CYCLE, a cobrança atual já tem desconto manual.
  • COUPON_CONFLICTS_WITH_DISCOUNT_SCHEDULE: a assinatura tem desconto recorrente em vigor.
  • DUE_DATE_REQUIRED: cupom de desconto com CURRENT_CYCLE, a cobrança atual está vencida e o dueDate não foi enviado.
  • DUE_DATE_NOT_APPLICABLE: dueDate enviado com cupom de período grátis, ou com a cobrança atual ainda não emitida.
  • PIX_AUTOMATICO_INSTRUCTED: a instrução de débito do ciclo já foi enviada ao banco.
  • CYCLE_BEING_PROCESSED: a cobrança está sendo processada agora; tente de novo em alguns minutos.

Para um abatimento pontual em uma cobrança, sem cupom, use Aplicar desconto em uma cobrança.

Envie dryRun: true para ver o efeito sem aplicar.

Authorizations

bearer

Authorization

string obrigatório

Cabeçalho de autenticação Bearer no formato Bearer {{token}} onde {{token}} é o seu token OAuth2.

Escopos requeridos

subscriptions/write

Path Parameters

subscriptionIdstringobrigatório
ID da assinatura (ex: sub_xxx) - required

Body

application/json

Content-Type:application/json
JSON
{
    "code": "INDICACAO", 
    "applyTo": "NEXT_CYCLE", 
    "dueDate": "2026-10-05", 
    "cancelOpenBoleto": false, 
    "dryRun": false 
}

Schema

codestringobrigatório
Código do cupom
applyTostringopcional
NEXT_CYCLE: a partir da próxima cobrança. CURRENT_CYCLE: já na cobrança atual (padrão NEXT_CYCLE)
Valores aceitos:NEXT_CYCLECURRENT_CYCLE
dueDatestringopcional
Vencimento da cobrança reemitida com desconto (YYYY-MM-DD), posterior a hoje. Obrigatório com CURRENT_CYCLE quando a cobrança atual está vencida. Não envie no período grátis nem quando a cobrança atual ainda não foi emitida
Regra:^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$
cancelOpenBoletobooleanopcional
true: cancela o boleto em aberto ao reemitir. Só com CURRENT_CYCLE
dryRunbooleanopcional
true: só simula
const url = 'https://sandbox.validapay.com.br/v1/subscriptions/:subscriptionId/coupons';

const options = {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer {{token}}',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    "code": "INDICACAO", 
    "applyTo": "NEXT_CYCLE", 
    "dueDate": "2026-10-05", 
    "cancelOpenBoleto": false, 
    "dryRun": false 
})
};

fetch(url, options)
  .then(res => res.json())
  .then(json => console.log(json))
  .catch(err => console.error(err));

Response Examples

200cupom aplicado▾
JSON
{
    "success": true, 
    "type": "COUPON_APPLIED", 
    "subscriptionId": "sub_xxx", 

    "coupon": { 
        "code": "INDICACAO", 
        "discountType": "EXTRA_PERIOD", 
        "discountValue": 1, 
        "extraPeriodUnit": "MONTHS", 
        "maxCycles": 1 
    },
    "applyTo": "NEXT_CYCLE", 
    "firstCycleNumber": 4, 
    "action": "SHIFT_UNBILLED_CYCLES", 
    "currentDueDate": null, 
    "newDueDate": null, 
    "reissuesOpenCharge": false, 
    "redemptionId": "red_xxx", 
    "reissued": null, 
    "shiftedCycles": [ 
        {
            "cycleNumber": 4, 
            "previousChargeDate": "2026-11-10", 
            "chargeDate": "2026-12-10" 
        }
    ],
    "repricedCycles": [], 
    "restoredStatus": null 
}

Campos da resposta

successboolean
true quando o cupom foi aplicado
typestring
COUPON_APPLIED: aplicado. PREVIEW: simulação (dryRun)
Valores aceitos:COUPON_APPLIEDPREVIEW
subscriptionIdstring
ID da assinatura
couponobject
Cupom aplicado
applyTostring
A partir de qual cobrança o cupom vale
Valores aceitos:CURRENT_CYCLENEXT_CYCLE
firstCycleNumbernumber
Primeiro ciclo afetado pelo cupom
actionstring
O que foi feito. APPLIED_ON_BILLING: vale quando a cobrança for gerada. SHIFT_UNBILLED_CYCLES: próximas cobranças remarcadas. REISSUE_WITH_DISCOUNT: cobrança atual reemitida com desconto. REISSUE_WITH_NEW_DUE_DATE: cobrança atual reemitida com vencimento adiado
Valores aceitos:APPLIED_ON_BILLINGSHIFT_UNBILLED_CYCLESREISSUE_WITH_DISCOUNTREISSUE_WITH_NEW_DUE_DATE
currentDueDateobject
Vencimento da cobrança atual antes do cupom
Regra:date
newDueDateobject
Vencimento da cobrança atual depois do cupom
Regra:date
reissuesOpenChargeboolean
true quando a cobrança atual é reemitida
redemptionIdstring
ID do uso do cupom nesta assinatura
reissuedobject
Cobrança reemitida no lugar da que estava em aberto. Só com CURRENT_CYCLE; veja o exemplo "200 cupom na cobrança atual"
shiftedCyclesarray[1]
Cobranças agendadas que foram adiadas pelo período grátis
repricedCyclesarray[0]
Cobranças agendadas que tiveram o valor recalculado com o desconto
restoredStatusobject
ACTIVE quando a nova data tirou a assinatura da inadimplência
200cupom na cobrança atual▾
JSON
{
    "success": true,
    "type": "COUPON_APPLIED",
    "subscriptionId": "sub_xxx",

    "coupon": { 
        "code": "VOLTA10", 
        "discountType": "PERCENTAGE", 
        "discountValue": 10, 
        "extraPeriodUnit": null, 
        "maxCycles": 3 
    },
    "applyTo": "CURRENT_CYCLE",
    "firstCycleNumber": 3,
    "action": "REISSUE_WITH_DISCOUNT",
    "currentDueDate": "2026-11-10",
    "newDueDate": "2026-11-10",
    "reissuesOpenCharge": true,
    "redemptionId": "red_xxx",
    "reissued": { 
        "chargeId": "cha_xxx", 
        "paymentType": "BOLETO", 
        "dueDate": "2026-11-10", 
        "amount": 90, 
        "replacedChargeId": null, 
        "keptOpenChargeId": "cha_yyy", 
        "warning": "O boleto anterior continua pagável; oriente o cliente a usar apenas a nova cobrança", 
        "payment": { 
            "transactionId": "9b22cd56-ca19-47f6-b19e-08908158ae9c", 
            "dueDate": "2026-11-10", 
            "boletoUrl": "34191090081225054789529988600002216220000001000" 
        }
    },
    "shiftedCycles": [],
    "repricedCycles": [ 
        {
            "cycleNumber": 4, 
            "previousAmount": 100, 
            "amount": 90 
        }
    ],
    "restoredStatus": null
}

Campos da resposta

successboolean
typestring
subscriptionIdstring
couponobject
Cupom aplicado
applyTostring
firstCycleNumbernumber
actionstring
currentDueDatestring
newDueDatestring
reissuesOpenChargeboolean
redemptionIdstring
reissuedobject
Nova cobrança emitida no lugar da que estava em aberto. Mesmo formato no desconto e no período grátis
shiftedCyclesarray[0]
repricedCyclesarray[1]
Cobranças agendadas que tiveram o valor recalculado com o desconto
restoredStatusobject
200prévia (dryRun)▾
JSON
{
    "success": true,
    "type": "PREVIEW",
    "subscriptionId": "sub_xxx",

    "coupon": { 
        "code": "INDICACAO", 
        "discountType": "EXTRA_PERIOD", 
        "discountValue": 1, 
        "extraPeriodUnit": "MONTHS", 
        "maxCycles": 1 
    },
    "applyTo": "NEXT_CYCLE", 
    "firstCycleNumber": 4, 
    "action": "SHIFT_UNBILLED_CYCLES", 
    "currentDueDate": null, 
    "newDueDate": null, 
    "reissuesOpenCharge": false 
}

Campos da resposta

successboolean
typestring
subscriptionIdstring
couponobject
Cupom aplicado
applyTostring
A partir de qual cobrança o cupom vale
Valores aceitos:CURRENT_CYCLENEXT_CYCLE
firstCycleNumbernumber
Primeiro ciclo afetado pelo cupom
actionstring
O que foi feito. APPLIED_ON_BILLING: vale quando a cobrança for gerada. SHIFT_UNBILLED_CYCLES: próximas cobranças remarcadas. REISSUE_WITH_DISCOUNT: cobrança atual reemitida com desconto. REISSUE_WITH_NEW_DUE_DATE: cobrança atual reemitida com vencimento adiado
Valores aceitos:APPLIED_ON_BILLINGSHIFT_UNBILLED_CYCLESREISSUE_WITH_DISCOUNTREISSUE_WITH_NEW_DUE_DATE
currentDueDateobject
Vencimento da cobrança atual antes do cupom
Regra:date
newDueDateobject
Vencimento da cobrança atual depois do cupom
Regra:date
reissuesOpenChargeboolean
true quando a cobrança atual é reemitida
400cupom em vigor▾
JSON
{
    "error": {
        "message": "A assinatura já tem o cupom BEMVINDO em vigor; aplique outro quando ele terminar",
        "code": "COUPON_ALREADY_ACTIVE",
        "details": null,
        "timestamp": "2026-09-24T12:00:00.000Z"
    }
}
400cobrança atual vencida▾
JSON
{
    "error": {
        "message": "A cobrança atual está vencida; informe um dueDate posterior a hoje para emitir a nova cobrança",
        "code": "DUE_DATE_REQUIRED",
        "details": null,
        "timestamp": "2026-09-24T12:00:00.000Z"
    }
}
400cupom inválido▾
JSON
{
    "error": {
        "message": "Cupom expirado",
        "code": "COUPON_EXPIRED",
        "details": null,
        "timestamp": "2026-09-24T12:00:00.000Z"
    }
}
400cobrança já paga▾
JSON
{
    "error": {
        "message": "A cobrança atual já foi paga; aplique o cupom a partir da próxima (NEXT_CYCLE)",
        "code": "CYCLE_ALREADY_SETTLED",
        "details": null,
        "timestamp": "2026-09-24T12:00:00.000Z"
    }
}