> ## Documentation Index
> Fetch the complete documentation index at: https://docs.z2pay.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Cancelar assinatura

> Encerra o contrato, agora ou ao fim do período atual.

`POST /subscriptions/:id/cancel`

Faz parte do recurso [Assinaturas](/pt-BR/subscriptions) — o conceito e os dez estados estão lá.

Encerra a assinatura. `canceled` é terminal: não há rota que a traga de volta.

<Note>
  **Os dois modos resolvem problemas diferentes.** `immediate` encerra na hora — o cliente perde o
  acesso ao que resta do período que já pagou. `at_period_end` mantém a assinatura ativa até
  `currentPeriodEnd` e a encerra sozinha lá, que é o comportamento esperado por quem cancela uma
  mensalidade no meio do mês.
</Note>

<Note>
  **`at_period_end` é reversível; `immediate` não.** Enquanto a assinatura estiver dentro da janela,
  [`uncancel`](/pt-BR/subscriptions/uncancel) limpa o agendamento. Depois que o motor a transiciona
  para `canceled`, não há volta.
</Note>

<Warning>
  **`reason` e `reasonDetails` são obrigatórios.** Não é campo de analytics opcional: a chamada
  falha sem eles. Todo cancelamento fica registrado com justificativa.
</Warning>

<Warning>
  **As faturas futuras deixam de existir; as vencidas dependem de você.** `keepOverdueInvoices: true`
  preserva o que já venceu como dívida em aberto, `false` anula. Omitido, vale a configuração da sua
  conta — então uma integração que não envie o campo pode ter comportamentos diferentes entre
  contas. As faturas já pagas não são afetadas.
</Warning>

<Note>
  **Nem todo estado aceita cancelamento.** Estados terminais respondem `409`. Uma assinatura
  `incomplete` pode ser cancelada normalmente — é assim que se descarta uma que nunca ganhou forma
  de pagamento.
</Note>

<Warning>
  **O `cancellationReason` da resposta tem mais valores do que o corpo aceita.** Você envia um dos
  sete motivos de feedback, mas um cancelamento também acontece sem você pedir — e aí o campo traz
  o motivo sistêmico: `at_period_end` (o agendado que chegou a hora), `dunning_exhausted` (a régua
  desistiu), `from_unpaid`, `from_paused`, `during_trial`, `incomplete_abandon`,
  `enrollment_failed` e `enrollment_expired`.

  Um `switch` fechado nos sete valores de entrada não cobre a assinatura que foi cancelada sozinha.
  Trate o desconhecido como "outro".
</Warning>

## Exemplo

```bash theme={null}
curl -X POST https://api.sandbox.z2pay.com/v1/subscriptions/sub_x33m4yn6brazh71en4mki6f5c/cancel \
  -H "x-api-key: SUA_CHAVE_DE_SANDBOX" \
  -H "Content-Type: application/json" \
  -d '{
    "mode": "at_period_end",
    "reason": "too_expensive",
    "reasonDetails": "Cliente migrou para o plano anual de outro fornecedor."
  }'
```

```json Resposta 200 theme={null}
{
  "id": "sub_x33m4yn6brazh71en4mki6f5c",
  "status": "active",
  "cancelAtPeriodEnd": true,
  "canceledAt": "2026-08-10T18:05:00.000Z",
  "cancellationReason": "too_expensive",
  "currentPeriodEnd": "2026-09-10T12:00:00.000Z",
  "nextInvoiceAt": null,
  "updatedAt": "2026-08-10T18:05:00.000Z"
}
```

<Note>
  Com `at_period_end`, a resposta ainda traz `status: "active"` — o que mudou foi
  `cancelAtPeriodEnd`. O `canceledAt` já vem **preenchido com o instante do agendamento**, não do
  cancelamento efetivo: para saber se a assinatura ainda está de pé, leia `status` e
  `cancelAtPeriodEnd`, nunca o `canceledAt`. Uma integração que só olhe o `status` não vê o
  cancelamento agendado. Com `immediate`, o `status` já vem `canceled`.
</Note>


## OpenAPI

````yaml openapi/billing.json POST /subscriptions/{id}/cancel
openapi: 3.0.3
info:
  title: Z2Pay Billing API
  version: 1.0.0
  description: Cobrança recorrente da Z2Pay — planos, assinaturas e faturas
servers:
  - url: https://api.sandbox.z2pay.com/v1
    description: Sandbox
  - url: https://api.z2pay.com/v1
    description: Produção
security: []
tags:
  - name: Invoices
    description: Faturas emitidas pelas assinaturas
  - name: Plans
    description: Planos de cobrança e versões de preço
  - name: Subscriptions
    description: Assinaturas recorrentes
