Respawn Tech Dev

PDF Convert

API de conversão de HTML em PDF, PNG ou JPG — fluxo assíncrono, batch, retenção e custos.

Envie HTML e CSS, receba um job assíncrono e baixe o arquivo quando estiver pronto. Suporta conversão unitária, batch com template, retenção configurável e sandbox JavaScript opcional.

Base path
/v1/tools/document/pdf
Escopos
tools:pdf:readtools:pdf:managetools:manage

Visão geral

O PDF Convert é assíncrono:

  1. POST /convert ou POST /batch → 202 Accepted com o conversion_id (o {id} das demais rotas).
  2. Um worker renderiza em background (Chromium headless).
  3. Acompanhe pelo callback webhook_url ou consultando GET /{id}.
  4. Baixe com GET /{id}/download quando status for completed.

Cobrança ao enfileirar

Os créditos são debitados quando o job é aceito. Se o enfileiramento de um batch falhar depois do débito, o valor é estornado automaticamente.

OperaçãoRota
Converter HTML em PDF/PNG/JPGPOST/convert
Batch com templatePOST/batch
Reprocessar falhaPOST/{id}/retry
Listar conversõesGET/
Status da conversãoGET/{id}
Baixar arquivoGET/{id}/download
Listar batchesGET/batches
Detalhe do batchGET/batches/{id}
Download ZIP do batchGET/batches/{id}/download
Listar templates salvosGET/templates
Salvar templatePOST/templates
Consultar templateGET/templates/{id}
Listar versões do templateGET/templates/{id}/versions
Renomear template ou salvar nova versãoPATCH/templates/{id}
Excluir templateDELETE/templates/{id}
Listar fontesGET/fonts
Enviar fontePOST/fonts
Excluir fonteDELETE/fonts/{id}

Custos

Por documento

ItemCréditosNotas
Conversão base1,0—
Retenção efêmera ou até 3 dias+0,0retention_days 0 (~24h) a 3
Retenção 4–7 dias+0,5—
Retenção 8–30 dias+2,5—
Retenção permanente+15,0retention_days: -1
Sandbox JavaScript+0,25enable_js: true

Pós-processamento e fontes — Somados ao custo do documento. Só `pdf` aceita pós-processamento.

ItemCréditosNotas
Marca d'água+0,1post_process.watermark
Proteção por senha+0,1post_process.protection
PDF/A-2b+0,25post_process.pdfa
Fontes personalizadas+0,05font_ids (uma vez por documento, não por fonte)

Desconto de volume no batch — Aplicado sobre base, JavaScript e retenção de cada item.

ItemDesconto
10+ itens5%
20+ itens10%
30+ itens15%
40+ itens20%

O batch aceita até 500 itens. O retry cobra o custo integral novamente, inclusive os adicionais acima. Salvar templates e enviar fontes não custa créditos. Consultas e downloads via API seguem a franquia diária.

Conversão

Converter HTML em PDF/PNG/JPG

POST/v1/tools/document/pdf/convert
Custo
Variável (ver custos)
Dry-run
Suportado (X-Dry-Run: true)
Autenticação
qualquer um detools:pdf:managetools:manage

Envie html ou url (um dos dois, nunca os dois). Com url, o Chromium abre a página pública e a renderiza; css, google_fonts_url e data são recusados nesse modo (pdf.invalid_option).

CampoLimite / valores
htmlmáx. 10 MB
urlalternativa a html: endereço público http/https, até 2048 caracteres (pdf.invalid_url se for privado ou inválido)
cssmáx. 1 MB
formatpdf (padrão), png, jpg / jpeg
file_namenome do arquivo gerado
title, author, subject, keywordsmetadados do documento, até 1000 caracteres cada
header_html / footer_htmlcabeçalho e rodapé repetidos em cada página
google_fonts_urlURL de CSS do Google Fonts a carregar
wait_selector / wait_delayespera um seletor aparecer / um atraso em ms antes de renderizar
enable_js / custom_jsexecuta JavaScript em sandbox (SPAs, gráficos) / script extra
dataobjeto com variáveis para placeholders {{campo}} no HTML
retention_days0 (efêmero, ~24h), 1–30 ou -1 (permanente)
webhook_urlrecebe o callback ao terminar
template_id, template_version, font_ids, post_processtemplates salvos, fontes e pós-processamento

Tamanho de página, margens, mídia, numeração e qualidade estão em Opções de página e render.

Guarde o conversion_id: é o {id} usado para consultar status e baixar o arquivo.

curl -sS -X POST 'https://api.respawntech.dev/v1/tools/document/pdf/convert' \
  -H "X-API-Token: $RESPAWN_API_TOKEN" \
  -H 'X-Idempotency-Key: 550e8400-e29b-41d4-a716-446655440001' \
  -H 'Content-Type: application/json' \
  -d '{
"html": "<html><body><h1>Fatura</h1></body></html>",
"css": "body { font-family: sans-serif; }",
"format": "pdf",
"page_size": "A4",
"retention_days": 7
}'
const response = await fetch('https://api.respawntech.dev/v1/tools/document/pdf/convert', {
  method: 'POST',
  headers: {
    'X-API-Token': process.env.RESPAWN_API_TOKEN,
    'X-Idempotency-Key': '550e8400-e29b-41d4-a716-446655440001',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
"html": "<html><body><h1>Fatura</h1></body></html>",
"css": "body { font-family: sans-serif; }",
"format": "pdf",
"page_size": "A4",
"retention_days": 7
}),
});

if (!response.ok) throw new Error((await response.json()).error.code);
console.log(await response.json());
import os
import requests

response = requests.post(
    "https://api.respawntech.dev/v1/tools/document/pdf/convert",
    headers={
        "X-API-Token": os.environ["RESPAWN_API_TOKEN"],
        "X-Idempotency-Key": "550e8400-e29b-41d4-a716-446655440001",
    },
    json={
"html": "<html><body><h1>Fatura</h1></body></html>",
"css": "body { font-family: sans-serif; }",
"format": "pdf",
"page_size": "A4",
"retention_days": 7
},
    timeout=30,
)
if not response.ok:
    raise RuntimeError(response.json()["error"]["code"])
print(response.json())
<?php
$ch = curl_init('https://api.respawntech.dev/v1/tools/document/pdf/convert');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('RESPAWN_API_TOKEN'),
        'X-Idempotency-Key: 550e8400-e29b-41d4-a716-446655440001',
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => <<<'JSON'
{
"html": "<html><body><h1>Fatura</h1></body></html>",
"css": "body { font-family: sans-serif; }",
"format": "pdf",
"page_size": "A4",
"retention_days": 7
}
JSON,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

if ($status >= 400) {
    throw new RuntimeException(json_decode($body, true)['error']['code']);
}
print_r(json_decode($body, true));
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"strings"
	"time"
)

