Pular para o conteúdo principal

Visão Geral

As assinaturas sob demanda permitem que você autorize um método de pagamento de um cliente uma vez e, em seguida, cobre valores variáveis sempre que precisar, em vez de em um cronograma fixo.
As assinaturas sob demanda agora estão disponíveis para todas as empresas. Este recurso permite controle de cobrança flexível para serviços baseados em uso e medidos.
Use este guia para:
  • Criar uma assinatura sob demanda (autorizar um mandato com preço inicial opcional)
  • Acionar cobranças subsequentes com valores personalizados
  • Rastrear resultados usando webhooks
Para uma configuração geral de assinatura, veja o Guia de Integração de Assinaturas.

Pré-requisitos

  • Conta de comerciante Dodo Payments e chave de API
  • Segredo do webhook configurado e um endpoint para receber eventos
  • Um produto de assinatura em seu catálogo
Se você quiser que o cliente aprove o mandato via checkout hospedado, defina payment_link: true e forneça um return_url.

Como funciona o sob demanda

  1. Você cria uma assinatura com o objeto on_demand para autorizar um método de pagamento e, opcionalmente, coletar uma cobrança inicial.
  2. Mais tarde, você cria cobranças contra essa assinatura com valores personalizados usando o endpoint de cobrança dedicado.
  3. Você escuta webhooks (por exemplo, payment.succeeded, payment.failed) para atualizar seu sistema.

Criar uma assinatura sob demanda

Endpoint: POST /subscriptions Campos principais da solicitação (corpo):
product_id
string
obrigatório
ID do produto para a assinatura.
quantity
integer
obrigatório
Número de unidades. Mínimo 1.
billing
object
obrigatório
Endereço de cobrança do cliente.
customer
object
obrigatório
Anexar um cliente existente ou fornecer detalhes do cliente.
Se verdadeiro, cria um link de checkout hospedado para autorização do mandato e pagamento inicial opcional.
return_url
string
Para onde redirecionar o cliente após completar o checkout hospedado.
on_demand.mandate_only
boolean
obrigatório
Se verdadeiro, autoriza o método de pagamento sem cobrar o cliente durante a criação.
on_demand.product_price
integer
Valor da cobrança inicial (na menor unidade monetária). Se especificado, este valor substitui o preço original do produto definido durante a criação do produto. Se omitido, o preço armazenado do produto é usado. Exemplo: para cobrar $1,00, passe 100.
on_demand.product_currency
string
Substituição de moeda opcional para a cobrança inicial. Padrão é a moeda do produto.
on_demand.product_description
string
Substituição de descrição opcional para cobrança e itens de linha.
on_demand.adaptive_currency_fees_inclusive
boolean
Se verdadeiro, inclui taxas de moeda adaptativa dentro de product_price. Se falso, as taxas são adicionadas por cima. Ignorado quando a precificação adaptativa está desativada.

Criar uma assinatura sob demanda

import DodoPayments from 'dodopayments';

const client = new DodoPayments({
  bearerToken: process.env.DODO_PAYMENTS_API_KEY,
  environment: 'test_mode', // defaults to 'live_mode'
});

async function main() {
  const subscription = await client.subscriptions.create({
    billing: { city: 'SF', country: 'US', state: 'CA', street: '1 Market St', zipcode: '94105' },
    customer: { customer_id: 'customer_123' },
    product_id: 'prod_sub_123',
    quantity: 1,
    payment_link: true,
    return_url: 'https://example.com/billing/success',
    on_demand: {
      mandate_only: true, // set false to collect an initial charge
      // product_price: 1000, // optional: charge $10.00 now if mandate_only is false
      // product_currency: 'USD',
      // product_description: 'Custom initial charge',
      // adaptive_currency_fees_inclusive: false,
    },
  });

  // If payment_link was true, redirect the customer to authorize the mandate
  console.log(subscription.payment_link);
}

main().catch(console.error);
Defina payment_link: true, redirecione o cliente para payment_link para completar a autorização do mandato.
Success
{
  "subscription_id": "sub_123",
  "payment_link": "https://pay.dodopayments.com/checkout/...",
  "customer": { "customer_id": "customer_123", "email": "[email protected]", "name": "Alex Doe" },
  "metadata": {},
  "recurring_pre_tax_amount": 0,
  "addons": []
}

Cobrar uma assinatura sob demanda

Após a autorização do mandato, crie cobranças conforme necessário. Endpoint: POST /subscriptions/{subscription_id}/charge Campos principais da solicitação (corpo):
product_price
integer
obrigatório
Valor a ser cobrado (na menor unidade monetária). Exemplo: para cobrar $25,00, passe 2500.
product_currency
string
Substituição de moeda opcional para a cobrança.
product_description
string
Substituição de descrição opcional para esta cobrança.
adaptive_currency_fees_inclusive
boolean
Se verdadeiro, inclui taxas de moeda adaptativa dentro de product_price. Se falso, as taxas são adicionadas por cima.
metadata
object
Metadados adicionais para o pagamento. Se omitido, os metadados da assinatura são usados.
import DodoPayments from 'dodopayments';

const client = new DodoPayments({
  bearerToken: process.env.DODO_PAYMENTS_API_KEY,
  environment: 'test_mode', // defaults to 'live_mode'
});

async function chargeNow(subscriptionId) {
  const res = await client.subscriptions.charge(subscriptionId, { product_price: 2500 });
  console.log(res.payment_id);
}

