> ## 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 checkout link

> Cria um template de cobrança reutilizável e devolve a URL pronta para divulgar.

`POST /checkout/links`

Faz parte do recurso [Links](/pt-BR/checkout/links) — o conceito, a Session gerada e os estados
estão lá.

Cria o template e devolve `201` com o Link inteiro, já com a `url` de pagamento. São obrigatórios os
**itens** e os **métodos de pagamento**; o resto tem default ou é opcional. O Link nasce `active` e
passa a vender na hora — cada abertura da URL materializa uma Session nova.

<Warning>
  **Valores são inteiros em centavos.** R\$ 99,90 é `9990`. Enviar `9.90` é recusado com `400`
  (`integer` requerido), mas `9` **passa** e vira nove centavos. Veja
  [Convenções](/pt-BR/convencoes).
</Warning>

<Warning>
  **Split exige soma 100 e exatamente um responsável.** As `percentage` somam 100 (tolerância de
  ±0.01 para arredondamento) **e** um único item do array tem `liable: true` — nenhum ou mais de um
  é recusado com `400`. O responsável é obrigatório porque chargeback sempre precisa de um dono; não
  existe divisão em que o prejuízo fique sem endereço.
</Warning>

<Warning>
  **O `slug` é único globalmente, não só na sua conta.** Se outra conta já usa aquele texto, a
  resposta é `409` com `key: "errors.checkout.slug_taken"`. Quando você envia um slug, a `url` da
  resposta já vem como `/c/{slug}` em vez de `/c/{id}`.
</Warning>

<Note>
  **`select` sem `options` é aceito, e quebra na página.** A API não recusa um campo customizado do
  tipo `select` sem opções — ele é criado e o comprador vê um dropdown vazio, sem como responder.
  Confira antes de publicar.
</Note>

<Note>
  **E-mail, documento e telefone sempre são exigidos.** O checkout os mescla em `requiredFields`
  mesmo que você não os liste — por isso a resposta nunca traz o campo vazio —, e confere o dígito
  verificador do documento. `address` é o único opt-in: só entra se você o listar. O nome o
  comprador informa na página, mas não há como torná-lo obrigatório — `name` não é um valor aceito
  em `requiredFields`.
</Note>