func main() {
	req, err := http.NewRequest("POST", "https://api.respawntech.dev/v1/tools/document/pdf/convert", strings.NewReader(`{
"html": "<html><body><h1>Fatura</h1></body></html>",
"css": "body { font-family: sans-serif; }",
"format": "pdf",
"page_size": "A4",
"retention_days": 7
}`))
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Token", os.Getenv("RESPAWN_API_TOKEN"))
	req.Header.Set("X-Idempotency-Key", "550e8400-e29b-41d4-a716-446655440001")
	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{Timeout: 30 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	data, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode >= 400 {
		panic(string(data))
	}
	fmt.Println(string(data))
}

Resposta 202

{
  "success": true,
  "trace_id": "550e8400-e29b-41d4-a716-446655440000",
  "data": {
    "conversion_id": "3e4f5a6b-7c8d-4e9f-a0b1-c2d3e4f5a6b7",
    "job_id": "pdf_9b8c7d6e5f",
    "status": "pending"
  }
}

Batch com template

POST/v1/tools/document/pdf/batch
Custo
Soma dos itens com desconto
Dry-run
Suportado (X-Dry-Run: true)
Autenticação
qualquer um detools:pdf:managetools:manage
CampoDescrição
template.htmlobrigatório — HTML com placeholders {{campo}} (sintaxe de Go template: {{if}}, {{range}} também funcionam)
template.cssCSS compartilhado
items[]obrigatório, 1 a 500 itens: custom_id (obrigatório, seu identificador), file_name e data
configopções aplicadas a todos os itens: page_size, orientation, margens, format, scale, retention_days, google_fonts_url, header_html, footer_html, wait_selector, wait_delay, title, author, enable_js, custom_js e file_name_template
delivery.methodzip ou list: como o resultado é entregue ao terminar
delivery.webhook_urlrecebe o callback ao terminar

O batch não aceita url, template_id, font_ids nem post_process: ele usa sempre o template.html do corpo. Os descontos de volume se aplicam sobre base, JavaScript e retenção. Acompanhe o progresso em Detalhe do batch.

curl -sS -X POST 'https://api.respawntech.dev/v1/tools/document/pdf/batch' \
  -H "X-API-Token: $RESPAWN_API_TOKEN" \
  -H 'X-Idempotency-Key: 550e8400-e29b-41d4-a716-446655440002' \
  -H 'Content-Type: application/json' \
  -d '{
"template": {
  "html": "<html><body><h1>{{title}}</h1></body></html>",
  "css": "h1 { color: #333; }"
},
"config": { "page_size": "A4", "format": "pdf", "retention_days": 7 },
"items": [
  { "custom_id": "fatura-001", "file_name": "fatura-001.pdf", "data": { "title": "Fatura 001" } },
  { "custom_id": "fatura-002", "file_name": "fatura-002.pdf", "data": { "title": "Fatura 002" } }
],
"delivery": { "method": "zip", "webhook_url": "https://example.com/hooks/pdf" }
}'
const response = await fetch('https://api.respawntech.dev/v1/tools/document/pdf/batch', {
  method: 'POST',
  headers: {
    'X-API-Token': process.env.RESPAWN_API_TOKEN,
    'X-Idempotency-Key': '550e8400-e29b-41d4-a716-446655440002',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
"template": {
  "html": "<html><body><h1>{{title}}</h1></body></html>",
  "css": "h1 { color: #333; }"
},
"config": { "page_size": "A4", "format": "pdf", "retention_days": 7 },
"items": [
  { "custom_id": "fatura-001", "file_name": "fatura-001.pdf", "data": { "title": "Fatura 001" } },
  { "custom_id": "fatura-002", "file_name": "fatura-002.pdf", "data": { "title": "Fatura 002" } }
],
"delivery": { "method": "zip", "webhook_url": "https://example.com/hooks/pdf" }
}),
});

if (!response.ok) throw new Error((await response.json()).error.code);
console.log(await response.json());
import os
import requests

response = requests.post(
    "https://api.respawntech.dev/v1/tools/document/pdf/batch",
    headers={
        "X-API-Token": os.environ["RESPAWN_API_TOKEN"],
        "X-Idempotency-Key": "550e8400-e29b-41d4-a716-446655440002",
    },
    json={
"template": {
  "html": "<html><body><h1>{{title}}</h1></body></html>",
  "css": "h1 { color: #333; }"
},
"config": { "page_size": "A4", "format": "pdf", "retention_days": 7 },
"items": [
  { "custom_id": "fatura-001", "file_name": "fatura-001.pdf", "data": { "title": "Fatura 001" } },
  { "custom_id": "fatura-002", "file_name": "fatura-002.pdf", "data": { "title": "Fatura 002" } }
],
"delivery": { "method": "zip", "webhook_url": "https://example.com/hooks/pdf" }
},
    timeout=30,
)
if not response.ok:
    raise RuntimeError(response.json()["error"]["code"])
print(response.json())
<?php
$ch = curl_init('https://api.respawntech.dev/v1/tools/document/pdf/batch');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('RESPAWN_API_TOKEN'),
        'X-Idempotency-Key: 550e8400-e29b-41d4-a716-446655440002',
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => <<<'JSON'
{
"template": {
  "html": "<html><body><h1>{{title}}</h1></body></html>",
  "css": "h1 { color: #333; }"
},
"config": { "page_size": "A4", "format": "pdf", "retention_days": 7 },
"items": [
  { "custom_id": "fatura-001", "file_name": "fatura-001.pdf", "data": { "title": "Fatura 001" } },
  { "custom_id": "fatura-002", "file_name": "fatura-002.pdf", "data": { "title": "Fatura 002" } }
],
"delivery": { "method": "zip", "webhook_url": "https://example.com/hooks/pdf" }
}
JSON,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

if ($status >= 400) {
    throw new RuntimeException(json_decode($body, true)['error']['code']);
}
print_r(json_decode($body, true));
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"strings"
	"time"
)

func main() {
	req, err := http.NewRequest("POST", "https://api.respawntech.dev/v1/tools/document/pdf/batch", strings.NewReader(`{
"template": {
  "html": "<html><body><h1>{{title}}</h1></body></html>",
  "css": "h1 { color: #333; }"
},
"config": { "page_size": "A4", "format": "pdf", "retention_days": 7 },
"items": [
  { "custom_id": "fatura-001", "file_name": "fatura-001.pdf", "data": { "title": "Fatura 001" } },
  { "custom_id": "fatura-002", "file_name": "fatura-002.pdf", "data": { "title": "Fatura 002" } }
],
"delivery": { "method": "zip", "webhook_url": "https://example.com/hooks/pdf" }
}`))
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Token", os.Getenv("RESPAWN_API_TOKEN"))
	req.Header.Set("X-Idempotency-Key", "550e8400-e29b-41d4-a716-446655440002")
	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{Timeout: 30 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	data, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode >= 400 {
		panic(string(data))
	}
	fmt.Println(string(data))
}

Resposta 202 — conversion_id é o id do batch

{
  "success": true,
  "trace_id": "550e8400-e29b-41d4-a716-446655440000",
  "data": {
    "conversion_id": "3e4f5a6b-7c8d-4e9f-a0b1-c2d3e4f5a6b7",
    "job_id": "batch_1f2e3d4c",
    "status": "processing"
  }
}

Reprocessar falha

POST/v1/tools/document/pdf/{id}/retry
Custo
Custo completo novamente
Dry-run
Não
Autenticação
qualquer um detools:pdf:managetools:manage

Permitido apenas quando status é failed. O corpo aceita as mesmas opções de Converter, então dá para corrigir o HTML ou as opções antes de tentar de novo. O webhook_url do corpo é ignorado: a conversão mantém o que foi enviado originalmente. O custo é cobrado por inteiro outra vez.

curl -sS -X POST 'https://api.respawntech.dev/v1/tools/document/pdf/550e8400-e29b-41d4-a716-446655440000/retry' \
  -H "X-API-Token: $RESPAWN_API_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{
"html": "<html><body><h1>Fatura corrigida</h1></body></html>",
"format": "pdf",
"page_size": "A4"
}'
const response = await fetch('https://api.respawntech.dev/v1/tools/document/pdf/550e8400-e29b-41d4-a716-446655440000/retry', {
  method: 'POST',
  headers: {
    'X-API-Token': process.env.RESPAWN_API_TOKEN,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
"html": "<html><body><h1>Fatura corrigida</h1></body></html>",
"format": "pdf",
"page_size": "A4"
}),
});

if (!response.ok) throw new Error((await response.json()).error.code);
console.log(await response.json());
import os
import requests

response = requests.post(
    "https://api.respawntech.dev/v1/tools/document/pdf/550e8400-e29b-41d4-a716-446655440000/retry",
    headers={
        "X-API-Token": os.environ["RESPAWN_API_TOKEN"],
    },
    json={
"html": "<html><body><h1>Fatura corrigida</h1></body></html>",
"format": "pdf",
"page_size": "A4"
},
    timeout=30,
)
if not response.ok:
    raise RuntimeError(response.json()["error"]["code"])
print(response.json())
<?php
$ch = curl_init('https://api.respawntech.dev/v1/tools/document/pdf/550e8400-e29b-41d4-a716-446655440000/retry');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('RESPAWN_API_TOKEN'),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => <<<'JSON'
{
"html": "<html><body><h1>Fatura corrigida</h1></body></html>",
"format": "pdf",
"page_size": "A4"
}
JSON,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

if ($status >= 400) {
    throw new RuntimeException(json_decode($body, true)['error']['code']);
}
print_r(json_decode($body, true));
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"strings"
	"time"
)

