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

# Create a Payment Link

> Cria um payment link.

Cria um **payment link** — uma URL pública compartilhável. A cada clique de um comprador, uma nova `checkout.session` é materializada, copiando os `line_items` e `metadata` do link. Use pra bio do Instagram, e-mail marketing, QR codes, "comprar agora" em landing page.

Para cobrar uma invoice existente, não crie um payment link: compartilhe
`invoice.hosted_invoice_url`, retornado pelos endpoints de invoices.

## Autenticação

Aceita dois tipos de API key:

| Token                                           | Header                                                                  | Comportamento                                                                       |
| ----------------------------------------------- | ----------------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
| **API key da organização** (`write` ou `admin`) | `Authorization: Bearer ch_live_...`                                     | Cria para a própria organização da chave. O header `Organization` é proibido (400). |
| **API key da plataforma** (`platform_admin`)    | `Authorization: Bearer ch_live_...` + `Organization: <organization_id>` | Cria em nome da organização conectada indicada. Sem `Organization` → 403.           |

O valor do header `Organization` deve ser uma organização conectada **ativa** vinculada à plataforma; caso contrário retorna 403.

## Attributes

<ParamField body="allow_discount_codes" type="boolean" default="true">
  Se o comprador pode inserir cupom no checkout.
</ParamField>

<ParamField body="cancel_url" type="string">
  Pra onde o comprador é redirecionado se cancelar/abandonar o checkout.
</ParamField>

<ParamField body="discount_id" type="string">
  ID de um desconto a aplicar automaticamente em todas as sessões geradas.
</ParamField>

<ParamField body="label" type="string">
  Nome interno do link (visível só pra organização). Não aparece pro comprador.
</ParamField>

<ParamField body="line_items" type="array" required>
  Itens do link. Cada item aponta pra um preço do catálogo (`price_id`) **ou** descreve um preço inline (`price_data`) — exatamente um dos dois.

  Restrições de integridade aplicadas em todo o array:

  * todos os itens compartilham a **mesma `currency`**;
  * ou **todos** são recorrentes, ou **nenhum** é (não pode misturar);
  * quando `price_data` é usado, **exatamente um** entre `product_id` e `product_data` deve acompanhá-lo.

  <Expandable title="line_items[]">
    <ParamField body="description" type="string">Descrição livre — sobrescreve o nome do produto na exibição do checkout.</ParamField>

    <ParamField body="price_data" type="object">
      Preço ad-hoc — não persiste no catálogo, vive só nas sessões geradas a partir do link. Mutuamente exclusivo com `price_id`.

      <Expandable title="price_data">
        <ParamField body="currency" type="string" required>Código ISO de 3 letras (ex.: `brl`).</ParamField>

        <ParamField body="product_data" type="object">
          Produto ad-hoc. **Obrigatório se `product_id` não foi enviado.**

          <Expandable title="product_data">
            <ParamField body="description" type="string">Descrição livre.</ParamField>
            <ParamField body="name" type="string" required>Nome do produto exibido no checkout.</ParamField>
          </Expandable>
        </ParamField>

        <ParamField body="product_id" type="string">
          ID de produto existente do catálogo. **Obrigatório se `product_data` não foi enviado.**
        </ParamField>

        <ParamField body="recurring" type="object">
          Quando presente, marca o item como recorrente — sessões geradas nascem em modo `subscription`.

          <Expandable title="recurring">
            <ParamField body="interval" type="string" required>`day`, `week`, `month` ou `year`.</ParamField>
            <ParamField body="interval_count" type="integer">Quantos intervalos por ciclo. Padrão `1`.</ParamField>
          </Expandable>
        </ParamField>

        <ParamField body="unit_amount" type="integer" required>Valor unitário em centavos (ex.: `19990` = R\$ 199,90).</ParamField>
      </Expandable>
    </ParamField>

    <ParamField body="price_id" type="string">
      ID de um preço já cadastrado no catálogo da org alvo. Mutuamente exclusivo com `price_data`.
    </ParamField>

    <ParamField body="quantity" type="integer">Padrão `1`. Inteiro >= 1.</ParamField>
  </Expandable>
</ParamField>

<ParamField body="metadata" type="object">
  Objeto chave-valor livre. Cada session gerada do link recebe esse `metadata` copiado.
</ParamField>

