Endpoint: POST /subscriptions/plan/{plan_id}/subscribe/
Autenticação: Público (sem autenticação)
Este é o ponto de entrada que uma página de adesão hospedada (ou qualquer formulário público) chama quando um visitante decide assinar. O endpoint faz quatro coisas, do ponto de vista do chamador, de forma atômica:
  1. Valida a identidade do assinante e os dados de pagamento.
  2. Se save_card for true e o método for credit_card, tokeniza o cartão para que ele possa ser reutilizado nas cobranças recorrentes.
  3. Cria um assinante vinculado ao plano com status='pending' e next_billing_date=now.
  4. Cria o primeiro pagamento da assinatura no valor do plano e tenta cobrá-lo imediatamente através da conta do vendedor. Em caso de sucesso, o assinante e o pagamento passam para paid e next_billing_date avança conforme a frequency do plano.
Retorna 201 com o assinante, o pagamento e — para PIX/boleto — as instruções de pagamento.

Pré-requisitos

  • O plano precisa existir (GET /subscriptions/plan/{plan_id}/ o retorna).
  • O plano precisa pertencer a uma conta de vendedor ativa na plataforma — caso contrário a chamada falhará.
  • O type enviado deve ser um dos métodos listados em payment_methods do plano. Enviar pix para um plano que aceita apenas cartão retorna 400.

Parâmetros de rota

plan_id
string
required
UUID do plano de assinatura ao qual se está aderindo.

Corpo da requisição

Campos de identidade do assinante são sempre obrigatórios. Campos de pagamento dependem do type.

Campos do assinante

name
string
required
Nome completo do assinante. Deve ter pelo menos duas palavras (nome + sobrenome).
email
string
required
E-mail do assinante. Validado como endereço de e-mail real.
phone_number
string
required
Número de telefone, máx. 15 caracteres. Caracteres não numéricos são removidos no servidor. Validado contra country_code.
country_code
string
default:"+55"
Prefixo de país E.164, formato +\d{1,4}. Padrão +55 (Brasil).
taxpayer_id
string
CPF (11 dígitos) ou CNPJ (14 dígitos). Opcional para credit_card e pix, obrigatório para boleto. Caracteres de formatação são removidos.

Campos de pagamento

type
string
required
Um dos valores credit_card, boleto, pix. Precisa estar presente em payment_methods do plano.
card
object
Obrigatório quando type=credit_card. Campos:
  • number (string, máx. 16) — número do cartão.
  • cvv (string, máx. 4).
  • name (string, máx. 255) — nome do portador.
  • expirationMonth (string, tamanho 2) — ex.: "08".
  • expirationYear (string, tamanho 4) — ex.: "2028".
  • id (string, opcional) — se você já tem um UUID de cartão tokenizado, envie id no lugar dos campos brutos.
installments
integer
Obrigatório para credit_card. Inteiro entre 1 e 21. Observação: assinaturas são cobradas com max_installments=1 independentemente desse valor — veja o fluxo de assinaturas para o racional.
address
object
Obrigatório quando type=boleto. Campos do endereço:
  • line1, line2, neighborhood, city — strings, máx. 255.
  • state — UF de 2 caracteres (ex.: "SP").
  • postalCode — CEP de 8 dígitos, apenas números.
save_card
boolean
default:"false"
Quando true e type=credit_card, tokeniza o cartão antes de cobrar e armazena o token no assinante. O token é reutilizado em todas as cobranças recorrentes seguintes.

Resposta

201 Created em caso de sucesso.
subscriber
object
Resumo público do assinante — veja Obter contexto público do assinante para o formato completo. Inclui id, name, email, phone_number, country_code, taxpayer_id, status, next_billing_date, subscribed_at e saved_card quando aplicável.
payment
object
Resumo do primeiro pagamento da assinatura:
  • id — UUID do pagamento.
  • statuspaid, pending ou failed.
  • payment_method — espelha o type enviado na requisição.
  • pix — presente apenas quando type=pix; contém os dados do QR Code.
  • boleto — presente apenas quando type=boleto; contém a URL e o código de barras do boleto.
{
  "subscriber": {
    "id": "f4b1c7a9-8c2d-4d4f-9c3a-5e6f7a8b9c0d",
    "name": "Maria Souza",
    "email": "maria@example.com",
    "phone_number": "11988887777",
    "country_code": "+55",
    "taxpayer_id": "12345678901",
    "status": "paid",
    "next_billing_date": "2026-06-14T12:30:00-03:00",
    "subscribed_at": "2026-05-14T12:30:00-03:00",
    "saved_card": {
      "card_brand": "visa",
      "last4_digits": "4242",
      "holder_name": "MARIA SOUZA"
    }
  },
  "payment": {
    "id": "a1b2c3d4-e5f6-7890-abcd-ef0123456789",
    "status": "paid",
    "payment_method": "credit_card"
  }
}
Para PIX a resposta também inclui:
{
  "payment": {
    "id": "...",
    "status": "pending",
    "payment_method": "pix",
    "pix": {
      "qr_code": "00020101021226...",
      "qr_code_image": "https://...",
      "expiration_date": "2026-05-14T13:00:00-03:00"
    }
  }
}
Inconsistência conhecida do campo amount: o valor é exposto como string em centavos (ex.: "4990" = R$ 49,90), diferente da convenção em centavos inteiros adotada em outros endpoints. Trate-o como string e converta para inteiro antes de operar aritmeticamente.

Erros

StatusQuando
400Erro de validação: campos faltantes, CPF/CNPJ inválido, método de pagamento fora do payment_methods do plano, card ausente para cartão de crédito, address ou taxpayer_id ausentes para boleto, conta do plano mal configurada ou cartão recusado antes da cobrança.
402Cartão recusado pelo emissor. O corpo da resposta contém o motivo da recusa. Tanto o pagamento quanto o assinante são marcados como failed.
404Não existe plano com o plan_id informado.
500Falha inesperada de processamento. O pagamento e o assinante são marcados como failed.

Exemplos

curl -X POST https://api.dlpay.cloud/subscriptions/plan/8b0e9f4a-2b7d-4f3f-9d8a-1c2e3a4b5c6d/subscribe/ \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Maria Souza",
    "email": "maria@example.com",
    "phone_number": "11988887777",
    "taxpayer_id": "12345678901",
    "type": "credit_card",
    "installments": 1,
    "save_card": true,
    "card": {
      "number": "4242424242424242",
      "cvv": "123",
      "name": "MARIA SOUZA",
      "expirationMonth": "08",
      "expirationYear": "2028"
    }
  }'