func main() {
	req, err := http.NewRequest("POST", "https://api.respawntech.dev/v1/tools/document/pdf/550e8400-e29b-41d4-a716-446655440000/retry", strings.NewReader(`{
"html": "<html><body><h1>Fatura corrigida</h1></body></html>",
"format": "pdf",
"page_size": "A4"
}`))
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Token", os.Getenv("RESPAWN_API_TOKEN"))
	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{Timeout: 30 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	data, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode >= 400 {
		panic(string(data))
	}
	fmt.Println(string(data))
}

Resposta 202

{
  "success": true,
  "trace_id": "550e8400-e29b-41d4-a716-446655440000",
  "data": {
    "conversion_id": "3e4f5a6b-7c8d-4e9f-a0b1-c2d3e4f5a6b7",
    "job_id": "pdf_4c3b2a19",
    "status": "pending"
  }
}

Opções de página e render

Valem para POST /convert e POST /retry. Valores fora da lista devolvem pdf.invalid_option (ou pdf.invalid_page_size para o tamanho do papel).

CampoValores
page_sizeA3, A4 (padrão), A5, Letter, Legal, Tabloid ou Custom
paper_width, paper_heightpapel personalizado, em polegadas (1 a 200). Só combinam com page_size vazio ou Custom; usados com outro tamanho, dão pdf.invalid_page_size
orientationportrait (padrão) ou landscape
margin_top, margin_bottom, margin_left, margin_rightmargens da página
scaleescala do render
print_backgroundimprime cores e imagens de fundo (padrão true)
media_typeprint ou screen: qual @media o CSS enxerga
color_schemelight ou dark: valor de prefers-color-scheme
page_numbersliga o contador de páginas na posição: header-left, header-center, header-right, footer-left, footer-center ou footer-right
page_number_formattexto do contador, com {page} e {total} (padrão {page} / {total}, até 200 caracteres). Exige page_numbers
jpeg_qualityde 1 a 100 (padrão 90). Só vale com format: jpg

Exemplo: fatura em papel de 8 x 11 polegadas, com contador no rodapé:

curl -sS -X POST 'https://api.respawntech.dev/v1/tools/document/pdf/convert' \
  -H "X-API-Token: $RESPAWN_API_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{
  "url": "https://example.com/relatorio",
  "page_size": "Custom",
  "paper_width": 8,
  "paper_height": 11,
  "media_type": "print",
  "page_numbers": "footer-center",
  "page_number_format": "Página {page} de {total}"
}'

Pós-processamento

post_process age sobre o PDF já renderizado e só vale com format: pdf (com png ou jpg, pdf.invalid_option). Cada recurso é cobrado à parte, veja Custos.

CampoDescrição
post_process.watermark.texttexto da marca d'água, até 200 caracteres
post_process.watermark.imagealternativa ao texto: imagem PNG ou JPEG em base64, até 1 MiB. Envie exatamente um entre text e image
watermark.font_sizede 1 a 300
watermark.colorcor no formato #rrggbb
watermark.opacity, watermark.scalede 0 a 1
watermark.rotationde -180 a 180 graus
watermark.positioncenter, top-left, top-center, top-right, left, right, bottom-left, bottom-center ou bottom-right
watermark.on_toptrue desenha a marca por cima do conteúdo
post_process.pdfatrue converte para PDF/A-2b (arquivamento de longo prazo)
post_process.protection.user_passwordobrigatória se houver protection, até 128 caracteres: senha para abrir o arquivo
protection.owner_passwordsenha de proprietário, até 128 caracteres
protection.permissionso que o leitor pode fazer: print, copy, modify, annotate, fill_forms, assemble. Lista vazia = nenhuma permissão

pdfa e protection não se combinam (o PDF/A proíbe criptografia): a API responde pdf.invalid_option. As senhas são guardadas cifradas só para o worker aplicá-las e não voltam nas respostas.

curl -sS -X POST 'https://api.respawntech.dev/v1/tools/document/pdf/convert' \
  -H "X-API-Token: $RESPAWN_API_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{
  "html": "<html><body><h1>Contrato</h1></body></html>",
  "format": "pdf",
  "post_process": {
    "watermark": { "text": "CONFIDENCIAL", "color": "#cc0000", "opacity": 0.2, "rotation": -45, "position": "center" },
    "protection": { "user_password": "senha-do-leitor", "permissions": ["print"] }
  }
}'

Templates salvos

Guarde o HTML de um documento recorrente na conta e renderize-o só com template_id e data. Cada alteração de conteúdo cria uma versão nova; as anteriores continuam consultáveis.

  • Em POST /convert, template_id não combina com html nem url (pdf.invalid_option). template_version escolhe a versão; 0 ou omitido usa a mais recente.
  • O css, o header_html e o footer_html do template valem como padrão; se você os enviar na conversão, os seus prevalecem.
  • Template ou versão inexistente: pdf.template_not_found. Nome de até 120 caracteres; o html segue os limites de 10 MB e o css de 1 MB.
  • Leituras usam o escopo tools:pdf:read; escritas, tools:pdf:manage (ou tools:manage). Nenhuma delas cobra créditos nem consome a franquia diária.
curl -sS -X POST 'https://api.respawntech.dev/v1/tools/document/pdf/convert' \
  -H "X-API-Token: $RESPAWN_API_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{
  "template_id": "5d4c3b2a-1f0e-4d9c-8b7a-6f5e4d3c2b1a",
  "template_version": 0,
  "data": { "numero": "001" }
}'

Listar templates salvos

GET/v1/tools/document/pdf/templates
Custo
Grátis
Dry-run
Não
Autenticação
qualquer um detools:pdf:readtools:manage

limit (padrão e máximo 100) e offset. A resposta traz items e total.

curl -sS -X GET 'https://api.respawntech.dev/v1/tools/document/pdf/templates?limit=20&offset=0' \
  -H "X-API-Token: $RESPAWN_API_TOKEN"
const response = await fetch('https://api.respawntech.dev/v1/tools/document/pdf/templates?limit=20&offset=0', {
  method: 'GET',
  headers: {
    'X-API-Token': process.env.RESPAWN_API_TOKEN,
  },
});

if (!response.ok) throw new Error((await response.json()).error.code);
console.log(await response.json());
import os
import requests

response = requests.get(
    "https://api.respawntech.dev/v1/tools/document/pdf/templates?limit=20&offset=0",
    headers={
        "X-API-Token": os.environ["RESPAWN_API_TOKEN"],
    },
    timeout=30,
)
if not response.ok:
    raise RuntimeError(response.json()["error"]["code"])
print(response.json())
<?php
$ch = curl_init('https://api.respawntech.dev/v1/tools/document/pdf/templates?limit=20&offset=0');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('RESPAWN_API_TOKEN'),
    ],
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

if ($status >= 400) {
    throw new RuntimeException(json_decode($body, true)['error']['code']);
}
print_r(json_decode($body, true));
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"time"
)

func main() {
	req, err := http.NewRequest("GET", "https://api.respawntech.dev/v1/tools/document/pdf/templates?limit=20&offset=0", nil)
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Token", os.Getenv("RESPAWN_API_TOKEN"))

	client := &http.Client{Timeout: 30 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	data, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode >= 400 {
		panic(string(data))
	}
	fmt.Println(string(data))
}

Resposta 200

{
  "success": true,
  "trace_id": "550e8400-e29b-41d4-a716-446655440000",
  "data": {
    "items": [
      {
        "id": "5d4c3b2a-1f0e-4d9c-8b7a-6f5e4d3c2b1a",
        "name": "Fatura padrão",
        "description": "Fatura mensal com logotipo",
        "current_version": 2,
        "created_at": "2026-10-01T12:00:00Z",
        "updated_at": "2026-10-10T09:30:00Z"
      }
    ],
    "total": 1
  }
}

Salvar template

POST/v1/tools/document/pdf/templates
Custo
Grátis
Dry-run
Não
Autenticação
qualquer um detools:pdf:managetools:manage

name (até 120 caracteres) e html são obrigatórios; description, css, header_html e footer_html são opcionais. Cria a versão 1.

curl -sS -X POST 'https://api.respawntech.dev/v1/tools/document/pdf/templates' \
  -H "X-API-Token: $RESPAWN_API_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{
"name": "Fatura padrão",
"description": "Fatura mensal com logotipo",
"html": "<html><body><h1>Fatura {{numero}}</h1></body></html>",
"css": "h1 { color: #333; }",
"header_html": "",
"footer_html": ""
}'
const response = await fetch('https://api.respawntech.dev/v1/tools/document/pdf/templates', {
  method: 'POST',
  headers: {
    'X-API-Token': process.env.RESPAWN_API_TOKEN,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
"name": "Fatura padrão",
"description": "Fatura mensal com logotipo",
"html": "<html><body><h1>Fatura {{numero}}</h1></body></html>",
"css": "h1 { color: #333; }",
"header_html": "",
"footer_html": ""
}),
});

