Skip to main content

Visão geral

O sistema de assinaturas da PlugToPay opera em três camadas:
ObjetoResponsabilidade
PlanoDefine valor, intervalo, período de trial e regras do ciclo
CupomDesconto percentual ou fixo aplicável a N ciclos
AssinaturaVincula cliente + cartão + plano e orquestra as cobranças
O fluxo básico é: criar plano → tokenizar cartão do cliente → criar assinatura. A partir daí, a PlugToPay cobra automaticamente a cada ciclo, com retentativas em caso de falha, e dispara webhooks a cada evento relevante.
Pré-requisito: o cliente e o cartão já devem existir no vault antes de criar uma assinatura. Para tokenizar o cartão use save_card: true em qualquer pagamento avulso — o token retornado no objeto card da resposta é o card_token usado aqui.

Planos

Criar plano

POST /api/v1/subscriptions/plans — requer X-Client-ID + X-API-Key.
{
  "name": "Pro Mensal",
  "description": "Acesso completo à plataforma",
  "amount": 2990,
  "currency": "BRL",
  "interval": "monthly",
  "interval_count": 1,
  "trial_period_days": 7,
  "billing_day": 5,
  "min_card_months": 3
}
CampoTipoObrigatórioDescrição
namestring (max 255)simNome do plano
descriptionstring (max 1000)nãoDescrição exibida ao cliente
amountinteiro (centavos)simValor do ciclo em centavos (ex: 2990 = R$ 29,90)
currencystring (3 chars)nãoMoeda — padrão BRL
intervalweekly|monthly|yearlysimFrequência de cobrança
interval_countinteiro (1–365)nãoMultiplicador do intervalo — padrão 1 (ex: 2 + monthly = a cada 2 meses)
trial_period_daysinteiro (0–365)nãoDias de trial gratuito antes da primeira cobrança
billing_dayinteiro (1–28)nãoDia fixo de cobrança no mês/ano. Para weekly é ignorado. Se omitido, usa o dia da criação da assinatura
min_card_monthsinteiro (1–120)nãoValidade mínima do cartão em meses a partir de hoje. Impede criação de assinaturas com cartões prestes a vencer
billing_day é sempre limitado a 28 para garantir compatibilidade com todos os meses. Dias 29, 30 e 31 não são aceitos.
Resposta 201:
{
  "id": "018f1a2b-3c4d-7e5f-a6b7-c8d9e0f1a2b3",
  "name": "Pro Mensal",
  "description": "Acesso completo à plataforma",
  "amount": 2990,
  "currency": "BRL",
  "interval": "monthly",
  "interval_count": 1,
  "trial_period_days": 7,
  "billing_day": 5,
  "min_card_months": 3,
  "is_active": true,
  "created_at": "2026-06-25T12:00:00+00:00",
  "updated_at": "2026-06-25T12:00:00+00:00"
}

Atualizar plano

PUT /api/v1/subscriptions/plans/{uuid} — requer X-Client-ID + X-API-Key.
{
  "name": "Pro Mensal Plus",
  "description": "Novo benefício incluído",
  "billing_day": 10,
  "trial_period_days": 14,
  "min_card_months": 6,
  "is_active": true
}
Não é possível alterar amount, currency, interval ou interval_count após a criação. Para mudar o valor ou a frequência, crie um novo plano e migre as assinaturas via troca de plano.

Listar planos

GET /api/v1/subscriptions/plans — requer X-Client-ID + X-API-Key. Retorna a lista de planos da empresa. Planos inativos (is_active: false) são incluídos.

Deletar plano

DELETE /api/v1/subscriptions/plans/{uuid} — requer X-Client-ID + X-API-Key. Soft-delete. Não é possível deletar um plano com assinaturas ativas.

Cupons

Criar cupom