<ParamField body="payment_method_options" type="object">
  Opções por método de pagamento. Quando omitido, aplicam-se os padrões da
  organização.

  <Expandable title="Campos de payment_method_options">
    <ParamField body="credit_card" type="object">
      Opções do cartão de crédito.

      <Expandable title="Campos de credit_card">
        <ParamField body="installments" type="object">
          Configuração do parcelamento.

          <Expandable title="Campos de installments">
            <ParamField body="has_interest" type="boolean">
              `true` quando o comprador paga o acréscimo do parcelamento;
              `false` quando o lojista absorve o acréscimo. Quando omitido, usa o
              padrão da organização.
            </ParamField>

            <ParamField body="max_count" type="integer">
              Número máximo de parcelas oferecidas (1–12). Quando omitido, usa o
              padrão da organização.
            </ParamField>
          </Expandable>
        </ParamField>
      </Expandable>
    </ParamField>
  </Expandable>
</ParamField>

<ParamField body="require_billing_address" type="boolean">
  Quando `true`, endereço de cobrança é obrigatório no checkout. Quando omitido,
  herda a política de checkout da organização. Boleto sempre exige.
</ParamField>

<ParamField body="require_document" type="boolean">
  Quando `true`, o documento (CPF/CNPJ) do comprador é obrigatório no checkout.
  Quando omitido, herda a política da organização (padrão `true`). Boleto sempre
  exige documento.
</ParamField>

<ParamField body="require_phone" type="boolean">
  Quando `true`, o telefone do comprador é obrigatório no checkout. Quando
  omitido, herda a política da organização (padrão `false`).
</ParamField>

<ParamField body="success_url" type="string">
  Pra onde o comprador é redirecionado após pagamento aprovado.
</ParamField>

## Cenários de `line_items`

Existem três formas válidas de descrever um item. Use a mais idiomática pro seu caso.

### (a) Preço do catálogo

Caminho mais curto. Resolve produto, preço e (se for o caso) recorrência automaticamente a partir do `price_id`.

<RequestExample>
  ```bash cURL theme={}
  curl -X POST "https://api.chargefy.io/v1/payment-links" \
    -H "Authorization: Bearer {{API_KEY}}" \
    -H "Content-Type: application/json" \
    -d '{
      "line_items": [
        {
          "price_id": "price_123"
        }
      ]
    }'
  ```
</RequestExample>

Quando o `price_id` referencia um preço cujo `type = recurring`, as sessões geradas nascem em `mode: subscription` sem nenhum campo extra.

### (b) Produto do catálogo + preço ad-hoc

Reusa nome/descrição/imagem do produto cadastrado, mas usa um valor único pra esse link. Útil pra promoção pontual sem criar preço novo no catálogo.

<RequestExample>
  ```bash cURL theme={}
  curl -X POST "https://api.chargefy.io/v1/payment-links" \
    -H "Authorization: Bearer {{API_KEY}}" \
    -H "Content-Type: application/json" \
    -d '{
      "line_items": [
        {
          "price_data": {
            "currency": "brl",
            "product_id": "prod_123",
            "unit_amount": 12990
          }
        }
      ]
    }'
  ```
</RequestExample>

Pra que o link seja recorrente, adicione `recurring` em `price_data`:

```json theme={}
{
  "price_data": {
    "currency": "brl",
    "product_id": "prod_123",
    "recurring": {
      "interval": "month",
      "interval_count": 1
    },
    "unit_amount": 12990
  }
}
```

### (c) Produto e preço ad-hoc

Nada vem do catálogo — útil pra integrações headless que não cadastram produto.

<RequestExample>
  ```bash cURL theme={}
  curl -X POST "https://api.chargefy.io/v1/payment-links" \
    -H "Authorization: Bearer {{API_KEY}}" \
    -H "Content-Type: application/json" \
    -d '{
      "line_items": [
        {
          "price_data": {
            "currency": "brl",
            "product_data": {
              "name": "Consultoria avulsa"
            },
            "unit_amount": 4990
          }
        }
      ]
    }'
  ```
</RequestExample>

### Como plataforma (em nome de uma organização conectada)

Adicione o header `Organization` apontando pra organização conectada. O body é
idêntico aos cenários acima — só a chave (`platform_admin`) e o header
`Organization` mudam.

## Resposta

`200 OK` com o objeto canônico do payment link.