chargeNow('sub_123').catch(console.error);
Success
{ "payment_id": "pay_abc123" }
Cobrar uma assinatura que não é sob demanda pode falhar. Certifique-se de que a assinatura tenha on_demand: true em seus detalhes antes de cobrar.

Tentativas de pagamento

Nosso sistema de detecção de fraudes pode bloquear padrões de tentativas agressivas (e pode sinalizá-los como testes de cartão potenciais). Siga uma política de tentativas segura.
Padrões de tentativas em massa podem ser sinalizados como fraudulentos ou suspeitos de teste de cartão pelos nossos sistemas de risco e processadores. Evite tentativas agrupadas; siga o cronograma de recuo e as orientações de alinhamento de tempo abaixo.

Princípios para políticas de tentativas seguras

  • Mecanismo de recuo: Use recuo exponencial entre as tentativas.
  • Limites de tentativas: Limite o total de tentativas (máximo de 3 a 4 tentativas).
  • Filtragem inteligente: Tente novamente apenas em falhas recuperáveis (por exemplo, erros de rede/emissor, fundos insuficientes); nunca tente novamente em recusas definitivas.
  • Prevenção de testes de cartão: Não tente novamente falhas como DO_NOT_HONOR, STOLEN_CARD, LOST_CARD, PICKUP_CARD, FRAUDULENT, AUTHENTICATION_FAILURE.
  • Variar metadados (opcional): Se você mantiver seu próprio sistema de tentativas, diferencie as tentativas por meio de metadados (por exemplo, retry_attempt).

Cronograma de tentativas sugerido (assinaturas)

  • 1ª tentativa: Imediata quando você cria a cobrança
  • 2ª tentativa: Após 3 dias
  • 3ª tentativa: Após mais 7 dias (10 dias no total)
  • 4ª tentativa (final): Após mais 7 dias (17 dias no total)
Passo final: se ainda não pago, marque a assinatura como não paga ou cancele-a, com base em sua política. Notifique o cliente durante a janela para atualizar seu método de pagamento.

Evite tentativas em massa; alinhe-se ao horário de autorização

  • Ancore as tentativas ao timestamp de autorização original para evitar comportamento de “explosão” em seu portfólio.
  • Exemplo: Se o cliente iniciar um teste ou mandato às 13h10 de hoje, agende tentativas de acompanhamento às 13h10 nos dias subsequentes conforme seu recuo (por exemplo, +3 dias → 13h10, +7 dias → 13h10).
  • Alternativamente, se você armazenar o último horário de pagamento bem-sucedido T, agende a próxima tentativa em T + X days para preservar o alinhamento do horário do dia.
Fuso horário e DST: use um padrão de tempo consistente para agendamento e converta apenas para exibição para manter os intervalos.

Códigos de recusa que você não deve tentar novamente

  • STOLEN_CARD
  • DO_NOT_HONOR
  • FRAUDULENT
  • PICKUP_CARD
  • AUTHENTICATION_FAILURE
  • LOST_CARD
Para uma lista abrangente de razões de recusa e se são corrigíveis pelo usuário, veja a documentação de Falhas de Transação.
Tente novamente apenas em problemas temporários/suaves (por exemplo, insufficient_funds, issuer_unavailable, processing_error, timeouts de rede). Se a mesma recusa se repetir, pause novas tentativas.

Diretrizes de implementação (sem código)

  • Use um agendador/fila que persista timestamps precisos; calcule a próxima tentativa no exato deslocamento de horário (por exemplo, T + 3 days no mesmo HH:MM).
  • Mantenha e faça referência ao último timestamp de pagamento bem-sucedido T para calcular a próxima tentativa; não agrupe várias assinaturas no mesmo instante.
  • Sempre avalie a última razão de recusa; pare as tentativas para recusas definitivas na lista de exclusão acima.
  • Limite tentativas simultâneas por cliente e por conta para evitar picos acidentais.
  • Comunique-se proativamente: envie e-mail/SMS ao cliente para atualizar seu método de pagamento antes da próxima tentativa agendada.
  • Use metadados apenas para observabilidade (por exemplo, retry_attempt); nunca tente “evadir” sistemas de fraude/risco rotacionando campos irrelevantes.

Rastrear resultados com webhooks

Implemente o manuseio de webhooks para rastrear a jornada do cliente. Veja Implementando Webhooks.
  • subscription.active: Mandato autorizado e assinatura ativada
  • subscription.failed: Criação falhou (por exemplo, falha de mandato)
  • subscription.on_hold: Assinatura colocada em espera (por exemplo, estado não pago)
  • payment.succeeded: Cobrança bem-sucedida
  • payment.failed: Cobrança falhou
Para fluxos sob demanda, concentre-se em payment.succeeded e payment.failed para reconciliar cobranças baseadas em uso.

Testes e próximos passos

1

Criar em modo de teste

Use sua chave de API de teste para criar a assinatura com payment_link: true, depois abra o link e complete o mandato.
2

Acionar uma cobrança

Chame o endpoint de cobrança com um pequeno product_price (por exemplo, 100) e verifique se você recebe payment.succeeded.
3

Ir ao vivo

Mude para sua chave de API ao vivo assim que você tiver validado eventos e atualizações de estado interno.

Resolução de problemas

  • 422 Solicitação Inválida: Certifique-se de que on_demand.mandate_only seja fornecido na criação e product_price seja fornecido para cobranças.
  • Erros de moeda: Se você substituir product_currency, confirme se é suportado para sua conta e cliente.
  • Nenhum webhook recebido: Verifique sua URL de webhook e configuração do segredo.