if (!response.ok) throw new Error((await response.json()).error.code);
console.log(await response.json());
import os
import requests

response = requests.post(
    "https://api.respawntech.dev/v1/tools/document/pdf/templates",
    headers={
        "X-API-Token": os.environ["RESPAWN_API_TOKEN"],
    },
    json={
"name": "Fatura padrão",
"description": "Fatura mensal com logotipo",
"html": "<html><body><h1>Fatura {{numero}}</h1></body></html>",
"css": "h1 { color: #333; }",
"header_html": "",
"footer_html": ""
},
    timeout=30,
)
if not response.ok:
    raise RuntimeError(response.json()["error"]["code"])
print(response.json())
<?php
$ch = curl_init('https://api.respawntech.dev/v1/tools/document/pdf/templates');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('RESPAWN_API_TOKEN'),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => <<<'JSON'
{
"name": "Fatura padrão",
"description": "Fatura mensal com logotipo",
"html": "<html><body><h1>Fatura {{numero}}</h1></body></html>",
"css": "h1 { color: #333; }",
"header_html": "",
"footer_html": ""
}
JSON,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

if ($status >= 400) {
    throw new RuntimeException(json_decode($body, true)['error']['code']);
}
print_r(json_decode($body, true));
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"strings"
	"time"
)

func main() {
	req, err := http.NewRequest("POST", "https://api.respawntech.dev/v1/tools/document/pdf/templates", strings.NewReader(`{
"name": "Fatura padrão",
"description": "Fatura mensal com logotipo",
"html": "<html><body><h1>Fatura {{numero}}</h1></body></html>",
"css": "h1 { color: #333; }",
"header_html": "",
"footer_html": ""
}`))
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Token", os.Getenv("RESPAWN_API_TOKEN"))
	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{Timeout: 30 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	data, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode >= 400 {
		panic(string(data))
	}
	fmt.Println(string(data))
}

Resposta 201

{
  "success": true,
  "trace_id": "550e8400-e29b-41d4-a716-446655440000",
  "data": {
    "id": "5d4c3b2a-1f0e-4d9c-8b7a-6f5e4d3c2b1a",
    "name": "Fatura padrão",
    "description": "Fatura mensal com logotipo",
    "current_version": 1,
    "created_at": "2026-10-01T12:00:00Z",
    "updated_at": "2026-10-10T09:30:00Z"
  }
}

Consultar template

GET/v1/tools/document/pdf/templates/{id}
Custo
Grátis
Dry-run
Não
Autenticação
qualquer um detools:pdf:readtools:manage

version opcional (padrão: a versão atual). Devolve o template e o conteúdo da version.

curl -sS -X GET 'https://api.respawntech.dev/v1/tools/document/pdf/templates/550e8400-e29b-41d4-a716-446655440000?version=2' \
  -H "X-API-Token: $RESPAWN_API_TOKEN"
const response = await fetch('https://api.respawntech.dev/v1/tools/document/pdf/templates/550e8400-e29b-41d4-a716-446655440000?version=2', {
  method: 'GET',
  headers: {
    'X-API-Token': process.env.RESPAWN_API_TOKEN,
  },
});

if (!response.ok) throw new Error((await response.json()).error.code);
console.log(await response.json());
import os
import requests

response = requests.get(
    "https://api.respawntech.dev/v1/tools/document/pdf/templates/550e8400-e29b-41d4-a716-446655440000?version=2",
    headers={
        "X-API-Token": os.environ["RESPAWN_API_TOKEN"],
    },
    timeout=30,
)
if not response.ok:
    raise RuntimeError(response.json()["error"]["code"])
print(response.json())
<?php
$ch = curl_init('https://api.respawntech.dev/v1/tools/document/pdf/templates/550e8400-e29b-41d4-a716-446655440000?version=2');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('RESPAWN_API_TOKEN'),
    ],
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

if ($status >= 400) {
    throw new RuntimeException(json_decode($body, true)['error']['code']);
}
print_r(json_decode($body, true));
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"time"
)

func main() {
	req, err := http.NewRequest("GET", "https://api.respawntech.dev/v1/tools/document/pdf/templates/550e8400-e29b-41d4-a716-446655440000?version=2", nil)
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Token", os.Getenv("RESPAWN_API_TOKEN"))

	client := &http.Client{Timeout: 30 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	data, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode >= 400 {
		panic(string(data))
	}
	fmt.Println(string(data))
}

Resposta 200

{
  "success": true,
  "trace_id": "550e8400-e29b-41d4-a716-446655440000",
  "data": {
    "template": {
      "id": "5d4c3b2a-1f0e-4d9c-8b7a-6f5e4d3c2b1a",
      "name": "Fatura padrão",
      "description": "Fatura mensal com logotipo",
      "current_version": 2,
      "created_at": "2026-10-01T12:00:00Z",
      "updated_at": "2026-10-10T09:30:00Z"
    },
    "version": {
      "template_id": "5d4c3b2a-1f0e-4d9c-8b7a-6f5e4d3c2b1a",
      "version": 2,
      "html": "<html><body><h1>Fatura {{numero}}</h1></body></html>",
      "css": "h1 { color: #333; }",
      "header_html": "",
      "footer_html": "",
      "created_at": "2026-10-10T09:30:00Z"
    }
  }
}

Listar versões do template

GET/v1/tools/document/pdf/templates/{id}/versions
Custo
Grátis
Dry-run
Não
Autenticação
qualquer um detools:pdf:readtools:manage
curl -sS -X GET 'https://api.respawntech.dev/v1/tools/document/pdf/templates/550e8400-e29b-41d4-a716-446655440000/versions' \
  -H "X-API-Token: $RESPAWN_API_TOKEN"
const response = await fetch('https://api.respawntech.dev/v1/tools/document/pdf/templates/550e8400-e29b-41d4-a716-446655440000/versions', {
  method: 'GET',
  headers: {
    'X-API-Token': process.env.RESPAWN_API_TOKEN,
  },
});

if (!response.ok) throw new Error((await response.json()).error.code);
console.log(await response.json());
import os
import requests

response = requests.get(
    "https://api.respawntech.dev/v1/tools/document/pdf/templates/550e8400-e29b-41d4-a716-446655440000/versions",
    headers={
        "X-API-Token": os.environ["RESPAWN_API_TOKEN"],
    },
    timeout=30,
)
if not response.ok:
    raise RuntimeError(response.json()["error"]["code"])
print(response.json())
<?php
$ch = curl_init('https://api.respawntech.dev/v1/tools/document/pdf/templates/550e8400-e29b-41d4-a716-446655440000/versions');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('RESPAWN_API_TOKEN'),
    ],
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

if ($status >= 400) {
    throw new RuntimeException(json_decode($body, true)['error']['code']);
}
print_r(json_decode($body, true));
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"time"
)

func main() {
	req, err := http.NewRequest("GET", "https://api.respawntech.dev/v1/tools/document/pdf/templates/550e8400-e29b-41d4-a716-446655440000/versions", nil)
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Token", os.Getenv("RESPAWN_API_TOKEN"))

	client := &http.Client{Timeout: 30 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	data, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode >= 400 {
		panic(string(data))
	}
	fmt.Println(string(data))
}

Resposta 200

{
  "success": true,
  "trace_id": "550e8400-e29b-41d4-a716-446655440000",
  "data": {
    "items": [
      {
        "template_id": "5d4c3b2a-1f0e-4d9c-8b7a-6f5e4d3c2b1a",
        "version": 2,
        "html": "<html><body><h1>Fatura {{numero}}</h1></body></html>",
        "css": "h1 { color: #333; }",
        "header_html": "",
        "footer_html": "",
        "created_at": "2026-10-10T09:30:00Z"
      },
      {
        "template_id": "5d4c3b2a-1f0e-4d9c-8b7a-6f5e4d3c2b1a",
        "version": 1,
        "html": "<html><body><h1>Fatura</h1></body></html>",
        "css": "h1 { color: #333; }",
        "header_html": "",
        "footer_html": "",
        "created_at": "2026-10-10T09:30:00Z"
      }
    ]
  }
}

Renomear template ou salvar nova versão

PATCH/v1/tools/document/pdf/templates/{id}
Custo
Grátis
Dry-run
Não
Autenticação
qualquer um detools:pdf:managetools:manage

Envie name e/ou description para renomear. Com html, é salva uma nova versão com o html, css, header_html e footer_html do corpo, e current_version sobe. Os campos de conteúdo omitidos ficam vazios na nova versão: reenvie o conteúdo completo.

curl -sS -X PATCH 'https://api.respawntech.dev/v1/tools/document/pdf/templates/550e8400-e29b-41d4-a716-446655440000' \
  -H "X-API-Token: $RESPAWN_API_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{
"name": "Fatura padrão v2",
"html": "<html><body><h1>Fatura {{numero}}</h1><p>{{cliente}}</p></body></html>",
"css": "h1 { color: #333; }"
}'
const response = await fetch('https://api.respawntech.dev/v1/tools/document/pdf/templates/550e8400-e29b-41d4-a716-446655440000', {
  method: 'PATCH',
  headers: {
    'X-API-Token': process.env.RESPAWN_API_TOKEN,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
"name": "Fatura padrão v2",
"html": "<html><body><h1>Fatura {{numero}}</h1><p>{{cliente}}</p></body></html>",
"css": "h1 { color: #333; }"
}),
});