POST /api/v1/subscriptions/coupons — requer X-Client-ID + X-API-Key.
{
  "code": "VERAO30",
  "name": "30% de desconto — Verão",
  "description": "Promoção de verão, primeiros 3 meses",
  "discount_type": "percentage",
  "discount_value": 30,
  "max_redemptions": 200,
  "max_cycles": 3,
  "valid_from": "2026-12-01",
  "valid_until": "2027-02-28"
}
CampoTipoObrigatórioDescrição
codestring alfanumérico (max 50)simCódigo único por empresa. Convertido automaticamente para maiúsculas
namestring (max 255)simNome interno do cupom
descriptionstring (max 1000)nãoDescrição opcional
discount_typepercentage|fixedsimTipo de desconto
discount_valueinteirosimPara percentage: 1–100. Para fixed: valor em centavos
max_redemptionsinteiro (min 1)nãoLimite total de resgates. null = ilimitado
max_cyclesinteiro (min 1)nãoAplica o desconto apenas nos primeiros N ciclos. null = aplica para sempre
valid_fromdate (YYYY-MM-DD)simData de início da validade
valid_untildate após valid_fromnãoData de fim da validade. null = sem expiração
Resposta 201:
{
  "id": "019a2b3c-4d5e-6f7a-8b9c-0d1e2f3a4b5c",
  "code": "VERAO30",
  "name": "30% de desconto — Verão",
  "description": "Promoção de verão, primeiros 3 meses",
  "discount_type": "percentage",
  "discount_value": 30,
  "max_redemptions": 200,
  "redemptions_count": 0,
  "max_cycles": 3,
  "valid_from": "2026-12-01T00:00:00+00:00",
  "valid_until": "2027-02-28T23:59:59+00:00",
  "is_active": true,
  "created_at": "2026-06-25T12:00:00+00:00"
}

Atualizar cupom

PUT /api/v1/subscriptions/coupons/{uuid} — requer X-Client-ID + X-API-Key. Campos editáveis: name, description, max_redemptions, max_cycles, valid_until, is_active. code, discount_type e discount_value são imutáveis após a criação.

Listar e deletar cupons

MétodoRotaDescrição
GET/api/v1/subscriptions/couponsLista todos os cupons
GET/api/v1/subscriptions/coupons/{uuid}Detalha um cupom
DELETE/api/v1/subscriptions/coupons/{uuid}Soft-delete

Assinaturas

Criar assinatura

