> ## 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.

# Criar plano

> Cria o plano com todos os seus itens e preços, já publicado e pronto para receber assinaturas.

`POST /plans`

Faz parte do recurso [Planos e Preços](/pt-BR/subscriptions/plans) — o item, o preço versionado e os
status estão lá.

Cria a oferta inteira numa chamada: o plano, cada entrada de `items` com o seu preço, e a
publicação. A resposta tem a mesma forma de [`GET /plans/{id}`](/pt-BR/subscriptions/plans/get) — o
plano com os itens e o preço em vigor de cada um.

<Note>
  **Não existe rascunho por aqui.** O plano nasce `active`, aceitando assinaturas. O status `draft`
  existe para o painel, onde uma tela precisa salvar um plano pela metade — uma chamada HTTP monta o
  objeto inteiro antes de enviar, e exigir uma publicação depois deixaria um plano que existe sem
  funcionar.
</Note>

<Warning>
  **Ao menos um item precisa ser `kind: "recurring"`.** Um plano só de `activation` não sustenta
  assinatura: a adesão cobra uma vez e não recorre, então não haveria o que faturar no segundo
  ciclo. A requisição responde `400` apontando `items`.
</Warning>

<Warning>
  **A `key` não se repete dentro do plano.** É por ela que a assinatura identifica o item, e duas
  iguais tornariam a referência ambígua. A resposta `400` aponta o índice do segundo item que a
  usou.
</Warning>

<Warning>
  **Adesão e período de teste se excluem.** Enviar `trialSpec` num plano cujos itens são todos
  `activation` responde `400`: diferir a única cobrança que a adesão tem não significa nada.
</Warning>

<Note>
  **A cadência e o teste são do plano, não de cada item.** Por isso `recurrence` e `trialSpec` vão
  na raiz, e o preço de cada item os herda — a assinatura tem um ciclo só, e dois itens com
  cadências diferentes não teriam quando cobrar juntos. A exceção é o item `activation`, que nunca
  recebe o teste mesmo com `trialSpec` preenchido na raiz.
</Note>

<Note>
  **O `code` é seu identificador do plano, e é único na conta.** Repetir um code já usado responde
  `409` — inclusive se o plano anterior estiver arquivado, porque arquivar não libera o código.
</Note>

<Note>
  **A validação roda sobre o corpo inteiro antes da primeira gravação.** Um erro no terceiro item
  não deixa os dois primeiros criados: ou o plano nasce completo, ou nada é gravado.
</Note>

## Exemplo

```bash theme={null}
curl -X POST https://api.sandbox.z2pay.com/v1/plans \
  -H "x-api-key: SUA_CHAVE_DE_SANDBOX" \
  -H "Content-Type: application/json" \
  -d '{
    "code": "pro-monthly",
    "name": "Plano Pro",
    "description": "Todos os recursos, cobrado mensalmente",
    "recurrence": {
      "interval": 1,
      "unit": "month",
      "anchor": "subscription_start",
      "collectionTiming": "prepaid"
    },
    "items": [
      {
        "item": { "key": "default", "name": "Assinatura Pro", "kind": "recurring" },
        "price": { "amount": 9900, "currency": "BRL" }
      }
    ]
  }'
```

```json Resposta 201 theme={null}
{
  "id": "plan_lhutpqeq2ml3stia4vn90xars",
  "code": "pro-monthly",
  "name": "Plano Pro",
  "status": "active",
  "recurrence": {
    "interval": 1,
    "unit": "month",
    "anchor": "subscription_start",
    "collectionTiming": "prepaid"
  },
  "trialSpec": null,
  "items": [
    {
      "id": "pli_oaimno59ai3uuqwq0ti7gxs0j",
      "key": "default",
      "name": "Assinatura Pro",
      "kind": "recurring",
      "quantityDefault": 1,
      "currentPrice": {
        "id": "price_l1r8693wk6ksbd9044bwvwu93",
        "amount": 9900,
        "currency": "BRL",
        "isCurrent": true
      }
    }
  ],
  "createdAt": "2026-08-10T13:45:30.000Z"
}
```

<Note>
  O exemplo acima está abreviado. A resposta completa traz todos os campos do item e do preço — o
  playground ao lado mostra o corpo inteiro.
</Note>


## OpenAPI