<ResponseField name="id" type="string">Identificador, prefixo `plink_`.</ResponseField>
<ResponseField name="object" type="string">Sempre `payment_link`.</ResponseField>
<ResponseField name="allow_discount_codes" type="boolean">Se cupons são permitidos no checkout.</ResponseField>
<ResponseField name="cancel_url" type="string">URL de cancelamento configurada. `null` se não enviado.</ResponseField>
<ResponseField name="created_at" type="string">ISO 8601.</ResponseField>
<ResponseField name="discount" type="string | null">ID do desconto auto-aplicado, ou `null`.</ResponseField>
<ResponseField name="is_active" type="boolean">`true` enquanto o link aceita cliques. Vira `false` quando desativado via update ou delete com histórico, e cliques retornam 404. Sessões já materializadas continuam vivas.</ResponseField>
<ResponseField name="label" type="string">Nome interno (visível só pra organização). `null` se não enviado.</ResponseField>
<ResponseField name="line_items" type="array">Itens fixados. Cada session gerada do link copia 1:1.</ResponseField>
<ResponseField name="livemode" type="boolean">Indica se o link foi criado em modo live.</ResponseField>
<ResponseField name="metadata" type="object">Metadata configurada.</ResponseField>
<ResponseField name="payment_method_options" type="object">Opções por método. `credit_card.installments.has_interest` (boolean) indica se o comprador paga o acréscimo do parcelamento; `credit_card.installments.max_count` (integer 1–12) é o número máximo de parcelas.</ResponseField>
<ResponseField name="require_billing_address" type="boolean">Se endereço de cobrança é obrigatório. Boleto sempre exige.</ResponseField>
<ResponseField name="require_document" type="boolean">Se o documento (CPF/CNPJ) é obrigatório. Boleto sempre exige.</ResponseField>
<ResponseField name="require_phone" type="boolean">Se o telefone do comprador é obrigatório.</ResponseField>
<ResponseField name="success_url" type="string">URL de sucesso configurada. `null` se não enviado.</ResponseField>
<ResponseField name="updated_at" type="string">ISO 8601 da última edição, ou `null` se nunca editado.</ResponseField>
<ResponseField name="url" type="string">URL pública pra compartilhar com compradores. Cada clique materializa uma `checkout.session`.</ResponseField>

<ResponseExample>
  ```json 200 theme={}
  {
    "id": "plink_demo_z2kkA78c1aCGhiEj",
    "object": "payment_link",
    "allow_discount_codes": true,
    "cancel_url": null,
    "created_at": "2026-05-02T18:31:00Z",
    "discount": null,
    "is_active": true,
    "label": "Bio do Instagram - Plano Pro",
    "line_items": [
      {
        "amount_discount": 0,
        "amount_subtotal": 12990,
        "amount_tax": 0,
        "amount_total": 12990,
        "currency": "brl",
        "description": "Plano Pro",
        "metadata": {},
        "position": 0,
        "price": "price_456",
        "price_data": null,
        "product": "prod_321",
        "quantity": 1,
        "recurring_interval": "month",
        "recurring_interval_count": 1,
        "unit_amount": 12990
      }
    ],
    "livemode": true,
    "metadata": {},
    "payment_method_options": {
      "credit_card": {
        "installments": {
          "has_interest": true,
          "max_count": 12
        }
      }
    },
    "require_billing_address": false,
    "require_document": true,
    "require_phone": false,
    "success_url": "https://meusite.com/obrigado",
    "updated_at": null,
    "url": "https://pay.chargefy.io/link/9a1bc3d2e4f5..."
  }
  ```
</ResponseExample>

## Erros comuns

| HTTP  | Razão                                                                                             |
| ----- | ------------------------------------------------------------------------------------------------- |
| `400` | `line_items` ausente, vazio ou item sem `price_id` nem `price_data`.                              |
| `400` | Item com `price_id` **e** `price_data` enviados juntos (envie exatamente um).                     |
| `400` | `price_data` enviado sem `product_id` nem `product_data` — ou com **ambos**. Envie exatamente um. |
| `400` | `price_data.recurring.interval` inválido (use `day`, `week`, `month` ou `year`).                  |
| `400` | Mistura de itens recorrentes e únicos no mesmo link. Ou todos são recorrentes, ou nenhum.         |
| `400` | Currency divergente entre os items.                                                               |
| `400` | `price_id` / `product_id` não pertence à org alvo.                                                |
| `400` | O header `Organization` enviado com chave de organização (chave já trava na própria org).         |
| `403` | Token de plataforma sem header `Organization`.                                                    |
| `403` | O header `Organization` aponta pra org que não é organização conectada ativa da plataforma.       |

## Webhooks

Cada criação dispara o evento `payment.link.created` para todos os endpoints de webhook ativos da organização dona e das plataformas vinculadas a ela. Payload é o mesmo objeto retornado pelo POST em `data.object`, dentro do envelope Standard Webhooks (`{ id, object: "event", created_at, data: { object }, livemode, organization, type }`).