paths:
  /subscriptions/{id}/cancel:
    post:
      tags:
        - Subscriptions
      summary: Cancelar assinatura
      description: >-
        `mode=immediate` encerra a assinatura imediatamente.
        `mode=at_period_end` a mantém ativa até o fim do período atual e então
        transiciona automaticamente — dentro dessa janela, `POST
        /subscriptions/{id}/uncancel` desfaz o agendamento. `reason` e
        `reasonDetails` são **obrigatórios**: todo cancelamento fica registrado
        com justificativa. `keepOverdueInvoices` decide o destino das faturas já
        vencidas; as futuras deixam de existir de qualquer forma.
      operationId: SubscriptionController_cancel
      parameters:
        - name: id
          in: path
          required: true
          description: ID da assinatura
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: Chave única para garantir idempotência da requisição
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                mode:
                  type: string
                  enum:
                    - immediate
                    - at_period_end
                  default: immediate
                  description: >-
                    Quando o cancelamento vale. `immediate` (padrão) encerra
                    agora; `at_period_end` mantém a assinatura ativa até o fim
                    do período atual e a encerra sozinha lá.
                reason:
                  type: string
                  enum:
                    - too_expensive
                    - unused
                    - customer_service
                    - low_quality
                    - missing_features
                    - switched_service
                    - other
                  description: Motivo do cancelamento, para o seu histórico. Obrigatório.
                reasonDetails:
                  type: string
                  minLength: 1
                  maxLength: 500
                  description: >-
                    Justificativa em texto livre (1 a 500 caracteres).
                    Obrigatória.
                keepOverdueInvoices:
                  type: boolean
                  description: >-
                    O que fazer com as faturas já **vencidas**: `true` as
                    preserva como dívida em aberto, `false` as anula. Omitido,
                    vale a configuração da conta. Não afeta as pagas nem as
                    futuras — estas deixam de existir com o cancelamento.
              required:
                - reason
                - reasonDetails
      responses:
        '200':
          description: Assinatura cancelada ou agendada para cancelamento
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
                    description: Identificador único do registro.
                  number:
                    type: object
                    properties:
                      sequence:
                        type: integer
                        description: >-
                          Número sequencial do documento dentro da numeração
                          (assinatura ou fatura).
                    description: Número do endereço.
                  referenceCode:
                    type: string
                    description: >-
                      Código do contrato no sistema do integrador; pesquisável,
                      sem unicidade.
                    nullable: true
                  customerId:
                    type: string
                    description: ID do cliente associado ao registro.
                  customerEmail:
                    type: string
                    description: E-mail do cliente.
                  customerName:
                    type: string
                    description: Nome do cliente.
                  customerDocument:
                    type: string
                    description: Documento do cliente (CPF ou CNPJ).
                  currency:
                    type: string
                    description: 'Moeda no padrão ISO 4217 (ex.: BRL).'
                  status:
                    type: string
                    enum:
                      - incomplete
                      - incomplete_expired
                      - trialing
                      - active
                      - past_due
                      - unpaid
                      - paused
                      - canceled
                      - completed
                    description: >-
                      Status atual do registro (assinatura, fatura, plano ou
                      slip de pagamento).
                  billingGroupId:
                    nullable: true
                    description: >-
                      ID do grupo de cobrança ao qual o registro pertence; nulo
                      se não agrupado.
                  currentPeriodStart:
                    type: string
                    format: date-time
                    description: >-
                      Início do período de cobrança atual da assinatura (ISO
                      8601).
                  currentPeriodEnd:
                    type: string
                    format: date-time
                    description: Fim do período de cobrança atual da assinatura (ISO 8601).
                  nextInvoiceAt:
                    nullable: true
                    description: >-
                      Data e hora prevista para a próxima fatura da assinatura
                      (ISO 8601).
                  recurrence:
                    type: object
                    properties:
                      interval:
                        type: integer
                        description: >-
                          Quantidade de unidades por ciclo de cobrança (ex.:
                          interval 3 + unit month = trimestral).
                      unit:
                        type: string
                        description: >-
                          Unidade do ciclo de cobrança: day, week, month ou
                          year.
                      anchor:
                        type: string
                        description: >-
                          Âncora que fixa a data de renovação do ciclo:
                          subscription_start, day_of_month ou end_of_month.
                      anchorDay:
                        type: integer
                        description: >-
                          Dia do mês (1–31) usado quando a âncora é
                          day_of_month.
                      collectionTiming:
                        type: string
                        description: >-
                          Momento da cobrança do ciclo: prepaid (no início) ou
                          postpaid (no fim).
                    description: >-
                      Regra de recorrência (intervalo, unidade e âncora do
                      ciclo).
                  collectionMethod:
                    type: string
                    enum:
                      - charge_automatically
                    description: >-
                      Como a fatura é cobrada. Hoje só a cobrança automática na
                      forma de pagamento padrão.
                  collectionTiming:
                    type: string
                    enum:
                      - prepaid
                      - postpaid
                    description: >-
                      Momento da cobrança do ciclo: prepaid (no início) ou
                      postpaid (no fim).
                  invoiceGenerationMode:
                    type: string
                    enum:
                      - just_in_time
                      - upfront
                    description: >-
                      Modo de geração de faturas: just_in_time (a cada ciclo) ou
                      upfront (todas antecipadas).
                  cancelAtPeriodEnd:
                    type: boolean
                    description: >-
                      Indica se a assinatura será cancelada ao fim do período
                      atual.
                  canceledAt:
                    type: string
                    format: date-time
                    description: >-
                      Data e hora do cancelamento; nula se não cancelado (ISO
                      8601).
                  endedAt:
                    type: string
                    format: date-time
                    description: >-
                      Data e hora em que a assinatura foi efetivamente
                      encerrada; nula se ainda ativa (ISO 8601).
                  cancellationReason:
                    type: string
                    description: Motivo do cancelamento da assinatura.
                  pausedAt:
                    nullable: true
                    description: >-
                      Data e hora em que a assinatura foi pausada; nula se não
                      pausada (ISO 8601).
                  pauseResumesAt:
                    nullable: true
                    description: >-
                      Data e hora agendada para a retomada automática da
                      assinatura pausada (ISO 8601).
                  pauseReason:
                    nullable: true
                    description: Motivo da pausa da assinatura.
                  trialEnd:
                    nullable: true
                    description: >-
                      Data e hora de término do período de teste; nula se sem
                      trial (ISO 8601).
                  incompleteExpiresAt:
                    nullable: true
                    description: >-
                      Prazo para concluir o primeiro pagamento antes de a
                      assinatura incompleta expirar (ISO 8601).
                  trialRemindersFired:
                    type: array
                    items: {}
                    description: >-
                      Lembretes de fim do período de teste já disparados para a
                      assinatura.
                  maxCycles:
                    nullable: true
                    description: >-
                      Número máximo de ciclos da assinatura; nulo se não houver
                      limite.
                  issuedCycles:
                    type: integer
                    description: >-
                      Número de ciclos já faturados (faturas emitidas) da
                      assinatura.
                  completedCycles:
                    type: integer
                    description: Número de ciclos já concluídos (pagos) da assinatura.
                  defaultPaymentMethodRef:
                    type: object
                    properties:
                      id:
                        type: string
                        description: Identificador único do registro.
                        nullable: true
                      type:
                        type: string
                        description: >-
                          Tipo da referência: meio da forma de pagamento (card,
                          pix, boleto) ou natureza da linha da fatura.
                    description: >-
                      Referência da forma de pagamento padrão usada para cobrar
                      a assinatura.
                  splitConfig:
                    nullable: true
                    description: >-
                      Configuração de divisão (split) dos valores entre
                      recebedores; nula se sem split.
                  paymentBehavior:
                    type: string
                    enum:
                      - allow_incomplete
                      - error_if_incomplete
                    description: >-
                      O que fazer quando a primeira cobrança não é aprovada:
                      allow_incomplete cria a assinatura com a fatura em aberto;
                      error_if_incomplete cancela a assinatura.
                  latestInvoiceId:
                    type: string
                    description: ID da fatura mais recente gerada pela assinatura.
                  paymentUpdateToken:
                    nullable: true
                    description: >-
                      Token do link público para o cliente atualizar a forma de
                      pagamento; nulo se não gerado.
                  paymentUpdateMethods:
                    nullable: true
                    description: >-
                      Formas de pagamento permitidas no link público de troca;
                      nula se não habilitada.
                  metadata:
                    type: object
                    properties: {}
                    description: >-
                      Metadados livres (pares chave-valor) para uso do
                      integrador; não afeta o processamento.
                  createdAt:
                    type: string
                    format: date-time
                    description: Data e hora de criação do registro (ISO 8601).
                  updatedAt:
                    type: string
                    format: date-time
                    description: Data e hora da última atualização do registro (ISO 8601).
              example:
                id: sub_hsm2kigu74htdxj3nw2z6f9xw
                number:
                  sequence: 42
                referenceCode: CONTRATO-2026-0042
                customerId: cust_c72q6ogr9iko0we85mqal04te
                customerEmail: maria.silva@example.com
                customerName: Maria Silva
                customerDocument: '12345678909'
                currency: BRL
                status: canceled
                billingGroupId: null
                currentPeriodStart: '2025-06-01T03:00:00.000Z'
                currentPeriodEnd: '2025-07-01T03:00:00.000Z'
                nextInvoiceAt: null
                recurrence:
                  interval: 1
                  unit: month
                  anchor: day_of_month
                  anchorDay: 1
                  collectionTiming: prepaid
                collectionMethod: charge_automatically
                collectionTiming: prepaid
                invoiceGenerationMode: just_in_time
                cancelAtPeriodEnd: false
                canceledAt: '2025-06-29T13:45:30.000Z'
                endedAt: '2025-06-29T13:45:30.000Z'
                cancellationReason: too_expensive
                pausedAt: null
                pauseResumesAt: null
                pauseReason: null
                trialEnd: null
                incompleteExpiresAt: null
                trialRemindersFired: []
                maxCycles: null
                issuedCycles: 1
                completedCycles: 1
                defaultPaymentMethodRef:
                  id: crd_tsj66oabsygc9kwvvzt8189f9
                  type: card
                splitConfig: null
                paymentBehavior: allow_incomplete
                latestInvoiceId: inv_c3qahi4qnkc258lfc14gplupt
                paymentUpdateToken: null
                paymentUpdateMethods: null
                metadata: {}
                createdAt: '2025-06-01T13:45:30.000Z'
                updatedAt: '2025-06-29T13:45:30.000Z'
        '400':
          description: >-
            Requisição inválida — algum parâmetro ou campo do corpo não passou
            na validação
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: object
                    properties:
                      code:
                        type: string
                        description: >-
                          Identificador estável do erro. É por ele que você deve
                          ramificar, não pela mensagem.
                      message:
                        type: string
                        description: >-
                          Descrição legível. Pode mudar sem aviso e não deve ser
                          usada em condicional.
                      issues:
                        type: array
                        description: >-
                          Um item por campo rejeitado. Nunca vem vazio: se há
                          400 de validação, há pelo menos um.
                        items:
                          type: object
                          properties:
                            path:
                              type: string
                              description: >-
                                Campo que falhou. Vem vazio quando o erro é do
                                corpo como um todo.
                            message:
                              type: string
                              description: O que há de errado com esse campo.
              example:
                error:
                  code: VALIDATION_ERROR
                  message: Validation failed
                  issues:
                    - path: status
                      message: >-
                        Status inválido. Valores aceitos: pending,
                        waiting_payment, paid, refused, canceled, refunded
                    - path: startDate
                      message: >-
                        Data deve ser ISO 8601 com timezone (ex.:
                        2026-06-24T00:00:00Z)
        '401':
          description: Chave de API ausente, malformada ou inválida
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: object
                    properties:
                      code:
                        type: string
                        description: >-
                          Identificador estável do erro. É por ele que você deve
                          ramificar, não pela mensagem.
                      message:
                        type: string
                        description: >-
                          Descrição legível. Pode mudar sem aviso e não deve ser
                          usada em condicional.
              example:
                error:
                  code: UNAUTHORIZED
                  message: Invalid API key
        '404':
          description: Assinatura não encontrada
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: object
                    properties:
                      code:
                        type: string
                        description: >-
                          Identificador estável do erro. É por ele que você deve
                          ramificar, não pela mensagem.
                      message:
                        type: string
                        description: >-
                          Descrição legível. Pode mudar sem aviso e não deve ser
                          usada em condicional.
              example:
                error:
                  code: NOT_FOUND
                  message: Subscription not found
        '409':
          description: Assinatura em estado que não permite cancelamento
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: object
                    properties:
                      code:
                        type: string
                        description: >-
                          Identificador estável do erro. É por ele que você deve
                          ramificar, não pela mensagem.
                      message:
                        type: string
                        description: >-
                          Descrição legível. Pode mudar sem aviso e não deve ser
                          usada em condicional.
              example:
                error:
                  code: CONFLICT
                  message: No refundable payment found
        '422':
          description: >-
            Idempotency-Key já usada com um corpo diferente. Use uma chave nova
            para uma operação diferente
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    description: >-
                      Mensagem do conflito de idempotência. Aqui `error` é
                      texto, não objeto — ramifique pelo status HTTP.
              example:
                error: Idempotency key already used with a different request body
      security:
        - apiKey: []
components:
  securitySchemes:
    apiKey:
      type: apiKey
      in: header
      name: x-api-key
      description: API Key da Credential (gerada no Backoffice)

````