🔓 Habilitar a API REST do Postiz
Por padrão, a API pública do Postiz vem desligada. Para evitar que alguém abuse do seu endpoint, é preciso ativar via flag no .env e reiniciar o stack. Depois disso, todos os endpoints ficam disponíveis em /api na mesma porta do app.
O endpoint base segue o padrão {MAIN_URL}/api. Em dev local, vira http://localhost:5000/api. Em produção atrás de domínio, https://postiz.seudominio.com/api.
# ~/postiz/.env — adicione (ou descomente)
API_LIMIT=30
NX_ADD_PLUGINS=false
# Habilitar API pública
IS_GENERAL=true
DISABLE_REGISTRATION=false
# (Opcional) restringir CORS a um domínio específico
FRONTEND_URL=http://localhost:5000
# Aplicar e reiniciar
docker compose up -d --force-recreate postiz
# Smoke test do endpoint base
curl -i http://localhost:5000/api/health
# HTTP/1.1 200 OK
# {"status":"ok"}
💡 Dica prática
Se sua instância do Postiz está em domínio público, considere colocar a rota /api atrás de rate limiting no proxy (Caddy, Traefik, Nginx). A flag API_LIMIT ajuda, mas defesa em camadas é mais segura.
Conceitos-chave
Recursos expostos via HTTP, verbos padrão (GET/POST/PUT/DELETE).
Var de ambiente que liga/desliga funcionalidades sem rebuild.
Prefixo comum a todos os endpoints (/api).
Teto de requisições por janela de tempo por chave/IP.
🔑 Gerar uma API key
A API do Postiz autentica via Bearer token no header Authorization. Cada chave fica vinculada a um usuário e herda os scopes dele — ou seja, só consegue publicar nas contas de redes sociais que aquele usuário conectou.
Na UI: Settings → API Keys → Create new key. Copie o valor na hora — depois que a modal fecha, o token nunca mais aparece (só o hash fica no banco).
# Exemplo de chave gerada (formato real)
pk_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6
# Guarde em variável de ambiente, nunca no código
export POSTIZ_API_KEY="pk_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6"
export POSTIZ_API_URL="http://localhost:5000/api"
# Testar a chave (lista contas conectadas)
curl -s -H "Authorization: Bearer $POSTIZ_API_KEY" \
$POSTIZ_API_URL/integrations \
| jq '.[].name'
✓ O que FAZER
- ✓Criar uma chave por integração (n8n, app próprio, script de bot).
- ✓Nomear cada chave com contexto:
n8n-prod,app-mobile. - ✓Guardar em secret manager (1Password, Vault, env do orquestrador).
- ✓Regenerar imediatamente se houver suspeita de vazamento.
✗ O que NÃO fazer
- ✗Compartilhar uma chave única entre múltiplos sistemas.
- ✗Commitar a chave no git — mesmo em repo privado.
- ✗Mandar a chave pra frontend público (vaza no DevTools).
- ✗Deixar chave de teste ativa após o desenvolvimento.
Conceitos-chave
Token portador enviado no header Authorization.
Conjunto de permissões herdadas do usuário dono da chave.
O banco guarda só o hash; o segredo não pode ser recuperado.
Trocar a chave periodicamente reduz impacto de vazamento.
📤 POST /posts via curl
O endpoint POST /api/posts é o coração da API. Você manda um JSON descrevendo o conteúdo, em quais integrações publicar e quando. O Postiz responde com o postId e enfileira o trabalho no BullMQ.
Os três campos obrigatórios são type (draft, schedule ou now), date (ISO 8601 em UTC) e posts — array com um item por integração.
# Body JSON: agendar um post no LinkedIn e no X
cat > payload.json <<'EOF'
{
"type": "schedule",
"date": "2026-06-01T14:30:00.000Z",
"shortLink": false,
"tags": ["lançamento", "produto"],
"posts": [
{
"integration": { "id": "ckxlinkedin123" },
"value": [
{
"content": "Lançamos uma feature nova: agendamento em massa via API. Quem usa Postiz, vai amar.",
"image": []
}
],
"group": null,
"settings": {}
},
{
"integration": { "id": "ckxtwitter456" },
"value": [
{ "content": "Postiz agora aceita agendamento via API REST. 🚀", "image": [] },
{ "content": "Detalhes no thread abaixo 👇", "image": [] }
],
"group": null,
"settings": {}
}
]
}
EOF
# Disparar o POST
curl -X POST "$POSTIZ_API_URL/posts" \
-H "Authorization: Bearer $POSTIZ_API_KEY" \
-H "Content-Type: application/json" \
-d @payload.json
# Resposta esperada (201 Created)
# {
# "postId": "ckxpost789abc",
# "scheduledFor": "2026-06-01T14:30:00.000Z",
# "status": "QUEUED",
# "integrations": ["ckxlinkedin123", "ckxtwitter456"]
# }
⚡ Dica prática
Para descobrir os integration.id certos, chame GET /api/integrations uma vez e cache os IDs no seu lado. Não dá pra usar o nome da rede — o Postiz precisa do ID da conta específica conectada.
Conceitos-chave
Re-enviar o mesmo POST não deve duplicar — use tags únicas.
Formato padrão de data em UTC: YYYY-MM-DDTHH:mm:ssZ.
O 201 só significa "enfileirado", não "publicado".
Um POST pode fanout para várias integrações simultaneamente.
🔔 Webhooks de status
Como o POST inicial só enfileira o trabalho, o jeito limpo de saber o resultado é receber um webhook. O Postiz dispara um POST para a URL que você cadastrar sempre que um post muda de estado — PUBLISHED, FAILED ou DELETED.
Cadastre o callback em Settings → Webhooks → Add URL. Cada webhook tem um secret usado para assinar o payload no header X-Postiz-Signature — valide isso no seu lado pra confirmar que a requisição veio mesmo do Postiz.
# Payload que o Postiz envia para sua URL
{
"event": "post.published",
"timestamp": "2026-06-01T14:30:12.482Z",
"data": {
"postId": "ckxpost789abc",
"status": "PUBLISHED",
"integration": {
"id": "ckxlinkedin123",
"provider": "linkedin",
"name": "Minha Página LinkedIn"
},
"publishedAt": "2026-06-01T14:30:12.000Z",
"remoteId": "urn:li:share:7203451829",
"remoteUrl": "https://www.linkedin.com/feed/update/urn:li:share:7203451829/",
"tags": ["lançamento", "produto"]
}
}
# Payload de falha (mesma estrutura, status diferente)
{
"event": "post.failed",
"timestamp": "2026-06-01T14:30:09.117Z",
"data": {
"postId": "ckxpost789abc",
"status": "FAILED",
"integration": { "id": "ckxtwitter456", "provider": "x" },
"error": {
"code": "RATE_LIMITED",
"message": "X API: 429 too many requests; retry after 900s"
},
"willRetry": true,
"retryAt": "2026-06-01T14:45:09.000Z"
}
}
📡 Eventos suportados
- post.queued: trabalho aceito e na fila — útil para auditoria.
- post.published: publicação concluída — guarde o
remoteUrlpara deep-link. - post.failed: erro na API da rede; inspecione
error.codepara alertar. - post.deleted: alguém removeu via UI ou API — sincronize seu lado.
🛡️ Dica prática
Responda 200 OK rápido (<2s) e processe o evento em fila do seu lado. Se demorar, o Postiz reenvia — e você processa o mesmo evento duas vezes. Use o postId + event como chave de deduplicação.
Conceitos-chave
URL do seu sistema que o Postiz chama assincronamente.
HMAC do payload assinado com o secret do webhook.
Garantia de entrega — pode chegar duas vezes; deduplicar no consumidor.
Postiz reenvia em backoff se você não responder 2xx.
🔗 Integração com n8n e Make
Tanto n8n quanto Make.com têm nodes nativos do Postiz (community node no n8n; módulo oficial no Make). Eles encapsulam a autenticação Bearer e expõem ações como Create Post, List Integrations, Delete Post. Se preferir, use o HTTP Request node genérico — funciona igual.
Para receber webhooks no n8n, use o Webhook node como trigger e cole a URL gerada no painel de webhooks do Postiz. No Make, use o módulo Custom Webhook.
# Exemplo: n8n HTTP Request node configurado manualmente
{
"method": "POST",
"url": "={{ $env.POSTIZ_API_URL }}/posts",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{ "name": "Authorization", "value": "Bearer {{ $env.POSTIZ_API_KEY }}" },
{ "name": "Content-Type", "value": "application/json" }
]
},
"sendBody": true,
"bodyContentType": "json",
"jsonBody": "={{ JSON.stringify($json.payload) }}"
}
🔄 Fluxo completo no n8n
- 1. Trigger — Schedule (diário 09:00), Webhook (form externo) ou Postgres trigger (novo registro).
- 2. Preparar conteúdo — node de IA (OpenAI/Claude) gera texto + imagem com base no input.
- 3. Montar payload — Function node monta o JSON com
posts[]e datas. - 4. POST Postiz — HTTP Request node ou Postiz node enfileira o post.
- 5. Webhook de retorno — outro workflow escuta
post.publishede atualiza um Google Sheet ou Notion.
🧠 Dica prática
No n8n self-hosted, suba o Postiz e o n8n na mesma docker network. Aí o webhook do Postiz pode apontar para http://n8n:5678/webhook/... sem precisar de domínio público — mais rápido e mais seguro.
Conceitos-chave
Plugin de terceiros que adiciona suporte a uma API ao n8n.
Fallback que sempre funciona — qualquer API REST.
Primeiro node de um workflow; inicia a execução.
JavaScript inline para transformar dados entre passos.
🎯 Fluxo: app próprio → API Postiz → redes
O grande motivo de usar a API do Postiz em vez de integrar direto com cada rede é não reinventar OAuth, renovação de tokens, rate limit e idempotência N vezes. Seu app fala com uma API consistente; o Postiz cuida do resto.
# Arquitetura recomendada
[ Seu App ]
|
| (1) POST /api/posts — Bearer token
v
[ Postiz API ]
|
| (2) enfileira no Redis (BullMQ)
v
[ Worker Postiz ]
|
| (3) chama API de cada rede (OAuth gerenciado pelo Postiz)
v
[ LinkedIn ] [ X ] [ Instagram ] [ Bluesky ] ...
|
| (4) sucesso/erro
v
[ Postiz ]
|
| (5) POST webhook → https://seuapp.com/webhooks/postiz
v
[ Seu App ] (atualiza DB, dispara notificação ao usuário)
✓ Vantagens vs integrar direto
- ✓Uma única autenticação (Bearer) em vez de OAuth por rede.
- ✓Refresh de tokens, retry e rate limit já implementados.
- ✓Agendamento e fila prontos — não precisa de cron/BullMQ próprio.
- ✓Quando o Postiz adiciona uma rede nova, você ganha de graça.
✗ Quando NÃO usar a API
- ✗Você precisa de uma feature exótica que a rede X tem mas Postiz não expõe.
- ✗Volume gigantesco (milhões/dia) — pode bater no rate limit interno.
- ✗Latência crítica em tempo real — passa por fila, não é instantâneo.
- ✗Você já tem integração direta madura e estável.
🚀 Dica prática
Pense no Postiz como um broker de publicação: seu app trata regra de negócio (quem pode postar o quê, quando, com qual aprovação) e o Postiz trata o last mile técnico de chegar nas redes. Essa separação é o que torna a arquitetura escalável.
Conceitos-chave
Camada intermediária que isola producers de consumers.
Uma entrada → várias saídas (uma por rede social).
Seu app não conhece detalhes de cada API de rede.
Publicação é assíncrona; estado final chega via webhook.
🎯 Resumo do Módulo
IS_GENERAL=true no .env, endpoint base em /api.type, date e array posts multi-rede.published/failed com assinatura HMAC e deduplicação.Trilha concluída! 🎉
Você dominou o Postiz: do Docker ao agendamento, das contas conectadas à API programática. A próxima trilha foca em redes sociais — algoritmos, formatos, melhores horários, estratégia de conteúdo por plataforma.