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

# Estrutura do Checkout (Checkout Builder)

> O que pode ir dentro do campo config: dispositivos, blocos disponíveis, atributos válidos e como imagens funcionam.

Todo checkout tem um campo `config` — um JSON que descreve o layout construído
no [Checkout Builder](https://app.cakto.com.br) (o editor visual do painel
Cakto). Esta página documenta o formato desse JSON para quem for lê-lo ou
escrevê-lo via [Atualizar Checkout](/api-reference/checkouts/update).

<Note>
  `config` é validado pela API pública, mas com um schema próprio da API
  pública — não é o mesmo contrato interno que o Checkout Builder do painel
  usa para salvar. As diferenças estão marcadas ao longo desta página,
  principalmente na seção [Imagens](#imagens).
</Note>

## Visão geral

```jsonc theme={null}
{
  "config": {
    "desktop": { "settings": {}, "extra": {}, "rows": [] },
    "mobile":  { "settings": {}, "extra": {}, "rows": [] }
  }
}
```

`desktop` e `mobile` são independentes e opcionais — você pode enviar só um
dos dois num `PUT`/`PATCH` (o outro permanece como estava). Cada um tem três
chaves:

| Chave      | O que é                                                                                             |
| ---------- | --------------------------------------------------------------------------------------------------- |
| `settings` | Tema visual (cores, fonte, fundo, botão de pagamento). Objeto livre — não é validado campo a campo. |
| `extra`    | Blocos globais que não pertencem a nenhuma linha: `chat`, `exitPopup`, `notification`.              |
| `rows`     | A lista de linhas do checkout, na ordem em que aparecem na página.                                  |

## `rows` → `columns` → `components`

Não existe campo `order`/`position` em nenhum nível — **a ordem é sempre a
posição no array**. A primeira linha de `rows[]` é a primeira a aparecer na
página; dentro dela, a primeira coluna de `columns[]` fica à esquerda; dentro
da coluna, o primeiro item de `components[]` fica no topo.

```jsonc theme={null}
{
  "id": "369db380-...",          // qualquer string, usada só como identificador local
  "type": "row",
  "layout": [12],                 // larguras das colunas (soma 12) — [12] | [8,4] | [4,8] | [4,4,4]
  "columns": [
    {
      "id": "e0253c14-...",
      "type": "column",
      "components": [
        { "id": "cff7c565-...", "type": "checkout", "attributes": {} }
      ]
    }
  ]
}
```

<Warning>
  A API não confere se o número de colunas bate com `layout.length`, nem se
  existe algum bloco `type: "checkout"` em algum lugar da árvore. Um checkout
  sem esse bloco é aceito pela API, mas fica sem formulário de pagamento na
  página pública — inclua sempre um bloco `checkout` em algum `rows[].columns[].components[]`.
</Warning>

## Catálogo de blocos (`components[].type`)

`type` só aceita um destes valores — qualquer outro é rejeitado com `400`.
`attributes` é validado de acordo com o `type`: campos fora dessa lista são
ignorados, e o tipo de cada campo é conferido (string, número, booleano).

| `type`        | Atributos válidos                                                                                                                                                                                                                                                                                                                                                     |
| ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `checkout`    | nenhum — é o formulário de pagamento em si, `attributes: {}`                                                                                                                                                                                                                                                                                                          |
| `text`        | `text`, `color`, `backgroundColor`, `borderColor` (string) · `borderWidth`, `borderRadius` (número)                                                                                                                                                                                                                                                                   |
| `image`       | `image` (**string**, URL — ver [Imagens](#imagens)) · `alignment`, `redirectUrl` (string) · `width` (número)                                                                                                                                                                                                                                                          |
| `advantage`   | `title`, `subtitle`, `icon`, `primaryColor`, `titleTextColor`, `size` (string) · `darkMode`, `vertical` (booleano)                                                                                                                                                                                                                                                    |
| `seal`        | `type`, `title`, `subtitle`, `primaryColor`, `titleTextColor`, `alignment` (string) · `darkMode` (booleano) · `width` (número)                                                                                                                                                                                                                                        |
| `header`      | `backgroundType`, `backgroundColor`, `backgroundImage`\* , `productImageType`, `productImage`\*, `productImageAlignment`, `titleTextColor`, `titleText`, `subtitleTextColor`, `subtitleText` (string) · `titleFontSize`, `subtitleFontSize` (número) · `showSubtitle` (booleano) — \*`backgroundImage`/`productImage` são URL em string, mesma regra do bloco `image` |
| `list`        | `backgroundColor`, `textColor`, `alignment`, `title`, `style`, `iconColor` (string) · `fontSize` (número) · `showTitle` (booleano) · `items`: `[{ "id": string, "text": string }]`                                                                                                                                                                                    |
| `countdown`   | `backgroundColor`, `textColor`, `activeText`, `finishedText`, `type` (string) · `fixedOnTop` (booleano) · `time` (string `"HH:MM"`) · `date` (string `"yyyy-MM-dd"`)                                                                                                                                                                                                  |
| `testimonial` | `backgroundColor`, `textColor`, `author`, `text` (string) · `rating` (número) · `horizontal` (booleano) · `avatar` — **único campo de imagem que aceita objeto livre** (ver [Imagens](#imagens))                                                                                                                                                                      |
| `video`       | `url`, `alignment` (string) · `width` (número) · `hideControls` (booleano)                                                                                                                                                                                                                                                                                            |
| `facebook`    | `type`, `url`, `size`, `orderBy` (string) · `count` (número) · `tabs`, `options` (listas)                                                                                                                                                                                                                                                                             |
| `map`         | `address`, `alignment` (string) · `width` (número)                                                                                                                                                                                                                                                                                                                    |

## Blocos globais (`extra`)

Ficam fora da árvore de linhas — são renderizados de forma fixa (popup,
notificação flutuante, widget de chat), não em uma posição específica da
página.

| Chave                | Atributos                                                                                                                                                                                                                       |
| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `extra.chat`         | `enabled` (booleano) · `provider` — um de `whatsapp`, `jivochat`, `zendesk`, `manychat`, `crisp`, `tawk`, `facebook`, `freshchat`, `intercom` · `accountId` (string)                                                            |
| `extra.exitPopup`    | `enabled` (booleano) · `type`, `actionOnClick`, `offer`, `title`, `description`, `actionLabel`, `video`, `url`, `coupon`, `backgroundButtonColor`, `textButtonColor` (string) · `image`\* (string, URL)                         |
| `extra.notification` | `enabled` (booleano) + cinco sub-blocos independentes: `interestedLast24Hours`, `interestedLastWeek`, `interestedRightNow`, `purchasedLast24Hours`, `purchasedLastWeek` — cada um `{ enabled, value, min, max, exibitionTime }` |

## Imagens

<Warning>
  **A API pública não tem endpoint de upload de imagem.** Só é possível
  referenciar uma imagem já hospedada em algum lugar — não existe uma rota
  tipo `/gallery/upload` na API pública para enviar um arquivo e receber uma
  URL de volta.
</Warning>

Para os blocos `image`, `header` (`backgroundImage`/`productImage`) e
`extra.exitPopup`, o atributo de imagem é validado como **string simples**
(a URL da imagem). Enviar um objeto nesses campos falha a validação com
`400`.

```jsonc theme={null}
// certo
{ "type": "image", "attributes": { "image": "https://meu-cdn.com/banner.png" } }

// errado — 400 Bad Request
{ "type": "image", "attributes": { "image": { "id": 42, "preview": "https://..." } } }
```

A única exceção é `testimonial.avatar`, que aceita um valor JSON livre
(string ou objeto) — não é validado como URL.

<Note>
  Essa regra é diferente do editor visual do painel Cakto: lá, ao fazer
  upload de uma imagem, o Checkout Builder grava um objeto
  `{ id, preview }` (o retorno do upload interno para a galeria do produto).
  Se você ler o `config` de um checkout montado pelo painel via API pública e
  regravá-lo sem alterar as imagens, pode encontrar esse formato de objeto —
  mas ao **escrever** um valor novo por aqui, use sempre a string da URL.
</Note>

Na prática, para colocar uma imagem num checkout via API: hospede o arquivo
você mesmo (seu storage, um CDN, etc.) e use a URL pública dele nos atributos
acima. Para reaproveitar uma imagem já enviada pelo painel, copie a URL do
campo `preview` do objeto existente.

## Erros de validação

Um `config` inválido — `type` de bloco desconhecido, campo do tipo errado,
`row`/`column`/`component` sem `id` — retorna `400` com os erros por campo,
no formato padrão de erro descrito em [Erros](/conceitos/erros).

## Ver também

<CardGroup cols={2}>
  <Card title="Personalizar Checkout" icon="pen" href="/api-reference/checkouts/update">
    Referência do endpoint, com um exemplo completo de config
  </Card>

  <Card title="Obter Checkout" icon="magnifying-glass" href="/api-reference/checkouts/retrieve">
    Como ler o config de um checkout existente
  </Card>

  <Card title="Criar um checkout" icon="cart-shopping" href="/comece-aqui/criar-checkout">
    Onde o checkout entra no fluxo de criar um produto
  </Card>

  <Card title="Erros" icon="triangle-exclamation" href="/conceitos/erros">
    Formato padrão de erro de validação
  </Card>
</CardGroup>