````yaml openapi/billing.json POST /plans
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:
  /plans:
    post:
      tags:
        - Plans
      summary: Criar plano
      description: >-
        O plano nasce pronto para vender: cada item de `items` é criado com seu
        preço e o plano é publicado (`active`) na mesma chamada. Toda a
        coerência do conjunto — cadência e período de teste iguais entre os
        itens recorrentes, `key` sem repetição — é validada antes de qualquer
        gravação.
      operationId: PlanController_create
      parameters:
        - 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:
                code:
                  type: string
                  minLength: 1
                  maxLength: 100
                  pattern: ^[a-z0-9-_]+$
                  description: >-
                    Identificador único do plano na sua conta. Apenas letras
                    minúsculas, números, hífen e underscore.
                name:
                  type: string
                  minLength: 1
                  maxLength: 255
                  description: Nome do plano.
                description:
                  type: string
                  maxLength: 1000
                  description: Descrição livre. Opcional.
                metadata:
                  type: object
                  additionalProperties: {}
                  description: >-
                    Objeto livre de chave/valor para dados seus. Devolvido nas
                    respostas e nos webhooks.
                recurrence:
                  type: object
                  properties:
                    interval:
                      type: integer
                      minimum: 0
                      exclusiveMinimum: true
                    unit:
                      type: string
                      enum:
                        - day
                        - week
                        - month
                        - year
                    anchor:
                      type: string
                      enum:
                        - subscription_start
                        - day_of_month
                        - end_of_month
                    anchorDay:
                      type: integer
                      minimum: 1
                      maximum: 31
                    collectionTiming:
                      type: string
                      enum:
                        - prepaid
                        - postpaid
                      default: prepaid
                  required:
                    - interval
                    - unit
                    - anchor
                  description: >-
                    Cadência da cobrança: a cada quantas unidades (`interval`),
                    qual unidade (`unit`), a âncora do ciclo e se cobra no
                    início ou no fim. Vale para todos os itens recorrentes.
                trialSpec:
                  type: object
                  properties:
                    durationDays:
                      type: integer
                      minimum: 0
                    requiresPaymentMethod:
                      type: boolean
                  required:
                    - durationDays
                    - requiresPaymentMethod
                  description: >-
                    Período de teste padrão da oferta. A assinatura pode
                    sobrescrevê-lo.
                items:
                  type: array
                  items:
                    type: object
                    properties:
                      item:
                        type: object
                        properties:
                          key:
                            type: string
                            minLength: 1
                            maxLength: 100
                            pattern: ^[a-z0-9-_]+$
                            description: >-
                              Slug estável do item, único dentro do plano. É por
                              ele que a assinatura escolhe quais itens opcionais
                              incluir.
                          name:
                            type: string
                            minLength: 1
                            maxLength: 255
                            description: Nome do item, como aparece na fatura.
                          kind:
                            type: string
                            enum:
                              - recurring
                              - activation
                            default: recurring
                            description: >-
                              `recurring` cobra todo ciclo; `activation` cobra
                              uma única vez, na adesão.
                          quantityDefault:
                            type: integer
                            minimum: 0
                            exclusiveMinimum: true
                            default: 1
                            description: >-
                              Quantidade cobrada quando a assinatura não informa
                              outra.
                          displayOrder:
                            type: integer
                            minimum: 0
                            default: 0
                            description: >-
                              Ordem em que o item aparece quando você consulta o
                              plano.
                          description:
                            type: string
                            maxLength: 1000
                            description: Descrição do item. Opcional.
                          metadata:
                            type: object
                            additionalProperties: {}
                            description: Objeto livre de chave/valor. Opcional.
                        required:
                          - key
                          - name
                        description: O item do plano — o que aparece na linha da fatura.
                      price:
                        type: object
                        properties:
                          billingScheme:
                            type: string
                            enum:
                              - fixed
                            default: fixed
                            description: >-
                              Forma de cobrança. Hoje só `fixed` (valor fixo por
                              ciclo).
                          amount:
                            type: integer
                            minimum: 0
                            description: >-
                              Valor da cobrança, em centavos (menor unidade da
                              moeda).
                          currency:
                            type: string
                            enum:
                              - BRL
                            description: >-
                              Código de moeda ISO 4217. Hoje o único valor
                              aceito é 'BRL'.
                            default: BRL
                        required:
                          - amount
                        description: 'O preço inicial desse item: quanto e com que cadência.'
                    required:
                      - item
                      - price
                  minItems: 1
                  description: >-
                    Itens do plano, cada um com seu preço. Ao menos um deve ser
                    `kind: "recurring"`.
              required:
                - code
                - name
                - recurrence
                - items
      responses:
        '201':
          description: Plano criado, com os itens e o preço de cada um
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
                    description: Identificador único do registro.
                  code:
                    type: string
                    description: >-
                      Código de identificação do recurso (ex.: código do plano
                      ou do contrato).
                  name:
                    type: string
                    description: Nome de exibição do plano ou do componente.
                  description:
                    type: string
                    nullable: true
                    description: Descrição do item (item do plano ou linha da fatura).
                  status:
                    type: string
                    description: >-
                      Status atual do registro (assinatura, fatura, plano ou
                      slip de pagamento).
                  recurrence:
                    type: object
                    nullable: true
                    description: >-
                      Cadência da cobrança: a cada quantas unidades
                      (`interval`), qual unidade (`unit`), a âncora do ciclo e
                      se cobra no início ou no fim. Vale para todos os itens
                      recorrentes.
                  trialSpec:
                    type: object
                    nullable: true
                    description: >-
                      Período de teste padrão da oferta. A assinatura pode
                      sobrescrevê-lo.
                  metadata:
                    type: object
                    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).
                  items:
                    type: array
                    description: Itens do plano, cada um com o preço em vigor.
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                          description: Identificador único do registro.
                        planId:
                          type: string
                          description: ID do plano ao qual o registro pertence.
                        key:
                          type: string
                          description: >-
                            Chave única e legível (slug) do componente dentro do
                            plano.
                        name:
                          type: string
                          description: Nome de exibição do plano ou do componente.
                        kind:
                          type: string
                          enum:
                            - recurring
                            - activation
                          description: >-
                            Natureza da cobrança: `recurring` cobra a cada
                            ciclo; `activation` cobra uma única vez, na fatura
                            de adesão.
                        quantityDefault:
                          type: integer
                          description: >-
                            Quantidade padrão do componente ao instanciar a
                            assinatura.
                        displayOrder:
                          type: integer
                          description: >-
                            Ordem de exibição do componente na listagem do
                            plano.
                        description:
                          type: string
                          nullable: true
                          description: >-
                            Descrição do item (item do plano ou linha da
                            fatura).
                        metadata:
                          type: object
                          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).
                        currentPrice:
                          type: object
                          nullable: true
                          properties:
                            id:
                              type: string
                              description: Identificador único do registro.
                            planItemId:
                              type: string
                              description: >-
                                ID do componente (plan item) ao qual o preço se
                                refere.
                            planId:
                              type: string
                              description: ID do plano ao qual o registro pertence.
                            billingScheme:
                              type: string
                              description: >-
                                Esquema de cobrança do preço: fixed, per_unit,
                                tiered, package ou metered.
                            amount:
                              type: integer
                              description: Valor do preço ou da linha, em centavos.
                            currency:
                              type: string
                              description: 'Moeda no padrão ISO 4217 (ex.: BRL).'
                            recurrence:
                              type: object
                              description: >-
                                Regra de recorrência (intervalo, unidade e
                                âncora do ciclo).
                            trialSpec:
                              type: object
                              nullable: true
                              description: >-
                                Configuração do período de teste (trial) do
                                preço; nula se sem trial.
                            isCurrent:
                              type: boolean
                              description: >-
                                Indica se esta é a versão de preço atualmente
                                vigente.
                            publishedAt:
                              type: string
                              format: date-time
                              nullable: true
                              description: >-
                                Data e hora em que a versão de preço foi
                                publicada (ISO 8601).
                            archivedAt:
                              type: string
                              format: date-time
                              nullable: true
                              description: >-
                                Data e hora em que a versão de preço foi
                                arquivada; nula se ainda vigente (ISO 8601).
                            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).
                          description: Versão de preço vigente do item do plano.
              example:
                id: plan_lhutpqeq2ml3stia4vn90xars
                code: pro-monthly
                name: Pro Plan
                description: Pro tier with all features
                status: active
                recurrence:
                  interval: 1
                  unit: month
                  anchor: subscription_start
                  collectionTiming: prepaid
                trialSpec: null
                metadata: {}
                createdAt: '2025-06-29T13:45:30.000Z'
                updatedAt: '2025-06-29T13:45:30.000Z'
                items:
                  - id: pli_oaimno59ai3uuqwq0ti7gxs0j
                    planId: plan_lhutpqeq2ml3stia4vn90xars
                    key: default
                    name: Pro Subscription
                    kind: recurring
                    quantityDefault: 1
                    displayOrder: 0
                    description: null
                    metadata: {}
                    createdAt: '2025-06-29T13:45:30.000Z'
                    updatedAt: '2025-06-29T13:45:30.000Z'
                    currentPrice:
                      id: price_l1r8693wk6ksbd9044bwvwu93
                      planItemId: pli_oaimno59ai3uuqwq0ti7gxs0j
                      planId: plan_lhutpqeq2ml3stia4vn90xars
                      billingScheme: fixed
                      amount: 9900
                      currency: BRL
                      recurrence:
                        interval: 1
                        unit: month
                        anchor: subscription_start
                        collectionTiming: prepaid
                      trialSpec: null
                      isCurrent: true
                      publishedAt: '2025-06-29T13:45:30.000Z'
                      archivedAt: null
                      createdAt: '2025-06-29T13:45:30.000Z'
                      updatedAt: '2025-06-29T13:45:30.000Z'
        '400':
          description: Falha de validação no plano, num item ou num preç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
        '409':
          description: Já existe um plano com este code
          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)

````