if (!response.ok) throw new Error((await response.json()).error.code);
console.log(await response.json());
import os
import requests

response = requests.patch(
    "https://api.respawntech.dev/v1/tools/document/pdf/templates/550e8400-e29b-41d4-a716-446655440000",
    headers={
        "X-API-Token": os.environ["RESPAWN_API_TOKEN"],
    },
    json={
"name": "Fatura padrão v2",
"html": "<html><body><h1>Fatura {{numero}}</h1><p>{{cliente}}</p></body></html>",
"css": "h1 { color: #333; }"
},
    timeout=30,
)
if not response.ok:
    raise RuntimeError(response.json()["error"]["code"])
print(response.json())
<?php
$ch = curl_init('https://api.respawntech.dev/v1/tools/document/pdf/templates/550e8400-e29b-41d4-a716-446655440000');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'PATCH',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('RESPAWN_API_TOKEN'),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => <<<'JSON'
{
"name": "Fatura padrão v2",
"html": "<html><body><h1>Fatura {{numero}}</h1><p>{{cliente}}</p></body></html>",
"css": "h1 { color: #333; }"
}
JSON,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

if ($status >= 400) {
    throw new RuntimeException(json_decode($body, true)['error']['code']);
}
print_r(json_decode($body, true));
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"strings"
	"time"
)

func main() {
	req, err := http.NewRequest("PATCH", "https://api.respawntech.dev/v1/tools/document/pdf/templates/550e8400-e29b-41d4-a716-446655440000", strings.NewReader(`{
"name": "Fatura padrão v2",
"html": "<html><body><h1>Fatura {{numero}}</h1><p>{{cliente}}</p></body></html>",
"css": "h1 { color: #333; }"
}`))
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Token", os.Getenv("RESPAWN_API_TOKEN"))
	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{Timeout: 30 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	data, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode >= 400 {
		panic(string(data))
	}
	fmt.Println(string(data))
}

Resposta 200

{
  "success": true,
  "trace_id": "550e8400-e29b-41d4-a716-446655440000",
  "data": {
    "id": "5d4c3b2a-1f0e-4d9c-8b7a-6f5e4d3c2b1a",
    "name": "Fatura padrão",
    "description": "Fatura mensal com logotipo",
    "current_version": 3,
    "created_at": "2026-10-01T12:00:00Z",
    "updated_at": "2026-10-10T09:30:00Z"
  }
}

Excluir template

DELETE/v1/tools/document/pdf/templates/{id}
Custo
Grátis
Dry-run
Não
Autenticação
qualquer um detools:pdf:managetools:manage

Apaga o template e todas as versões. As conversões já geradas não são afetadas.

curl -sS -X DELETE 'https://api.respawntech.dev/v1/tools/document/pdf/templates/550e8400-e29b-41d4-a716-446655440000' \
  -H "X-API-Token: $RESPAWN_API_TOKEN"
const response = await fetch('https://api.respawntech.dev/v1/tools/document/pdf/templates/550e8400-e29b-41d4-a716-446655440000', {
  method: 'DELETE',
  headers: {
    'X-API-Token': process.env.RESPAWN_API_TOKEN,
  },
});

if (!response.ok) throw new Error((await response.json()).error.code);
console.log(await response.json());
import os
import requests

response = requests.delete(
    "https://api.respawntech.dev/v1/tools/document/pdf/templates/550e8400-e29b-41d4-a716-446655440000",
    headers={
        "X-API-Token": os.environ["RESPAWN_API_TOKEN"],
    },
    timeout=30,
)
if not response.ok:
    raise RuntimeError(response.json()["error"]["code"])
print(response.json())
<?php
$ch = curl_init('https://api.respawntech.dev/v1/tools/document/pdf/templates/550e8400-e29b-41d4-a716-446655440000');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'DELETE',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('RESPAWN_API_TOKEN'),
    ],
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

if ($status >= 400) {
    throw new RuntimeException(json_decode($body, true)['error']['code']);
}
print_r(json_decode($body, true));
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"time"
)

func main() {
	req, err := http.NewRequest("DELETE", "https://api.respawntech.dev/v1/tools/document/pdf/templates/550e8400-e29b-41d4-a716-446655440000", nil)
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Token", os.Getenv("RESPAWN_API_TOKEN"))

	client := &http.Client{Timeout: 30 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	data, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode >= 400 {
		panic(string(data))
	}
	fmt.Println(string(data))
}

Resposta 204 — sem corpo; apaga o template e todas as versões

Fontes

Envie fontes próprias (woff2 ou ttf) e use-as no HTML com font-family: passe os ids em font_ids (até 20 por conversão) e a plataforma injeta o @font-face correspondente. Fonte inexistente em font_ids: pdf.font_not_found. O adicional de fontes é cobrado uma vez por documento que usa font_ids.

  • Até 50 fontes por conta (pdf.font_limit).
  • Uma combinação de family + weight + style só pode existir uma vez (pdf.font_exists, 409).
  • O formato é detectado pelo conteúdo do arquivo, não pela extensão.

Listar fontes

GET/v1/tools/document/pdf/fonts
Custo
Grátis
Dry-run
Não
Autenticação
qualquer um detools:pdf:readtools:manage
curl -sS -X GET 'https://api.respawntech.dev/v1/tools/document/pdf/fonts' \
  -H "X-API-Token: $RESPAWN_API_TOKEN"
const response = await fetch('https://api.respawntech.dev/v1/tools/document/pdf/fonts', {
  method: 'GET',
  headers: {
    'X-API-Token': process.env.RESPAWN_API_TOKEN,
  },
});

if (!response.ok) throw new Error((await response.json()).error.code);
console.log(await response.json());
import os
import requests

response = requests.get(
    "https://api.respawntech.dev/v1/tools/document/pdf/fonts",
    headers={
        "X-API-Token": os.environ["RESPAWN_API_TOKEN"],
    },
    timeout=30,
)
if not response.ok:
    raise RuntimeError(response.json()["error"]["code"])
print(response.json())
<?php
$ch = curl_init('https://api.respawntech.dev/v1/tools/document/pdf/fonts');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('RESPAWN_API_TOKEN'),
    ],
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

if ($status >= 400) {
    throw new RuntimeException(json_decode($body, true)['error']['code']);
}
print_r(json_decode($body, true));
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"time"
)

