Blocos de conteúdo
O corpo de um post é um documento de blocos, não uma única string HTML. Isso mantém o conteúdo portável entre temas e seguro para renderizar. Você o envia como o campo blocks_json de POST /v1/posts.
Envelope
Seção intitulada “Envelope”{ "v": 1, "blocks": [ { "id": "p1", "type": "paragraph", "text": "…" } ]}v— versão do schema. Sempre1.blocks— um array ordenado. Ordem de renderização = ordem do array.
Todo bloco tem:
| Campo | Tipo | Obrigatório | Observações |
|---|---|---|---|
id |
string | sim | Único e não vazio dentro do documento (ex.: p1, h1, b_ab12). |
type |
string | sim | Um dos tipos de bloco abaixo. |
text |
string | depende | Payload de texto/HTML (veja cada tipo). |
attrs |
object | depende | Atributos específicos do tipo. |
Tipos de bloco
Seção intitulada “Tipos de bloco”type |
Carrega | Renderiza como |
|---|---|---|
paragraph |
text (HTML inline) |
<p> |
heading |
attrs.level (2–6), text |
<h2>…<h6> |
list |
attrs.style "unordered"/"ordered" + text (um item por linha) |
<ul> / <ol> |
code |
attrs.language, text (literal) |
<pre><code> |
quote |
text |
<blockquote> |
image |
attrs.src (ou attrs.media_id), attrs.alt |
<figure><img> |
divider |
— | <hr> |
paragraph
Seção intitulada “paragraph”text pode conter HTML inline: <a href>, <strong>, <em>, <code>, <br>. Ele é sanitizado no servidor (veja abaixo).
{ "id": "p1", "type": "paragraph", "text": "Read the <a href=\"https://docs.canverly.com\">docs</a> for <strong>more</strong>." }heading
Seção intitulada “heading”{ "id": "h1", "type": "heading", "attrs": { "level": 2 }, "text": "Section title" }Coloque um item por linha em text, separados por \n. Os itens podem conter HTML inline.
{ "id": "l1", "type": "list", "attrs": { "style": "unordered" }, "text": "First item\nSecond item\nThird with a <a href=\"https://x.com\">link</a>" }text é preservado literalmente (sem interpretação de HTML). attrs.language define o realce de sintaxe.
{ "id": "c1", "type": "code", "attrs": { "language": "python" }, "text": "print('hello')" }Referencie uma imagem já hospedada por URL, ou por um id de mídia da Canverly, se você tiver um.
{ "id": "i1", "type": "image", "attrs": { "src": "https://cdn.example.com/cover.jpg", "alt": "Cover" } }Sanitização de HTML
Seção intitulada “Sanitização de HTML”O HTML inline dentro do texto dos blocos (e dos itens de lista) é renderizado como HTML e depois passa por um sanitizador de allowlist quando publicado pela API pública. Isso significa:
- Mantido: tags de formatação (
a,strong,em,code,b,i,u,s,p,br,ul/ol/li,h1–h6,blockquote,img,pre,span, tabelas) e linkshttp/https/mailto. - Removido:
<script>, handlers de evento (onerror,onclick, …), URLsjavascript:,<iframe>e qualquer outra coisa que não esteja na allowlist.
Então você pode enviar rich text com segurança, mas não consegue injetar scripts em um site por meio de uma chave de API. Se precisar de texto puro, basta enviar texto puro — ele passa sem alteração.
Um corpo completo
Seção intitulada “Um corpo completo”{ "v": 1, "blocks": [ { "id": "p1", "type": "paragraph", "text": "An intro paragraph with a <a href=\"https://canverly.com\">link</a>." }, { "id": "h1", "type": "heading", "attrs": { "level": 2 }, "text": "Steps" }, { "id": "l1", "type": "list", "attrs": { "style": "ordered" }, "text": "Get a key\nPOST /v1/posts\nVerify it's live" }, { "id": "c1", "type": "code", "attrs": { "language": "bash" }, "text": "curl https://api.canverly.com/v1/sites/me -H 'Authorization: Bearer ck_…'" }, { "id": "q1", "type": "quote", "text": "Publishing should be one API call." } ]}