POST /api/v1/subscriptions — requer X-Client-ID + X-API-Key.
{
  "plan_uuid": "018f1a2b-3c4d-7e5f-a6b7-c8d9e0f1a2b3",
  "customer_token": "cus_7556...",
  "card_token": "card_86123...",
  "coupon_code": "VERAO30",
  "billing_day": 10,
  "metadata": {
    "internal_ref": "user_789"
  }
}
CampoTipoObrigatórioDescrição
plan_uuiduuidsimUUID do plano existente e ativo
customer_tokenstringsimToken do cliente (customer.token)
card_tokenstringnão*Token do cartão (card.token). *Obrigatório para planos sem trial ou com trial_period_days: 0
coupon_codestringnãoCódigo do cupom a aplicar desde o primeiro ciclo
billing_dayinteiro (1–28)nãoSobrepõe o billing_day do plano para esta assinatura
metadataobjetonãoDados livres associados à assinatura (IDs internos, referências, etc.)
O sistema impede a criação de uma segunda assinatura ativa do mesmo cliente no mesmo plano. Para mudar o plano, use a troca de plano em vez de cancelar e recriar.
Validação de min_card_months: se o plano tiver esse campo definido, o cartão informado deve ter validade mínima de min_card_months meses a partir de hoje. Uma assinatura anual com min_card_months: 13, por exemplo, impede o uso de um cartão que vence em 6 meses. Resposta 201:
{
  "id": "01a2b3c4-d5e6-7f8a-9b0c-1d2e3f4a5b6c",
  "status": "trialing",
  "plan": {
    "id": "018f1a2b-3c4d-7e5f-a6b7-c8d9e0f1a2b3",
    "name": "Pro Mensal",
    "amount": 2990,
    "interval": "monthly",
    "interval_count": 1
  },
  "customer": {
    "id": 42,
    "name": "João Silva",
    "email": "joao@example.com",
    "token": "cus_7556..."
  },
  "card": {
    "last_4_digits": "1111",
    "brand": "visa",
    "expire_month": "12",
    "expire_year": "2028"
  },
  "coupon": {
    "code": "VERAO30",
    "discount_type": "percentage",
    "discount_value": 30,
    "max_cycles": 3
  },
  "amount": 2093,
  "original_amount": 2990,
  "discount_amount": 897,
  "currency": "BRL",
  "interval": "monthly",
  "interval_count": 1,
  "billing_day": 10,
  "trial": {
    "period_days": 7,
    "start": "2026-06-25T12:00:00+00:00",
    "end": "2026-07-02T12:00:00+00:00"
  },
  "current_period": {
    "start": "2026-06-25T12:00:00+00:00",
    "end": "2026-07-02T12:00:00+00:00"
  },
  "next_billing_at": "2026-07-02T12:00:00+00:00",
  "paused_at": null,
  "paused_until": null,
  "canceled_at": null,
  "cancel_at": null,
  "cancel_at_period_end": false,
  "plan_change_at": null,
  "new_plan_id": null,
  "metadata": { "internal_ref": "user_789" },
  "created_at": "2026-06-25T12:00:00+00:00",
  "updated_at": "2026-06-25T12:00:00+00:00"
}

Status possíveis

StatusDescrição
trialingEm período de trial — nenhuma cobrança ainda
activeFaturando normalmente
past_dueTodas as retentativas esgotadas — requer ação do cliente
pausedFaturamento suspenso temporariamente
canceledEncerrada

Ciclo de faturamento

Quando next_billing_at é atingido, a PlugToPay:
  1. Cria um ciclo pending para o período
  2. Aplica o desconto do cupom (se elegível pelo max_cycles)
  3. Tenta cobrar o cartão via CreatePaymentCardService (mesmo fluxo de pagamento avulso com cartão tokenizado)
  4. Sucesso → ciclo marcado como paid, período avança, webhook subscription.payment.success
  5. Falha → ciclo marcado como failed, retentativas agendadas, webhook subscription.payment.failed
Lógica de retentativas:
TentativaQuando
1ª (original)Na data de vencimento
2ª retry+1 dia após a falha original
3ª retry+3 dias após a falha original
4ª retry+5 dias após a falha original
Após a 4ª tentativa sem sucesso, a assinatura vai para past_due e o webhook subscription.past_due é disparado. Nesse estado, nenhuma nova cobrança automática ocorre — o cliente deve atualizar o cartão. Cálculo do billing_day:
  • weekly: o billing_day é ignorado; o ciclo avança exatamente pelo número de semanas definido
  • monthly / yearly: a cobrança ocorre no billing_day do próximo mês/ano (sempre limitado a 28)

Listar assinaturas

GET /api/v1/subscriptions — requer X-Client-ID + X-API-Key. Retorna lista paginada. Suporta filtros (consultar via parâmetros de query).

Consultar assinatura

GET /api/v1/subscriptions/{uuid} — requer X-Client-ID + X-API-Key. Retorna o objeto completo com plan, customer, card, coupon e datas de período.

Listar ciclos