func main() {
	req, err := http.NewRequest("GET", "https://api.respawntech.dev/v1/tools/document/pdf/fonts", nil)
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Token", os.Getenv("RESPAWN_API_TOKEN"))

	client := &http.Client{Timeout: 30 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	data, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode >= 400 {
		panic(string(data))
	}
	fmt.Println(string(data))
}

Resposta 200

{
  "success": true,
  "trace_id": "550e8400-e29b-41d4-a716-446655440000",
  "data": {
    "items": [
      {
        "id": "2b3c4d5e-6f70-4a8b-9c0d-1e2f3a4b5c6d",
        "family": "Inter",
        "weight": 400,
        "style": "normal",
        "format": "woff2",
        "size_bytes": 108544,
        "created_at": "2026-10-05T14:00:00Z"
      }
    ]
  }
}

Enviar fonte

POST/v1/tools/document/pdf/fonts
Custo
Grátis
Dry-run
Não
Autenticação
qualquer um detools:pdf:managetools:manage

Envio multipart/form-data com file (obrigatório, woff2 ou ttf, até 5 MiB), family (obrigatório, 1 a 64 letras, números, espaços, - ou _), weight (100 a 900 em passos de 100; padrão 400) e style (normal ou italic; padrão normal). Qualquer violação devolve pdf.font_invalid.

curl -sS -X POST 'https://api.respawntech.dev/v1/tools/document/pdf/fonts' \
  -H "X-API-Token: $RESPAWN_API_TOKEN" \
  -F 'file=@Inter-Regular.woff2' \
  -F 'family=Inter' \
  -F 'weight=400' \
  -F 'style=normal'

Depois, converta com a fonte:

curl -sS -X POST 'https://api.respawntech.dev/v1/tools/document/pdf/convert' \
  -H "X-API-Token: $RESPAWN_API_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{
  "html": "<html><body style=\"font-family: Inter\"><h1>Olá</h1></body></html>",
  "font_ids": ["2b3c4d5e-6f70-4a8b-9c0d-1e2f3a4b5c6d"]
}'
curl -sS -X POST 'https://api.respawntech.dev/v1/tools/document/pdf/fonts' \
  -H "X-API-Token: $RESPAWN_API_TOKEN"
const response = await fetch('https://api.respawntech.dev/v1/tools/document/pdf/fonts', {
  method: 'POST',
  headers: {
    'X-API-Token': process.env.RESPAWN_API_TOKEN,
  },
});

if (!response.ok) throw new Error((await response.json()).error.code);
console.log(await response.json());
import os
import requests

response = requests.post(
    "https://api.respawntech.dev/v1/tools/document/pdf/fonts",
    headers={
        "X-API-Token": os.environ["RESPAWN_API_TOKEN"],
    },
    timeout=30,
)
if not response.ok:
    raise RuntimeError(response.json()["error"]["code"])
print(response.json())
<?php
$ch = curl_init('https://api.respawntech.dev/v1/tools/document/pdf/fonts');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('RESPAWN_API_TOKEN'),
    ],
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

if ($status >= 400) {
    throw new RuntimeException(json_decode($body, true)['error']['code']);
}
print_r(json_decode($body, true));
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"time"
)

func main() {
	req, err := http.NewRequest("POST", "https://api.respawntech.dev/v1/tools/document/pdf/fonts", nil)
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Token", os.Getenv("RESPAWN_API_TOKEN"))

	client := &http.Client{Timeout: 30 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	data, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode >= 400 {
		panic(string(data))
	}
	fmt.Println(string(data))
}

Resposta 201

{
  "success": true,
  "trace_id": "550e8400-e29b-41d4-a716-446655440000",
  "data": {
    "id": "2b3c4d5e-6f70-4a8b-9c0d-1e2f3a4b5c6d",
    "family": "Inter",
    "weight": 400,
    "style": "normal",
    "format": "woff2",
    "size_bytes": 108544,
    "created_at": "2026-10-05T14:00:00Z"
  }
}

Excluir fonte

DELETE/v1/tools/document/pdf/fonts/{id}
Custo
Grátis
Dry-run
Não
Autenticação
qualquer um detools:pdf:managetools:manage

Remove a fonte e o arquivo armazenado.

curl -sS -X DELETE 'https://api.respawntech.dev/v1/tools/document/pdf/fonts/550e8400-e29b-41d4-a716-446655440000' \
  -H "X-API-Token: $RESPAWN_API_TOKEN"
const response = await fetch('https://api.respawntech.dev/v1/tools/document/pdf/fonts/550e8400-e29b-41d4-a716-446655440000', {
  method: 'DELETE',
  headers: {
    'X-API-Token': process.env.RESPAWN_API_TOKEN,
  },
});

if (!response.ok) throw new Error((await response.json()).error.code);
console.log(await response.json());
import os
import requests

response = requests.delete(
    "https://api.respawntech.dev/v1/tools/document/pdf/fonts/550e8400-e29b-41d4-a716-446655440000",
    headers={
        "X-API-Token": os.environ["RESPAWN_API_TOKEN"],
    },
    timeout=30,
)
if not response.ok:
    raise RuntimeError(response.json()["error"]["code"])
print(response.json())
<?php
$ch = curl_init('https://api.respawntech.dev/v1/tools/document/pdf/fonts/550e8400-e29b-41d4-a716-446655440000');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'DELETE',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('RESPAWN_API_TOKEN'),
    ],
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

if ($status >= 400) {
    throw new RuntimeException(json_decode($body, true)['error']['code']);
}
print_r(json_decode($body, true));
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"time"
)

func main() {
	req, err := http.NewRequest("DELETE", "https://api.respawntech.dev/v1/tools/document/pdf/fonts/550e8400-e29b-41d4-a716-446655440000", nil)
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Token", os.Getenv("RESPAWN_API_TOKEN"))

	client := &http.Client{Timeout: 30 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	data, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode >= 400 {
		panic(string(data))
	}
	fmt.Println(string(data))
}

Resposta 204 — sem corpo; apaga a fonte e o arquivo armazenado

Consulta e download

Listar conversões

GET/v1/tools/document/pdf
Custo
Franquia diária, depois 0,005 crédito/leitura via API
Dry-run
Suportado (X-Dry-Run: true)
Autenticação
qualquer um detools:pdf:readtools:manage

Query: limit (padrão 20), offset e exclude_batch=true para ocultar itens de batch. Na listagem, file_url e error_message não são preenchidos — consulte o status de cada conversão.

curl -sS -X GET 'https://api.respawntech.dev/v1/tools/document/pdf?limit=20&offset=0' \
  -H "X-API-Token: $RESPAWN_API_TOKEN"
const response = await fetch('https://api.respawntech.dev/v1/tools/document/pdf?limit=20&offset=0', {
  method: 'GET',
  headers: {
    'X-API-Token': process.env.RESPAWN_API_TOKEN,
  },
});

if (!response.ok) throw new Error((await response.json()).error.code);
console.log(await response.json());
import os
import requests

response = requests.get(
    "https://api.respawntech.dev/v1/tools/document/pdf?limit=20&offset=0",
    headers={
        "X-API-Token": os.environ["RESPAWN_API_TOKEN"],
    },
    timeout=30,
)
if not response.ok:
    raise RuntimeError(response.json()["error"]["code"])
print(response.json())
<?php
$ch = curl_init('https://api.respawntech.dev/v1/tools/document/pdf?limit=20&offset=0');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('RESPAWN_API_TOKEN'),
    ],
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

if ($status >= 400) {
    throw new RuntimeException(json_decode($body, true)['error']['code']);
}
print_r(json_decode($body, true));
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"time"
)

func main() {
	req, err := http.NewRequest("GET", "https://api.respawntech.dev/v1/tools/document/pdf?limit=20&offset=0", nil)
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Token", os.Getenv("RESPAWN_API_TOKEN"))

	client := &http.Client{Timeout: 30 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	data, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode >= 400 {
		panic(string(data))
	}
	fmt.Println(string(data))
}

Resposta 200

{
  "success": true,
  "trace_id": "550e8400-e29b-41d4-a716-446655440000",
  "data": {
    "items": [
      {
        "id": "3e4f5a6b-7c8d-4e9f-a0b1-c2d3e4f5a6b7",
        "job_id": "pdf_9b8c7d6e5f",
        "status": "completed",
        "file_name": "fatura-001.pdf",
        "page_size": "A4",
        "orientation": "portrait",
        "margin_top": 10,
        "margin_bottom": 10,
        "margin_left": 10,
        "margin_right": 10,
        "scale": 1,
        "format": "pdf",
        "enable_js": false,
        "cost_credits": 1.5,
        "cost_units": 15000,
        "retention_days": 7,
        "expires_at": "2026-10-01T12:00:00Z",
        "is_deleted_from_storage": false,
        "html": "<html>…</html>",
        "css": "body { font-family: sans-serif; }",
        "created_at": "2026-09-24T12:00:00Z",
        "updated_at": "2026-09-24T12:00:09Z"
      }
    ],
    "total": 57,
    "page": 1,
    "page_size": 20
  }
}

Status da conversão

GET/v1/tools/document/pdf/{id}
Custo
Franquia diária, depois 0,01 crédito/leitura via API
Dry-run
Suportado (X-Dry-Run: true)
Autenticação
qualquer um detools:pdf:readtools:manage

status: pending, processing, completed ou failed. Em falha, error_code e error_message explicam o motivo. data traz as variáveis enviadas e file_url aparece quando o job termina — para baixar, use sempre Baixar arquivo.

curl -sS -X GET 'https://api.respawntech.dev/v1/tools/document/pdf/550e8400-e29b-41d4-a716-446655440000' \
  -H "X-API-Token: $RESPAWN_API_TOKEN"
const response = await fetch('https://api.respawntech.dev/v1/tools/document/pdf/550e8400-e29b-41d4-a716-446655440000', {
  method: 'GET',
  headers: {
    'X-API-Token': process.env.RESPAWN_API_TOKEN,
  },
});

if (!response.ok) throw new Error((await response.json()).error.code);
console.log(await response.json());
import os
import requests

response = requests.get(
    "https://api.respawntech.dev/v1/tools/document/pdf/550e8400-e29b-41d4-a716-446655440000",
    headers={
        "X-API-Token": os.environ["RESPAWN_API_TOKEN"],
    },
    timeout=30,
)
if not response.ok:
    raise RuntimeError(response.json()["error"]["code"])
print(response.json())
<?php
$ch = curl_init('https://api.respawntech.dev/v1/tools/document/pdf/550e8400-e29b-41d4-a716-446655440000');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('RESPAWN_API_TOKEN'),
    ],
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