<Note>
  **A escrita é plana, a leitura é aninhada.** Aqui você envia `items`, `paymentMethods`, `splits` e
  `branding` no topo do corpo. Na leitura ([`GET /checkout/links/{id}`](/pt-BR/checkout/links/get))
  esses quatro voltam dentro de `config`. Os demais campos ficam no topo nos dois sentidos. O
  detalhe importa ao
  [espelhar um Link numa venda rápida](/pt-BR/checkout/charges#espelhar-a-config-de-um-link-numa-venda-rápida).
</Note>

<Note>
  **O conflito de domínio não vai em `code`.** Todo `409` de regra responde `code: "CONFLICT"` — o
  que distingue um caso do outro é a `key`, com o prefixo inteiro
  (`errors.checkout.slug_taken`). Comparar `error.code === "slug_taken"` nunca casa. Veja
  [Erros de domínio](/pt-BR/erros#erros-de-dom%C3%ADnio-a-key).
</Note>

<Info>
  Endpoint idempotente. Envie `Idempotency-Key` para que um retry por timeout não crie dois Links.
  Veja [Convenções](/pt-BR/convencoes#idempot%C3%AAncia).
</Info>

## Exemplo

```bash theme={null}
curl -X POST https://api.sandbox.z2pay.com/v1/checkout/links \
  -H "x-api-key: SUA_CHAVE_DE_SANDBOX" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 7c9e6679-7425-40de-944b-e07fc1f90ae7" \
  -d '{
    "name": "Curso de Backend",
    "description": "Link para divulgação no Instagram",
    "items": [
      { "name": "Curso de Backend — vitalício", "quantity": 1, "unitAmount": 49900 }
    ],
    "paymentMethods": {
      "card": { "enabled": true, "installments": { "maxInstallments": 12, "freeInstallments": 3 } },
      "pix":  { "enabled": true, "expiresIn": 3600 }
    },
    "branding": { "primaryColor": "#1e3b79", "merchantName": "Henrique Cursos" },
    "metadata": { "campaign": "instagram-bio-2026-05" }
  }'
```

```json Resposta 201 theme={null}
{
  "id": "chk_byd8p3p79re859jpkmr0j65n3",
  "name": "Curso de Backend",
  "description": "Link para divulgação no Instagram",
  "slug": null,
  "status": "active",
  "sellable": true,
  "mode": "payment",
  "currency": "BRL",
  "locale": "pt-BR",
  "config": {
    "items": [
      { "name": "Curso de Backend — vitalício", "quantity": 1, "unitAmount": 49900 }
    ],
    "paymentMethods": { "...": "..." },
    "splits": null,
    "branding": { "primaryColor": "#1e3b79", "merchantName": "Henrique Cursos" }
  },
  "requiredFields": ["email", "document", "phone"],
  "customFields": null,
  "successUrl": null,
  "cancelUrl": null,
  "metadata": { "campaign": "instagram-bio-2026-05" },
  "expirationMinutes": 1440,
  "createdAt": "2026-06-24T12:00:00.000Z",
  "updatedAt": "2026-06-24T12:00:00.000Z",
  "url": "https://pay.sandbox.z2pay.com/c/chk_byd8p3p79re859jpkmr0j65n3"
}
```

A `url` da resposta é o link pronto para compartilhar. Cada abertura materializa uma Session nova.


## OpenAPI

````yaml openapi/checkout.json POST /checkout/links
openapi: 3.0.3
info:
  title: Z2Pay Checkout API
  version: 1.0.0
  description: >-
    API pública dedicada do Checkout. Autenticação via header x-api-key com a
    API key unificada da conta (z2_{live|test}_{sk|pk}_...). Endpoints privados
    exigem uma key secret (sk); endpoints públicos aceitam a key publishable
    (pk) consumida pelo frontend do comprador.
servers:
  - url: https://api.sandbox.z2pay.com/v1
    description: Sandbox
  - url: https://api.z2pay.com/v1
    description: Produção
security: []
tags:
  - name: Checkout Links
    description: Checkout Links (integração API via sk_)
  - name: Checkout Sessions
    description: Checkout Sessions (integração API via sk_)
  - name: Vendas rápidas
    description: Cobrança individual sem Link — Sessions ad-hoc criadas com a chave secreta
paths:
  /checkout/links:
    post:
      tags:
        - Checkout Links
      summary: Criar checkout link
      description: >-
        Cria um CheckoutLink persistente — a URL gerada pode ser compartilhada N
        vezes e cada abertura materializa uma Session.
      operationId: CheckoutLinkApiController_create
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  maxLength: 255
                  nullable: true
                  description: Nome do link de checkout.
                description:
                  type: string
                  maxLength: 2000
                  nullable: true
                  description: Descrição exibida no checkout.
                slug:
                  type: string
                  pattern: ^[a-z0-9-]+$
                  minLength: 3
                  maxLength: 100
                  nullable: true
                  description: >-
                    Slug único global usado na URL pública /c/{slug} (a-z, 0-9 e
                    hífen).
                mode:
                  type: string
                  enum:
                    - payment
                    - subscription
                  default: payment
                  description: >-
                    'payment' (default) para pagamento único; 'subscription'
                    exige o objeto subscription populado.
                currency:
                  type: string
                  enum:
                    - BRL
                  default: BRL
                  description: Moeda da cobrança. Só `BRL` — os gateways liquidam em real.
                locale:
                  type: string
                  enum:
                    - pt-BR
                    - en-US
                    - es-ES
                  default: pt-BR
                  description: Idioma do checkout (default 'pt-BR').
                items:
                  type: array
                  items:
                    type: object
                    properties:
                      name:
                        type: string
                        minLength: 1
                        maxLength: 255
                        description: Nome do item exibido no checkout.
                      description:
                        type: string
                        maxLength: 2000
                        description: Descrição do item.
                      imageUrl:
                        type: string
                        format: uri
                        maxLength: 2000
                        description: URL da imagem do item.
                      quantity:
                        type: integer
                        minimum: 1
                        description: Quantidade do item (inteiro ≥ 1).
                      unitAmount:
                        type: integer
                        minimum: 1
                        description: Preço UNITÁRIO do item, em centavos (inteiro ≥ 1).
                      chargeType:
                        type: string
                        enum:
                          - one_time
                          - recurring
                          - activation
                        description: >-
                          Eixo de cobrança da linha: ausente/'one_time' em
                          pagamento único; 'recurring'/'activation' espelham
                          PlanItem.kind em mode=subscription.
                      metadata:
                        type: object
                        additionalProperties:
                          type: string
                        description: Metadados livres do item (string → string).
                    required:
                      - name
                      - quantity
                      - unitAmount
                  default: []
                  description: >-
                    Itens do carrinho (unitAmount em centavos); ao menos 1
                    quando mode=payment.
                paymentMethods:
                  type: object
                  properties:
                    card:
                      type: object
                      properties:
                        enabled:
                          type: boolean
                        installments:
                          type: object
                          properties:
                            maxInstallments:
                              type: integer
                              minimum: 1
                              maximum: 12
                            freeInstallments:
                              type: integer
                              minimum: 0
                              maximum: 12
                            interestRate:
                              type: number
                              minimum: 0
                              maximum: 100
                            interestType:
                              type: string
                              enum:
                                - simple
                                - compound
                              default: compound
                          required:
                            - maxInstallments
                        threeDSecure:
                          type: boolean
                          description: >-
                            Liga a autenticação 3D Secure para os pagamentos com
                            cartão deste checkout. Aceita `true` ou `false`;
                            default `false` (sem desafio). Exige 3DS habilitado
                            para a conta — sem a habilitação o campo é aceito e
                            ignorado (nenhum erro, nenhum desafio); se a conta
                            for habilitada depois, os checkouts com `true`
                            passam a desafiar automaticamente.
                      required:
                        - enabled
                    pix:
                      type: object
                      properties:
                        enabled:
                          type: boolean
                        expiresIn:
                          type: integer
                          minimum: 60
                          maximum: 86400
                      required:
                        - enabled
                    boleto:
                      type: object
                      properties:
                        enabled:
                          type: boolean
                        dueDateDays:
                          type: integer
                          minimum: 1
                          maximum: 30
                      required:
                        - enabled
                    combined:
                      type: object
                      properties:
                        enabled:
                          type: boolean
                        minAmountPerPayment:
                          type: integer
                          minimum: 1
                        maxPaymentsCount:
                          type: integer
                          minimum: 2
                          maximum: 8
                      required:
                        - enabled
                  description: >-
                    Métodos de pagamento habilitados (card/pix/boleto/combined);
                    ao menos um enabled.
                splits:
                  type: array
                  items:
                    type: object
                    properties:
                      recipientId:
                        type: string
                        minLength: 1
                        description: Recebedor (`rec_`) que fica com esta fatia.
                      percentage:
                        type: number
                        minimum: 0.01
                        maximum: 100
                        description: >-
                          Fatia do valor total, em porcentagem. Aceita decimais
                          (`33.33`).
                      liable:
                        type: boolean
                        description: >-
                          Marca o recebedor como responsável por chargebacks.
                          Exatamente um split do array precisa ter `true` —
                          nenhum ou mais de um é recusado.
                    required:
                      - recipientId
                      - percentage
                  nullable: true
                  description: >-
                    Divisão de receita por percentual; a soma deve ser
                    exatamente 100.
                branding:
                  type: object
                  properties:
                    primaryColor:
                      type: string
                      pattern: ^#([0-9a-f]{6}|[0-9a-f]{3})$
                      description: 'Cor primária do checkout em hex (#RRGGBB ou #RGB).'
                    logoUrl:
                      type: string
                      format: uri
                      maxLength: 2000
                      description: URL do logo exibido no checkout.
                    merchantName:
                      type: string
                      maxLength: 100
                      description: Nome do vendedor exibido no checkout (≤ 100 chars).
                    mobileLayout:
                      type: string
                      enum:
                        - single-page
                        - step-by-step
                      description: 'Layout no mobile: ''single-page'' ou ''step-by-step''.'
                    faviconUrl:
                      type: string
                      format: uri
                      maxLength: 2000
                      description: URL do favicon da página de checkout.
                    coverUrl:
                      type: string
                      format: uri
                      maxLength: 2000
                      description: URL da imagem de capa do checkout.
                  nullable: true
                  description: Customização visual do checkout.
                subscription:
                  type: object
                  properties:
                    planId:
                      type: string
                      minLength: 1
                      description: >-
                        ID de um plano publicado. Com ele, a assinatura nasce do
                        plano — itens, preços e cadência vêm de lá. Sem ele, a
                        assinatura é montada avulsa e `recurrence` e `currency`
                        passam a ser obrigatórios.
                    recurrence:
                      type: object
                      properties:
                        interval:
                          type: integer
                          minimum: 0
                          exclusiveMinimum: true
                          maximum: 120
                          description: >-
                            Quantidade de unidades entre cobranças: 1 com
                            unit=month é mensal; 3, trimestral.
                        unit:
                          type: string
                          enum:
                            - day
                            - week
                            - month
                            - year
                          description: Unidade do intervalo entre cobranças.
                        anchor:
                          type: string
                          enum:
                            - subscription_start
                            - day_of_month
                          default: subscription_start
                          description: >-
                            O que define a data da próxima cobrança:
                            `subscription_start` (default) usa o aniversário da
                            assinatura; `day_of_month` fixa um dia do mês e
                            exige `anchorDay` com `unit=month`.
                        anchorDay:
                          type: integer
                          minimum: 0
                          maximum: 31
                          description: >-
                            Dia da âncora — do mês (1 a 31) ou da semana (0 a
                            6). Obrigatório quando `anchor` não é
                            `subscription_start`; ignorado quando é.
                      required:
                        - interval
                        - unit
                      description: >-
                        Com que frequência cobrar. Obrigatório na assinatura
                        avulsa; com `planId`, é herdado do plano.
                    currency:
                      type: string
                      enum:
                        - BRL
                      description: >-
                        Moeda da assinatura. Só `BRL`. Omitido, herda a do link.
                        Obrigatório na assinatura avulsa.
                    trialDays:
                      type: integer
                      minimum: 0
                      maximum: 365
                      description: >-
                        Dias de teste antes da primeira cobrança recorrente. `0`
                        ou omitido é sem teste. Com teste, o cartão é o único
                        método aceito.
                    maxCycles:
                      type: integer
                      minimum: 0
                      exclusiveMinimum: true
                      nullable: true
                      description: >-
                        Quantos ciclos cobrar antes de encerrar a assinatura.
                        Omitido ou `null`, ela cobra até ser cancelada.
                    collectionTiming:
                      type: string
                      enum:
                        - prepaid
                        - postpaid
                      default: prepaid
                      description: >-
                        Quando cobrar dentro do ciclo: `prepaid` (default) no
                        início, `postpaid` no fim. Em `postpaid`, a primeira
                        cobrança só tem valor se houver item de adesão.
                    metadata:
                      type: object
                      additionalProperties: {}
                      description: Dados livres seus, devolvidos junto com a assinatura.
                    itemCovers:
                      type: object
                      additionalProperties:
                        type: string
                        format: uri
                        maxLength: 2000
                      description: >-
                        Imagem de capa por item do plano, indexada pelo id do
                        item (`pli_`). Só apresentação — não afeta o que é
                        cobrado.
                    maxEnrollmentInstallments:
                      type: integer
                      minimum: 1
                      maximum: 12
                      default: 1
                      description: >-
                        Em quantas parcelas a taxa de adesão pode ser paga. `1`
                        (default) é à vista, até 12. O parcelamento é do canal
                        de venda, não do plano: o mesmo plano pode ser vendido à
                        vista num link e parcelado em outro. Sem cartão
                        habilitado, não tem efeito.
                  nullable: true
                  description: >-
                    Configuração de recorrência; obrigatória (e exclusiva)
                    quando mode=subscription.
                requiredFields:
                  type: array
                  items:
                    type: string
                    enum:
                      - email
                      - document
                      - phone
                      - address
                  nullable: true
                  description: >-
                    Campos do comprador exigidos no checkout (email, document,
                    phone, address).
                customFields:
                  type: array
                  items:
                    type: object
                    properties:
                      key:
                        type: string
                        pattern: ^[a-z][a-z0-9_]*$
                        maxLength: 50
                      label:
                        oneOf:
                          - type: string
                            minLength: 1
                            maxLength: 200
                          - type: object
                            additionalProperties:
                              type: string
                              minLength: 1
                              maxLength: 200
                      type:
                        type: string
                        enum:
                          - text
                          - select
                          - checkbox
                      options:
                        type: array
                        items:
                          oneOf:
                            - type: string
                              maxLength: 100
                            - type: object
                              properties:
                                value:
                                  type: string
                                  maxLength: 100
                                label:
                                  oneOf:
                                    - type: string
                                      minLength: 1
                                      maxLength: 200
                                    - type: object
                                      additionalProperties:
                                        type: string
                                        minLength: 1
                                        maxLength: 200
                              required:
                                - value
                                - label
                      required:
                        type: boolean
                    required:
                      - key
                      - label
                      - type
                  maxItems: 20
                  nullable: true
                  description: Campos customizados do formulário (máx. 20).
                successUrl:
                  type: string
                  format: uri
                  maxLength: 2000
                  nullable: true
                  description: URL de redirecionamento após pagamento aprovado.
                cancelUrl:
                  type: string
                  format: uri
                  maxLength: 2000
                  nullable: true
                  description: URL de redirecionamento quando o comprador cancela.
                metadata:
                  type: object
                  additionalProperties:
                    type: string
                  nullable: true
                  description: >-
                    Metadados do seller (string → string), consultáveis no
                    próprio link. Não são propagados à Transaction; para
                    correlacionar vendas ao link nos webhooks, use o
                    additionalInfo.checkoutLinkId da Transaction.
                expirationMinutes:
                  type: integer
                  minimum: 5
                  maximum: 43200
                  nullable: true
                  description: Expiração da sessão em minutos (5 a 43200 = 30 dias).
              required:
                - paymentMethods
            examples:
              apenasCartaoParcelamentoSimples:
                summary: Apenas cartão (parcelamento simples)
                description: >-
                  Uma única aba "Cartão". Seletor mostra 1× sem juros, 2–6× com
                  juros.
                value:
                  name: Apenas cartão
                  items:
                    - name: Produto Teste
                      quantity: 1
                      unitAmount: 19900
                  paymentMethods:
                    card:
                      enabled: true
                      installments:
                        maxInstallments: 6
                        freeInstallments: 1
              apenasPixExpiraEm1h:
                summary: Apenas PIX (expira em 1h)
                description: Aba PIX única, QR code expira em 1h.
                value:
                  name: Apenas PIX
                  items:
                    - name: Doação
                      quantity: 1
                      unitAmount: 5000
                  paymentMethods:
                    pix:
                      enabled: true
                      expiresIn: 3600
              apenasBoletoVenceEm5Dias:
                summary: Apenas boleto (vence em 5 dias)
                description: Aba boleto única, vencimento em 5 dias.
                value:
                  name: Apenas boleto
                  items:
                    - name: Mensalidade
                      quantity: 1
                      unitAmount: 12000
                  paymentMethods:
                    boleto:
                      enabled: true
                      dueDateDays: 5
              todosOsMetodos:
                summary: Todos os métodos
                description: 3 abas; cartão até 12× sem juros; PIX 30min; boleto 3 dias.
                value:
                  name: Todos os métodos
                  items:
                    - name: E-book Premium
                      quantity: 1
                      unitAmount: 9900
                  paymentMethods:
                    card:
                      enabled: true
                      installments:
                        maxInstallments: 12
                        freeInstallments: 12
                    pix:
                      enabled: true
                      expiresIn: 1800
                    boleto:
                      enabled: true
                      dueDateDays: 3
              multiplosItens:
                summary: Múltiplos itens
                description: >-
                  3 linhas de item, total R\$ 998,00 (`49900 + 4900 + 3 ×
                  15000`).
                value:
                  name: Múltiplos itens
                  items:
                    - name: Curso Backend
                      quantity: 1
                      unitAmount: 49900
                    - name: Material PDF
                      quantity: 1
                      unitAmount: 4900
                    - name: Mentoria (3x)
                      quantity: 3
                      unitAmount: 15000
                  paymentMethods:
                    card:
                      enabled: true
              itemComImagemEDescricao:
                summary: Item com imagem e descrição
                description: >-
                  Thumbnail à esquerda; descrição abaixo do nome; quantidade 2;
                  total R\$ 158,00.
                value:
                  name: Item com imagem
                  items:
                    - name: Camiseta Tech — Tamanho M
                      description: 100% algodão, estampa em silk
                      imageUrl: https://exemplo.com/camiseta-m.jpg
                      quantity: 2
                      unitAmount: 7900
                  paymentMethods:
                    card:
                      enabled: true
                    pix:
                      enabled: true
              brandingCorLogoNome:
                summary: Branding (cor + logo + nome)
                description: >-
                  Botões/ações em verde; logo no header; nome "Loja Verde"
                  exibido.
                value:
                  name: Branding completo
                  items:
                    - name: Produto
                      quantity: 1
                      unitAmount: 5000
                  paymentMethods:
                    pix:
                      enabled: true
                  branding:
                    primaryColor: '#16a34a'
                    merchantName: Loja Verde
                    logoUrl: https://exemplo.com/logo-verde.png
              localeEnUsEsEs:
                summary: Locale en-US / es-ES
                description: >-
                  Use `"locale": "es-ES"` para a página em espanhol. A página
                  inteira segue o idioma escolhido.
                value:
                  name: Inglês
                  locale: en-US
                  items:
                    - name: Online Course
                      quantity: 1
                      unitAmount: 29900
                  paymentMethods:
                    card:
                      enabled: true
              enderecoObrigatorioRequiredFields:
                summary: Endereço obrigatório (required fields)
                description: O form de endereço completo aparece antes do pagamento.
                value:
                  name: Endereço obrigatório
                  items:
                    - name: Produto físico
                      quantity: 1
                      unitAmount: 8900
                  paymentMethods:
                    card:
                      enabled: true
                  requiredFields:
                    - email
                    - document
                    - phone
                    - address
              customFieldsTextSelectCheckbox:
                summary: Custom fields (text + select + checkbox)
                description: "3 campos extras; select com 3 opções; checkbox opcional. Bloqueia o confirm sem\r\n    `experience_level`."
                value:
                  name: Custom fields
                  items:
                    - name: Workshop
                      quantity: 1
                      unitAmount: 19900
                  paymentMethods:
                    pix:
                      enabled: true
                  customFields:
                    - key: company_name
                      label: Nome da empresa
                      type: text
                      required: false
                    - key: experience_level
                      label:
                        pt-BR: Nível de experiência
                        en-US: Experience level
                      type: select
                      options:
                        - value: junior
                          label: Júnior
                        - value: pleno
                          label: Pleno
                        - value: senior
                          label: Sênior
                      required: true
                    - key: newsletter
                      label: Quero receber novidades por e-mail
                      type: checkbox
              splits7030Marketplace:
                summary: Splits 70/30 (marketplace)
                description: "Comprador vê total R\\$ 100,00; após pagar, R\\$ 70 vão para o seller principal e R\\$ 30 para a\r\n    plataforma."
                value:
                  name: Marketplace 70/30
                  items:
                    - name: Pedido marketplace
                      quantity: 1
                      unitAmount: 10000
                  paymentMethods:
                    card:
                      enabled: true
                    pix:
                      enabled: true
                  splits:
                    - recipientId: rec_seller_principal
                      percentage: 70
                      liable: true
                    - recipientId: rec_plataforma
                      percentage: 30
              parcelamentoComJurosCompostos:
                summary: Parcelamento com juros compostos
                description: "1×/2×/3× sem juros; 4–10× com 2,99% ao mês (preço/Tabela). Comprador vê o valor da parcela e o\r\n    total final."
                value:
                  name: Juros compostos
                  items:
                    - name: Notebook
                      quantity: 1
                      unitAmount: 350000
                  paymentMethods:
                    card:
                      enabled: true
                      installments:
                        maxInstallments: 10
                        freeInstallments: 3
                        interestRate: 2.99
                        interestType: compound
              cartaoCom3dSecure:
                summary: Cartão com 3D Secure
                description: "Liga a autenticação 3DS nos pagamentos com cartão deste link. Exige 3DS habilitado para a\r\n    conta — sem a habilitação o campo é aceito e ignorado (nenhum erro, nenhum desafio); habilitando\r\n    a conta depois, este link passa a desafiar sozinho."
                value:
                  name: Cartão com 3DS
                  items:
                    - name: Produto de alto valor
                      quantity: 1
                      unitAmount: 250000
                  paymentMethods:
                    card:
                      enabled: true
                      threeDSecure: true
                      installments:
                        maxInstallments: 6
                        freeInstallments: 6
              successCancelUrls:
                summary: Success / Cancel URLs
                description: "Após aprovação, o comprador é redirecionado para `successUrl`. Você pode usar\r\n    `{CHECKOUT_SESSION_ID}` como placeholder — substituímos pelo `cs_*` antes de redirecionar."
                value:
                  name: Com redirects
                  items:
                    - name: Produto
                      quantity: 1
                      unitAmount: 5000
                  paymentMethods:
                    card:
                      enabled: true
                  successUrl: >-
                    https://meu-site.com/pedido/obrigado?session={CHECKOUT_SESSION_ID}
                  cancelUrl: https://meu-site.com/carrinho
              kitchenSinkQuaseTodosOsCampos:
                summary: Kitchen-sink (quase todos os campos)
                description: "2 itens, 3 métodos, combined até 3 entradas, split 80/20, branding completo, endereço obrigatório,\r\n    2 custom fields, redirects, expira em 3 dias."
                value:
                  name: Kitchen-sink
                  description: Link com tudo configurado
                  mode: payment
                  currency: BRL
                  locale: pt-BR
                  items:
                    - name: Produto A
                      description: ...
                      imageUrl: https://...
                      quantity: 2
                      unitAmount: 9900
                    - name: Produto B
                      quantity: 1
                      unitAmount: 4900
                  paymentMethods:
                    card:
                      enabled: true
                      installments:
                        maxInstallments: 12
                        freeInstallments: 6
                        interestRate: 1.99
                    pix:
                      enabled: true
                      expiresIn: 3600
                    boleto:
                      enabled: true
                      dueDateDays: 3
                    combined:
                      enabled: true
                      maxPaymentsCount: 3
                      minAmountPerPayment: 1000
                  splits:
                    - recipientId: rec_principal
                      percentage: 80
                      liable: true
                    - recipientId: rec_afiliado
                      percentage: 20
                  branding:
                    primaryColor: '#1e3b79'
                    merchantName: Empresa X
                    logoUrl: https://...
                    mobileLayout: step-by-step
                  requiredFields:
                    - email
                    - document
                    - phone
                    - address
                  customFields:
                    - key: company
                      label: Empresa
                      type: text
                      required: false
                    - key: newsletter
                      label: Quero novidades
                      type: checkbox
                  successUrl: https://meu-site.com/obrigado
                  cancelUrl: https://meu-site.com/cancelado
                  metadata:
                    campaign: lancamento-2026
                  expirationMinutes: 4320
      responses:
        '201':
          description: Link criado
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
                    description: Identificador único do registro.
                  slug:
                    type: string
                    nullable: true
                    description: Slug único global usado na URL pública /c/{slug}.
                  status:
                    type: string
                    description: Estado atual do registro.
                  mode:
                    type: string
                    description: >-
                      Modo do checkout: 'payment' (pagamento único) ou
                      'subscription' (assinatura).
                  currency:
                    type: string
                    description: 'Moeda no padrão ISO 4217 (ex.: BRL).'
                  locale:
                    type: string
                    description: 'Idioma do checkout (ex.: pt-BR, en-US, es-ES).'
                  name:
                    type: string
                    nullable: true
                    description: Nome de exibição do registro.
                  description:
                    type: string
                    nullable: true
                    description: Descrição exibida no checkout.
                  sellable:
                    type: boolean
                    description: >-
                      Se o Link pode vender agora. É false quando um recebedor
                      do splits, ou o dono da conta, não está ativo no PSP — o
                      comprador vê uma página de indisponível. Independente do
                      status.
                  config:
                    type: object
                    description: >-
                      Snapshot da configuração do checkout (formas de pagamento,
                      itens e personalização visual).
                  requiredFields:
                    type: array
                    items:
                      type: string
                    nullable: true
                    description: >-
                      Campos do comprador exigidos no checkout (ex.: email,
                      document, phone, address).
                  customFields:
                    type: array
                    items:
                      type: object
                    nullable: true
                    description: >-
                      Definições dos campos personalizados solicitados no
                      checkout.
                  successUrl:
                    type: string
                    nullable: true
                    description: >-
                      URL de redirecionamento após o pagamento ser concluído com
                      sucesso.
                  cancelUrl:
                    type: string
                    nullable: true
                    description: >-
                      URL de redirecionamento quando o comprador cancela o
                      checkout.
                  metadata:
                    type: object
                    nullable: true
                    description: >-
                      Metadados livres (pares chave-valor) para uso do
                      integrador; não afeta o processamento.
                  expirationMinutes:
                    type: integer
                    nullable: true
                    description: Tempo de validade da sessão de checkout, em minutos.
                  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).
                  url:
                    type: string
                    description: >-
                      URL pública do checkout para o comprador finalizar o
                      pagamento.
              example:
                id: chk_byd8p3p79re859jpkmr0j65n3
                slug: curso-marketing-digital
                status: active
                mode: payment
                currency: BRL
                locale: pt-BR
                name: Curso de Marketing Digital
                description: Acesso vitalício ao curso completo
                sellable: true
                config:
                  items:
                    - name: Curso de Marketing Digital
                      description: Acesso vitalício
                      imageUrl: https://cdn.z2pay.com/products/curso-mkt.png
                      quantity: 1
                      unitAmount: 49700
                      chargeType: one_time
                  paymentMethods:
                    card:
                      enabled: true
                      installments:
                        maxInstallments: 12
                        freeInstallments: 1
                    pix:
                      enabled: true
                      expiresIn: 3600
                    boleto:
                      enabled: false
                  branding:
                    primaryColor: '#5B21B6'
                    merchantName: Academia Online
                requiredFields:
                  - email
                  - document
                  - phone
                customFields: null
                successUrl: https://academia.com/obrigado
                cancelUrl: https://academia.com/checkout
                metadata:
                  campaign: blackfriday
                expirationMinutes: 1440
                createdAt: '2025-06-29T13:45:30.000Z'
                updatedAt: '2025-06-29T13:45:30.000Z'
                url: https://pay.z2pay.com/c/curso-marketing-digital
        '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
        '403':
          description: >-
            A chave é válida, mas não tem permissão para esta operação — é o
            caso de usar uma publishable key (pk) onde a rota exige uma secret
            key (sk)
          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: FORBIDDEN
                  message: Forbidden — insufficient permissions
        '409':
          description: >-
            Já existe uma requisição em andamento com esta Idempotency-Key. A
            API aguarda a primeira concluir por até 5 segundos antes de
            responder assim
          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: A request with this idempotency key is already being processed
        '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 unificada (z2_{live|test}_{sk|pk}_...) — secret (sk) para
        integração backend, publishable (pk) para uso no frontend público

````