GET /api/v1/subscriptions/{uuid}/cycles — requer X-Client-ID + X-API-Key. Retorna o histórico de ciclos de faturamento da assinatura:
[
  {
    "id": "01b2c3d4-e5f6-7a8b-9c0d-1e2f3a4b5c6d",
    "subscription_id": "01a2b3c4-d5e6-7f8a-9b0c-1d2e3f4a5b6c",
    "period_start": "2026-07-02T00:00:00+00:00",
    "period_end": "2026-08-10T00:00:00+00:00",
    "amount": 2093,
    "discount_amount": 897,
    "status": "paid",
    "due_at": "2026-07-10T00:00:00+00:00",
    "paid_at": "2026-07-10T08:45:00+00:00",
    "failed_at": null,
    "retry_count": 0,
    "next_retry_at": null,
    "gateway_transaction_id": "019ddb56-fbe3-72e1-9f3c-8d0b2faf8f73",
    "created_at": "2026-07-10T00:00:00+00:00"
  }
]
CampoDescrição
statuspending|paid|failed|waived
retry_countNúmero de retentativas já realizadas (máx. 3)
next_retry_atPróxima tentativa agendada (null se esgotadas ou bem-sucedido)
gateway_transaction_idUUID da transação no gateway_transactions (consulta via GET /api/v1/payments/{id})

Gerenciamento

Pausar

PATCH /api/v1/subscriptions/{uuid}/pause — requer X-Client-ID + X-API-Key.
{
  "paused_until": "2026-09-01"
}
paused_until é opcional. Se informado, a assinatura retoma automaticamente nessa data via cron. Caso contrário, permanece pausada até um resume explícito. Apenas assinaturas em active ou trialing podem ser pausadas.

Retomar

PATCH /api/v1/subscriptions/{uuid}/resume — requer X-Client-ID + X-API-Key. Corpo vazio. Recalcula next_billing_at a partir da data atual, respeitando o billing_day.

Cancelar

DELETE /api/v1/subscriptions/{uuid} — requer X-Client-ID + X-API-Key.
{
  "at_period_end": true
}
at_period_endComportamento
false (padrão)Cancela imediatamente — sem cobrança do período em andamento
trueAgenda para o fim do período atual — cliente mantém acesso até lá
Quando at_period_end: true, a assinatura continua active mas exibe cancel_at_period_end: true e cancel_at com a data de expiração. O cancelamento é executado automaticamente pelo cron.

Trocar plano

PATCH /api/v1/subscriptions/{uuid}/plan — requer X-Client-ID + X-API-Key.
{
  "new_plan_uuid": "018f9z8y-7x6w-5v4u-3t2s-1r0q9p8o7n6m",
  "immediately": false
}
immediatelyComportamento
false (padrão)Troca agendada para o início do próximo período
trueTroca imediata com pro-rata: crédito proporcional ao tempo não utilizado no período atual é calculado e descontado do novo valor
A troca é classificada automaticamente como upgrade (novo valor ≥ atual) ou downgrade (novo valor < atual) e sinalizada no webhook.

Atualizar cartão

PATCH /api/v1/subscriptions/{uuid}/card — requer X-Client-ID + X-API-Key.
{
  "card_token": "card_novocartao..."
}
Use quando o cartão anterior for recusado (estado past_due) ou quando o cliente adicionar um novo método de pagamento. O cartão deve pertencer ao mesmo cliente da assinatura.
Após atualizar o cartão de uma assinatura past_due, chame Antecipar para tentar cobrar imediatamente sem esperar o próximo ciclo automático.

Antecipar

POST /api/v1/subscriptions/{uuid}/anticipate — requer X-Client-ID + X-API-Key. Corpo vazio. Cobra o próximo ciclo agora, independentemente de next_billing_at. Ideal para:
  • Reativar assinaturas past_due após atualização de cartão
  • Testes de integração
  • Cobranças sob demanda antecipadas pelo operador
Retorna o ciclo criado com o resultado da tentativa de cobrança.

Aplicar cupom

POST /api/v1/subscriptions/{uuid}/coupon — requer X-Client-ID + X-API-Key.
{
  "coupon_code": "RETENCAO10"
}
Substitui o cupom atual (se houver). O desconto passa a valer a partir do próximo ciclo. O contador de max_cycles é resetado — os N ciclos com desconto são contados do zero.

