Descontos e cupons

Aplicar desconto em uma cobrança

Dá um desconto de valor livre em uma cobrança específica — por exemplo, para negociar uma fatura vencida. Com cycles, o desconto vale também para as cobranças seguintes.

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

Qual cobrança: informe invoiceId, chargeId ou cycleNumber. Sem nenhum deles, vale para a cobrança atual.

Por quantas cobranças (cycles): conta a partir da cobrança escolhida, incluindo ela.

  • 1 (padrão): só esta cobrança.
  • 3: esta e as duas seguintes.
  • null: todas a partir desta.

Com mais de uma cobrança, o desconto vira o desconto recorrente da assinatura. Os ciclos seguintes já criados e ainda não emitidos recebem o desconto na hora, e os próximos já nascem com ele.

O que acontece com a cobrança: se ela já foi emitida em Pix ou boleto, é reemitida com o valor novo (a menos que reissueOpenCharge seja false). O boleto antigo não é cancelado, a menos que você envie cancelOpenBoleto: true. Para remover um desconto, envie discount: null.

Regras do desconto recorrente:

  • A assinatura tem um desconto recorrente por vez. Outro desconto recorrente numa cobrança coberta substitui o atual a partir dela.
  • discount: null numa cobrança coberta encerra o desconto recorrente a partir dela. As cobranças anteriores mantêm o desconto.
  • Desconto recorrente e cupom não valem juntos: com cupom em vigor, a resposta é DISCOUNT_CONFLICTS_WITH_COUPON.
  • A troca de plano encerra o desconto recorrente: o novo plano começa sem ele.
  • Vale só para a mensalidade. A fatura avulsa de um ciclo aceita apenas cycles: 1.
  • No Pix Automático com autorização de valor fixo, o desconto recorrente não é aceito.

O desconto não pode zerar a cobrança. Para período grátis, use Aplicar cupom.

Envie dryRun: true para ver o valor novo, e os ciclos seguintes afetados, sem aplicar.

Erros:

  • DISCOUNT_EXCEEDS_CHARGE_AMOUNT: o desconto zeraria esta cobrança ou um dos ciclos seguintes.
  • DISCOUNT_SCHEDULE_ACTIVE: cycles: 1 numa cobrança coberta pelo desconto recorrente. Envie outro desconto recorrente para substituí-lo, ou discount: null para encerrá-lo.
  • LATER_CYCLE_ALREADY_BILLED: um ciclo seguinte dentro do período já foi emitido. Aplique o desconto recorrente a partir dele.
  • DISCOUNT_SCHEDULE_REQUIRES_RECURRING_CHARGE: desconto recorrente em fatura avulsa do ciclo.
  • DISCOUNT_CONFLICTS_WITH_COUPON: a assinatura tem cupom em vigor.
  • PIX_AUTOMATICO_FIXED_AMOUNT: a autorização Pix Automático do cliente tem valor fixo.
  • PIX_AUTOMATICO_INSTRUCTED: a instrução de débito do ciclo já foi enviada ao banco.
  • INVOICE_NOT_PAYABLE, CYCLE_ALREADY_SETTLED: a cobrança já foi paga ou cancelada.

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
{
    "cycleNumber": 3, 
    "discount": { 
        "type": "PERCENTAGE", 
        "value": 10 
    },
    "cycles": 3, 
    "reissueOpenCharge": true, 
    "cancelOpenBoleto": false, 
    "reason": "Negociação da fatura", 
    "dryRun": false 
}

Schema

discountobjectobrigatório
Desconto. Envie null para remover o desconto atual
cycleNumbernumberopcional
Ciclo da cobrança. Alternativa: invoiceId ou chargeId
cyclesnumberopcional
Quantas cobranças, contando esta. 1: só esta (padrão). null: todas a partir desta
reissueOpenChargebooleanopcional
false: não reemite a cobrança já emitida (padrão true)
cancelOpenBoletobooleanopcional
true: cancela o boleto em aberto ao reemitir
reasonstringopcional
Motivo, gravado no histórico
dryRunbooleanopcional
true: só simula
const url = 'https://sandbox.validapay.com.br/v1/subscriptions/:subscriptionId/discounts';

const options = {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer {{token}}',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    "cycleNumber": 3, 
    "discount": { 
        "type": "PERCENTAGE", 
        "value": 10 
    },
    "cycles": 3, 
    "reissueOpenCharge": true, 
    "cancelOpenBoleto": false, 
    "reason": "Negociação da fatura", 
    "dryRun": false 
})
};

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

Response Examples

200▾
JSON
{
    "success": true, 
    "type": "DISCOUNT_APPLIED", 
    "subscriptionId": "sub_xxx", 
    "target": { 
        "kind": "INVOICE", 
        "cycleNumber": 3, 
        "invoiceId": "inv_xxx", 
        "invoiceNumber": "000003", 
        "isPrimaryInvoice": true 
    },
    "discount": { "type": "PERCENTAGE", "value": 10 }, 
    "previousDiscount": null, 
    "grossAmount": 99.9, 
    "discountAmount": 9.99, 
    "currentAmount": 99.9, 
    "newAmount": 89.91, 
    "reissue": { 
        "willReissue": true, 
        "skipReason": null, 
        "paymentType": "BOLETO", 
        "subscriptionPaymentType": "BOLETO", 
        "openChargeId": "cha_xxx" 
    },
    "discountSchedule": { 
        "current": null, 
        "coversTarget": false, 
        "next": { 
            "type": "PERCENTAGE", 
            "value": 10, 
            "startCycleNumber": 3, 
            "cycles": 3, 
            "lastCycleNumber": 5, 
            "endedAt": null 
        },
        "laterCycles": [ 
            { "cycleNumber": 4, "amount": 89.91 }
        ]
    },
    "warnings": [], 
    "reissued": { "chargeId": "cha_yyy", "paymentType": "BOLETO", "dueDate": "2026-10-10", "amount": 89.91 } 
}

Campos da resposta

successboolean
true quando o desconto foi aplicado ou removido
typestring
DISCOUNT_APPLIED, DISCOUNT_REMOVED, NO_CHANGE ou PREVIEW (dryRun)
Valores aceitos:DISCOUNT_APPLIEDDISCOUNT_REMOVEDNO_CHANGEPREVIEW
subscriptionIdstring
ID da assinatura
targetobject
Cobrança que recebeu o desconto
discountobject
Desconto aplicado
previousDiscountobject
Desconto que existia antes
grossAmountnumber
Valor sem desconto, em reais
discountAmountnumber
Valor do desconto, em reais
currentAmountnumber
Valor da cobrança antes, em reais
newAmountnumber
Valor da cobrança depois, em reais
reissueobject
Reemissão da cobrança
discountScheduleobject
Desconto recorrente da assinatura
warningsarray[0]
Avisos, como boleto antigo que continua pagável
reissuedobject
Nova cobrança emitida com o desconto
400desconto zera a cobrança▾
JSON
{
    "error": {
        "message": "O desconto não pode zerar a cobrança, hoje em 99.90",
        "code": "DISCOUNT_EXCEEDS_CHARGE_AMOUNT",
        "details": null,
        "timestamp": "2026-09-24T12:00:00.000Z"
    }
}
400cobrança coberta por desconto recorrente▾
JSON
{
    "error": {
        "message": "Esta cobrança faz parte de um desconto recorrente; encerre-o ou aplique outro desconto recorrente para substituí-lo",
        "code": "DISCOUNT_SCHEDULE_ACTIVE",
        "details": null,
        "timestamp": "2026-11-04T12:00:00.000Z"
    }
}