if ($status >= 400) {
    throw new RuntimeException(json_decode($body, true)['error']['code']);
}
print_r(json_decode($body, true));
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"time"
)

func main() {
	req, err := http.NewRequest("GET", "https://api.respawntech.dev/v1/tools/document/pdf/550e8400-e29b-41d4-a716-446655440000", nil)
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Token", os.Getenv("RESPAWN_API_TOKEN"))

	client := &http.Client{Timeout: 30 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	data, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode >= 400 {
		panic(string(data))
	}
	fmt.Println(string(data))
}

Resposta 200

{
  "success": true,
  "trace_id": "550e8400-e29b-41d4-a716-446655440000",
  "data": {
    "id": "3e4f5a6b-7c8d-4e9f-a0b1-c2d3e4f5a6b7",
    "job_id": "pdf_9b8c7d6e5f",
    "status": "failed",
    "file_name": "fatura-001.pdf",
    "page_size": "A4",
    "orientation": "portrait",
    "margin_top": 10,
    "margin_bottom": 10,
    "margin_left": 10,
    "margin_right": 10,
    "scale": 1,
    "format": "pdf",
    "enable_js": false,
    "cost_credits": 1.5,
    "cost_units": 15000,
    "retention_days": 7,
    "expires_at": "2026-10-01T12:00:00Z",
    "is_deleted_from_storage": false,
    "html": "<html>…</html>",
    "css": "body { font-family: sans-serif; }",
    "created_at": "2026-09-24T12:00:00Z",
    "updated_at": "2026-09-24T12:00:09Z",
    "error_code": "pdf.render_timeout",
    "error_tag": "pdf.render_timeout",
    "error_message": "O tempo limite de renderização foi excedido",
    "webhook_url": "https://example.com/hooks/pdf",
    "data": "{\"cliente\":\"Ana\"}"
  }
}

Baixar arquivo

GET/v1/tools/document/pdf/{id}/download
Custo
Franquia diária, depois 0,03 crédito/leitura via API
Dry-run
Não
Autenticação
qualquer um detools:pdf:readtools:manage
Timeout
2 minutos

Requer status: completed. O arquivo é descriptografado e descomprimido durante o download. X-Dry-Run não se aplica a downloads.

O campo file_url da conversão (ou do detalhe do batch) é um link assinado com ?sig=&exp=: ele baixa o arquivo sem o cabeçalho X-API-Token e sem consumir a franquia, então serve para entregar o link a um cliente final. Ele vale até a data exp; depois dela, consulte a conversão de novo para obter outro.

curl -sS -X GET 'https://api.respawntech.dev/v1/tools/document/pdf/550e8400-e29b-41d4-a716-446655440000/download' \
  -H "X-API-Token: $RESPAWN_API_TOKEN"
const response = await fetch('https://api.respawntech.dev/v1/tools/document/pdf/550e8400-e29b-41d4-a716-446655440000/download', {
  method: 'GET',
  headers: {
    'X-API-Token': process.env.RESPAWN_API_TOKEN,
  },
});

if (!response.ok) throw new Error((await response.json()).error.code);
const file = Buffer.from(await response.arrayBuffer());
import os
import requests

response = requests.get(
    "https://api.respawntech.dev/v1/tools/document/pdf/550e8400-e29b-41d4-a716-446655440000/download",
    headers={
        "X-API-Token": os.environ["RESPAWN_API_TOKEN"],
    },
    timeout=30,
)
if not response.ok:
    raise RuntimeError(response.json()["error"]["code"])
open("arquivo", "wb").write(response.content)
<?php
$ch = curl_init('https://api.respawntech.dev/v1/tools/document/pdf/550e8400-e29b-41d4-a716-446655440000/download');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('RESPAWN_API_TOKEN'),
    ],
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

if ($status >= 400) {
    throw new RuntimeException(json_decode($body, true)['error']['code']);
}
file_put_contents('arquivo', $body);
package main

import (
	"io"
	"net/http"
	"os"
	"time"
)

func main() {
	req, err := http.NewRequest("GET", "https://api.respawntech.dev/v1/tools/document/pdf/550e8400-e29b-41d4-a716-446655440000/download", nil)
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Token", os.Getenv("RESPAWN_API_TOKEN"))

	client := &http.Client{Timeout: 30 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	data, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode >= 400 {
		panic(string(data))
	}
	if err := os.WriteFile("arquivo", data, 0o644); err != nil {
		panic(err)
	}
}

Resposta 200 — corpo binário com Content-Type do formato (application/pdf, image/png ou image/jpeg) e Content-Disposition: attachment; filename="…"; suporta If-None-Match (304)

Batches

Listar batches

GET/v1/tools/document/pdf/batches
Custo
Franquia diária, depois 0,005 crédito/leitura via API
Dry-run
Suportado (X-Dry-Run: true)
Autenticação
qualquer um detools:pdf:readtools:manage

status do batch: processing, delivering, completed, partially_failed ou failed.

curl -sS -X GET 'https://api.respawntech.dev/v1/tools/document/pdf/batches?limit=20&offset=0' \
  -H "X-API-Token: $RESPAWN_API_TOKEN"
const response = await fetch('https://api.respawntech.dev/v1/tools/document/pdf/batches?limit=20&offset=0', {
  method: 'GET',
  headers: {
    'X-API-Token': process.env.RESPAWN_API_TOKEN,
  },
});

if (!response.ok) throw new Error((await response.json()).error.code);
console.log(await response.json());
import os
import requests

response = requests.get(
    "https://api.respawntech.dev/v1/tools/document/pdf/batches?limit=20&offset=0",
    headers={
        "X-API-Token": os.environ["RESPAWN_API_TOKEN"],
    },
    timeout=30,
)
if not response.ok:
    raise RuntimeError(response.json()["error"]["code"])
print(response.json())
<?php
$ch = curl_init('https://api.respawntech.dev/v1/tools/document/pdf/batches?limit=20&offset=0');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('RESPAWN_API_TOKEN'),
    ],
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

if ($status >= 400) {
    throw new RuntimeException(json_decode($body, true)['error']['code']);
}
print_r(json_decode($body, true));
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"time"
)