Webhooks

Todos os eventos de assinatura seguem o mesmo envelope. Cadastre os eventos desejados em POST /api/v1/user/company/webhooks.

Eventos disponíveis

EventoQuando é disparado
subscription.createdAssinatura criada
subscription.trial_startedAssinatura criada com trial
subscription.activatedPrimeiro ciclo pago com sucesso (trial encerrou)
subscription.pausedAssinatura pausada
subscription.resumedAssinatura retomada
subscription.plan_changedPlano alterado (imediato ou agendado)
subscription.payment.successCiclo cobrado com sucesso
subscription.payment.failedTentativa de cobrança falhou
subscription.payment.retryRetentativa agendada
subscription.past_dueTodas as retentativas esgotadas
subscription.canceledAssinatura cancelada

Payload base

Todos os eventos incluem estes campos:
{
  "event": "subscription.payment.success",
  "subscription_id": "01a2b3c4-d5e6-7f8a-9b0c-1d2e3f4a5b6c",
  "plan_id": "018f1a2b-3c4d-7e5f-a6b7-c8d9e0f1a2b3",
  "customer_id": 42,
  "status": "active",
  "amount": 2093,
  "currency": "BRL",
  "interval": "monthly",
  "interval_count": 1,
  "billing_day": 10,
  "next_billing_at": "2026-08-10T00:00:00+00:00",
  "current_period": {
    "start": "2026-07-10T00:00:00+00:00",
    "end": "2026-08-10T00:00:00+00:00"
  },
  "trial": null,
  "created_at": "2026-06-25T12:00:00+00:00"
}

Campos extras por evento

EventoCampos adicionais
subscription.trial_startedtrial_end
subscription.canceledat_period_end
subscription.pausedpaused_until
subscription.plan_changednew_plan_id, change_type (upgrade|downgrade), immediately, executed
subscription.payment.successcycle_id, amount_charged, transaction_id
subscription.payment.failedcycle_id, retry_count, next_retry_at, final
subscription.payment.retrycycle_id, retry_count, next_retry_at
subscription.past_duecycle_id, retry_count, reason
Implemente todos os eventos de subscription.payment.* e subscription.past_due. São eles que sinalizam quando o acesso do cliente deve ser suspenso ou reativado.

Referência rápida de rotas

Todos os endpoints requerem X-Client-ID + X-API-Key.
MétodoRotaDescrição
POST/api/v1/subscriptions/plansCriar plano
GET/api/v1/subscriptions/plansListar planos
GET/api/v1/subscriptions/plans/{uuid}Detalhar plano
PUT/api/v1/subscriptions/plans/{uuid}Atualizar plano
DELETE/api/v1/subscriptions/plans/{uuid}Deletar plano
POST/api/v1/subscriptions/couponsCriar cupom
GET/api/v1/subscriptions/couponsListar cupons
GET/api/v1/subscriptions/coupons/{uuid}Detalhar cupom
PUT/api/v1/subscriptions/coupons/{uuid}Atualizar cupom
DELETE/api/v1/subscriptions/coupons/{uuid}Deletar cupom
POST/api/v1/subscriptionsCriar assinatura
GET/api/v1/subscriptionsListar assinaturas
GET/api/v1/subscriptions/{uuid}Detalhar assinatura
DELETE/api/v1/subscriptions/{uuid}Cancelar assinatura
PATCH/api/v1/subscriptions/{uuid}/pausePausar
PATCH/api/v1/subscriptions/{uuid}/resumeRetomar
PATCH/api/v1/subscriptions/{uuid}/planTrocar plano
PATCH/api/v1/subscriptions/{uuid}/cardAtualizar cartão
POST/api/v1/subscriptions/{uuid}/anticipateAntecipar cobrança
POST/api/v1/subscriptions/{uuid}/couponAplicar cupom
GET/api/v1/subscriptions/{uuid}/cyclesListar ciclos