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

# Create Checkout Links

> Programmatically create a hosted checkout link with an API key — reference your own products by external_id, or generate a value-only link.

Use this endpoint to create a hosted checkout link from your backend or a no-code/AI tool, the
same way you create transactions. Authentication is by API key; the tenant and company are resolved
from the token. The response is just the final checkout URL.

## Happy path

1. Call `POST /v2/checkout-links` with your API key.
2. Send either `products[]` (referenced by your own `external_id`) **or** a value-only `amount`.
3. Pagou upserts each product by `external_id`, builds the link, and attaches the company's active
   payment methods plus any eligible order bump / upsell automatically.
4. Use the returned `data.url` — it already carries your custom domain when one is active.

## Authentication

Send your secret API key as a Bearer token (same key used for [transactions](/api-reference/transactions/create)):

```
Authorization: Bearer YOUR_API_KEY
```

The `x-api-key: YOUR_API_KEY` header is also accepted.

## Products by external\_id (upsert)

Each item in `products[]` is keyed by **`external_id`** — your own identifier for the product. On
every call Pagou **upserts** by `(company, external_id)`:

* **First time:** creates the product in your catalog (`origin = api`).
* **Next times:** reuses the same product and **updates** its name/price/fields from the payload
  (reviving it if it was archived). It never duplicates.

You never need to know Pagou's internal product ids — `external_id` is the only identifier you pass.

<Note>
  Prices are integers in **cents** (`7990` = R\$ 79.90). Re-sending the same `external_id` overwrites
  the product's name, price, description and image from the payload, so always send the full product
  state you want.
</Note>

### Example request — products

```bash theme={null}
curl --request POST \
  --url https://api.pagou.ai/v2/checkout-links \
  --header "Authorization: Bearer YOUR_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "currency": "BRL",
    "title": "Order #1042",
    "products": [
      {
        "external_id": "SKU-TSHIRT-BLACK-M",
        "name": "Black T-Shirt M",
        "price": 7990,
        "quantity": 2,
        "type": "physical",
        "image_url": "https://cdn.example.com/tshirt.jpg",
        "compare_price": 9990
      }
    ]
  }'
```

## Value-only link

Omit `products` and send `amount` (in cents) to generate a quick, value-only link. `title` is
optional — when absent it is auto-generated.

```bash theme={null}
curl --request POST \
  --url https://api.pagou.ai/v2/checkout-links \
  --header "Authorization: Bearer YOUR_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{ "currency": "BRL", "amount": 15000 }'
```

Send **either** `products` **or** `amount` — not both, and not neither.

## Example response

```json theme={null}
{
  "success": true,
  "requestId": "req_1201",
  "data": {
    "url": "https://checkout.pagou.ai/chk_01J8Z..."
  }
}
```

## Request fields

| Field                      | Type            | Required | Notes                                                 |
| -------------------------- | --------------- | -------- | ----------------------------------------------------- |
| `currency`                 | string          | no       | Link currency. Default `BRL`.                         |
| `title`                    | string          | no       | Auto-generated when omitted.                          |
| `amount`                   | integer (cents) | one of   | Value-only link. Mutually exclusive with `products`.  |
| `products[]`               | array           | one of   | Product-based link. Mutually exclusive with `amount`. |
| `products[].external_id`   | string          | yes      | Your identifier; upsert key.                          |
| `products[].name`          | string          | yes      | Product name.                                         |
| `products[].price`         | integer (cents) | yes      | Unit price.                                           |
| `products[].quantity`      | integer         | no       | Default `1`.                                          |
| `products[].currency`      | string          | no       | Inherits the link currency.                           |
| `products[].type`          | string          | no       | `physical` or `digital`. Default `physical`.          |
| `products[].description`   | string          | no       |                                                       |
| `products[].image_url`     | string (url)    | no       |                                                       |
| `products[].compare_price` | integer (cents) | no       | "From" price for a discount display.                  |

## Common error

Status `422` — neither `amount` nor `products` was provided (or both were):

```json theme={null}
{
  "type": "https://api.pagou.ai/problems/validation-error",
  "title": "Validation Error",
  "status": 422,
  "detail": "The request contains invalid data.",
  "errors": [
    {
      "field": "amount",
      "message": "Either amount or products must be provided.",
      "code": "custom"
    }
  ]
}
```

## Use with AI

Paste this into Claude Code, Cursor, Codex, Copilot, Lovable, Bolt, or any AI coding agent:

```text theme={null}
Read https://developer.pagou.ai/llms-full.txt and https://developer.pagou.ai/api-reference/openapi-v2.json

Build a checkout link flow (Pagou-hosted checkout — no card handling on your side):
1. Backend/server function only: POST /v2/checkout-links with an Authorization: Bearer <API key>
2. Body — products: { "currency": "BRL", "title": "<order>", "products": [{ "external_id": "<your id>", "name": "<name>", "price": <cents>, "quantity": <n> }] }
3. Body — value-only: { "currency": "BRL", "amount": <cents> }. Send EITHER products OR amount, never both.
4. external_id is your own product id; re-sending the same id updates that product (no duplicates).
5. Response is { "data": { "url": "<checkout url>" } } — redirect the buyer to data.url.
6. Fulfillment: update the order only after the transaction webhook (event=transaction, data.event_type) confirms payment — not on redirect.

Prices/amount are integers in cents. Keep the API key server-side (env var), never in the browser. Validate all fields against OpenAPI.
```

## Notes

* **Payment methods** are always derived from the company's active permissions — you don't pass them.
* **Order bumps and upsells** eligible for the products are attached automatically.
* **Custom domain** is applied to the returned URL when the company has one active.
* **Out of scope (v1):** product variants by `external_id`, subscriptions/recurring, and updating or
  listing links via the API.

## Next steps

* [Checkout Links Reference](/api-reference/checkout-links/create)
* [Authentication](/start-here/authentication)
* [Payment Events](/webhooks/payment-events)