func main() {
	req, err := http.NewRequest("GET", "https://api.respawntech.dev/v1/tools/document/pdf/batches?limit=20&offset=0", nil)
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Token", os.Getenv("RESPAWN_API_TOKEN"))

	client := &http.Client{Timeout: 30 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	data, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode >= 400 {
		panic(string(data))
	}
	fmt.Println(string(data))
}

Resposta 200

{
  "success": true,
  "trace_id": "550e8400-e29b-41d4-a716-446655440000",
  "data": {
    "items": [
      {
        "id": "7a6b5c4d-3e2f-4a1b-9c8d-7e6f5a4b3c2d",
        "status": "partially_failed",
        "total_items": 25,
        "completed_items": 24,
        "failed_items": 1,
        "created_at": "2026-09-24T12:00:00Z"
      }
    ],
    "total": 3,
    "page": 1,
    "page_size": 20
  }
}

Detalhe do batch

GET/v1/tools/document/pdf/batches/{id}
Custo
Franquia diária, depois 0,01 crédito/leitura via API
Dry-run
Suportado (X-Dry-Run: true)
Autenticação
qualquer um detools:pdf:readtools:manage
curl -sS -X GET 'https://api.respawntech.dev/v1/tools/document/pdf/batches/550e8400-e29b-41d4-a716-446655440000' \
  -H "X-API-Token: $RESPAWN_API_TOKEN"
const response = await fetch('https://api.respawntech.dev/v1/tools/document/pdf/batches/550e8400-e29b-41d4-a716-446655440000', {
  method: 'GET',
  headers: {
    'X-API-Token': process.env.RESPAWN_API_TOKEN,
  },
});

if (!response.ok) throw new Error((await response.json()).error.code);
console.log(await response.json());
import os
import requests

response = requests.get(
    "https://api.respawntech.dev/v1/tools/document/pdf/batches/550e8400-e29b-41d4-a716-446655440000",
    headers={
        "X-API-Token": os.environ["RESPAWN_API_TOKEN"],
    },
    timeout=30,
)
if not response.ok:
    raise RuntimeError(response.json()["error"]["code"])
print(response.json())
<?php
$ch = curl_init('https://api.respawntech.dev/v1/tools/document/pdf/batches/550e8400-e29b-41d4-a716-446655440000');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('RESPAWN_API_TOKEN'),
    ],
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

if ($status >= 400) {
    throw new RuntimeException(json_decode($body, true)['error']['code']);
}
print_r(json_decode($body, true));
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"time"
)

func main() {
	req, err := http.NewRequest("GET", "https://api.respawntech.dev/v1/tools/document/pdf/batches/550e8400-e29b-41d4-a716-446655440000", nil)
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Token", os.Getenv("RESPAWN_API_TOKEN"))

	client := &http.Client{Timeout: 30 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	data, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode >= 400 {
		panic(string(data))
	}
	fmt.Println(string(data))
}

Resposta 200

{
  "success": true,
  "trace_id": "550e8400-e29b-41d4-a716-446655440000",
  "data": {
    "batch": {
      "id": "7a6b5c4d-3e2f-4a1b-9c8d-7e6f5a4b3c2d",
      "status": "completed",
      "total_items": 1,
      "completed_items": 1,
      "failed_items": 0,
      "created_at": "2026-09-24T12:00:00Z"
    },
    "conversions": [
      {
        "id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
        "job_id": "pdf_9b8c7d6e5f",
        "status": "completed",
        "file_name": "fatura-ana.pdf",
        "page_size": "A4",
        "orientation": "portrait",
        "margin_top": 10,
        "margin_bottom": 10,
        "margin_left": 10,
        "margin_right": 10,
        "scale": 1,
        "format": "pdf",
        "enable_js": false,
        "cost_credits": 1.5,
        "cost_units": 15000,
        "retention_days": 7,
        "expires_at": "2026-10-01T12:00:00Z",
        "is_deleted_from_storage": false,
        "html": "<html>…</html>",
        "css": "body { font-family: sans-serif; }",
        "created_at": "2026-09-24T12:00:00Z",
        "updated_at": "2026-09-24T12:00:09Z",
        "batch_id": "7a6b5c4d-3e2f-4a1b-9c8d-7e6f5a4b3c2d"
      }
    ],
    "template": {
      "html": "<html><body><h1>{{title}}</h1></body></html>",
      "css": ""
    }
  }
}

Download ZIP do batch

GET/v1/tools/document/pdf/batches/{id}/download
Custo
Franquia diária, depois 0,03 crédito/leitura via API
Dry-run
Não
Autenticação
qualquer um detools:pdf:readtools:manage
Timeout
2 minutos

Disponível quando o batch termina, inclusive parcialmente se alguns itens falharem. Também aceita o link assinado ?sig=&exp=, sem token.

curl -sS -X GET 'https://api.respawntech.dev/v1/tools/document/pdf/batches/550e8400-e29b-41d4-a716-446655440000/download' \
  -H "X-API-Token: $RESPAWN_API_TOKEN"
const response = await fetch('https://api.respawntech.dev/v1/tools/document/pdf/batches/550e8400-e29b-41d4-a716-446655440000/download', {
  method: 'GET',
  headers: {
    'X-API-Token': process.env.RESPAWN_API_TOKEN,
  },
});

if (!response.ok) throw new Error((await response.json()).error.code);
const file = Buffer.from(await response.arrayBuffer());
import os
import requests

response = requests.get(
    "https://api.respawntech.dev/v1/tools/document/pdf/batches/550e8400-e29b-41d4-a716-446655440000/download",
    headers={
        "X-API-Token": os.environ["RESPAWN_API_TOKEN"],
    },
    timeout=30,
)
if not response.ok:
    raise RuntimeError(response.json()["error"]["code"])
open("arquivo", "wb").write(response.content)
<?php
$ch = curl_init('https://api.respawntech.dev/v1/tools/document/pdf/batches/550e8400-e29b-41d4-a716-446655440000/download');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('RESPAWN_API_TOKEN'),
    ],
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

if ($status >= 400) {
    throw new RuntimeException(json_decode($body, true)['error']['code']);
}
file_put_contents('arquivo', $body);
package main

import (
	"io"
	"net/http"
	"os"
	"time"
)

func main() {
	req, err := http.NewRequest("GET", "https://api.respawntech.dev/v1/tools/document/pdf/batches/550e8400-e29b-41d4-a716-446655440000/download", nil)
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Token", os.Getenv("RESPAWN_API_TOKEN"))

	client := &http.Client{Timeout: 30 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	data, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode >= 400 {
		panic(string(data))
	}
	if err := os.WriteFile("arquivo", data, 0o644); err != nil {
		panic(err)
	}
}

Resposta 200 — application/zip com os itens concluídos (batch-<id>.zip); itens com falha ficam de fora

Erros

CódigoHTTPQuando
pdf.invalid_request400Corpo da requisição inválido.
pdf.html_required400html e url ausentes: envie um dos dois.
pdf.html_too_large400HTML acima de 10 MB.
pdf.css_too_large400CSS acima de 1 MB.
pdf.invalid_page_size400Tamanho de página inválido.
pdf.invalid_format400Formato diferente de pdf, png ou jpg.
pdf.invalid_url400url (ou google_fonts_url) inválida: precisa ser um endereço público http/https de até 2048 caracteres.
pdf.invalid_option400Opção inválida ou combinação não permitida (html com url, post_process fora do formato pdf, pdfa com protection, template_id com html…).
pdf.template_not_found404Template (ou versão) não encontrado na conta.
pdf.font_not_found404Fonte não encontrada na conta.
pdf.font_invalid400Fonte inválida: arquivo ausente, acima de 5 MiB, que não seja woff2/ttf, ou family, weight ou style fora do permitido.
pdf.font_exists409Já existe uma fonte com a mesma família, peso e estilo.
pdf.font_limit400Limite de 50 fontes por conta atingido.
pdf.retention_invalid400retention_days inválido.
pdf.batch_empty400Batch sem itens.
pdf.batch_too_large400Mais de 500 itens no batch.
pdf.template_required400Template HTML obrigatório no batch.
pdf.not_completed400Download solicitado antes de a conversão terminar.
pdf.no_file400Arquivo não disponível (expirado ou não gerado).
pdf.download_failed400Falha ao ler ou descomprimir o arquivo.
pdf.decrypt_failed400Falha ao preparar o arquivo para download.
pdf.render_failed502Falha no render.
pdf.storage_failed502Falha ao armazenar o arquivo.
pdf.enqueue_failed502Falha ao enfileirar o job.
pdf.render_timeout504Tempo esgotado no render.
pdf.internal500Erro interno ao processar a conversão.
pdf.template_failedassíncronoFalha ao aplicar os dados do item no template (batch).

Peculiaridades

  • Um batch usa um único template HTML; cada item de items[].data preenche os placeholders. custom_id ajuda a relacionar os arquivos gerados com os seus registros.
  • Para PDFs recorrentes, salve um template em vez de reenviar o HTML a cada chamada.
  • retention_days: 0 é efêmero (~24h) — ideal para previews.
  • Prefira webhook_url a consultar o status em loop: cada consulta via API conta na franquia diária.

Atualizado em