/canaisLista as contas conectadas: _id, rede, nome, usuario e status (ativo, expirado, erro).
curl https://api.posttai.com/canais -H "Authorization: Bearer $POSTTAI_TOKEN"O mesmo token que conecta o Claude (MCP) também abre a API REST. Crie posts, agende, suba mídias e receba avisos assinados quando algo acontecer.
Gere um token em Configurações → Tokens e MCP (planos Profissional e Agência). Ele começa com ptt_, pertence a uma marca e aparece uma vez só. Mande em todo pedido no cabeçalho Authorization:
curl https://api.posttai.com/tokens-api/atual \
-H "Authorization: Bearer ptt_seu_token"2026-10-09T18:30:00-03:00); o Posttai trabalha no horário de Brasília.Toda resposta vem no mesmo envelope. Em erro, body traz a mensagem pronta, em português.
{ "status": "ok", "statusCode": 200, "body": { ... } }
{ "status": "error", "statusCode": 422, "body": "Escolha pelo menos um canal." }401 token inválido ou revogado · 403 sem permissão ou fora do plano · 404 não existe nesta marca · 409 conflito de estado · 422 dado inválido · 429 limite.Contas conectadas da marca. Conectar uma conta nova é feito no app (ou pelo link “Pedir para o cliente conectar”).
/canaisLista as contas conectadas: _id, rede, nome, usuario e status (ativo, expirado, erro).
curl https://api.posttai.com/canais -H "Authorization: Bearer $POSTTAI_TOKEN"/canais/redesRedes disponíveis, com limites de texto e mídia de cada uma.
curl https://api.posttai.com/canais/redes -H "Authorization: Bearer $POSTTAI_TOKEN"/grupos-canaisGrupos de canais (ex.: “Cliente X”), para publicar em vários de uma vez.
curl https://api.posttai.com/grupos-canais -H "Authorization: Bearer $POSTTAI_TOKEN"Um post tem texto base, canais, mídias e, se quiser, um texto próprio por canal (variacoes).
/posts?status=agendado&de=…&ate=…Lista posts. status aceita vários separados por vírgula; de/ate filtram pela data agendada.
curl "https://api.posttai.com/posts?status=agendado,publicado&de=2026-10-01&ate=2026-10-31" -H "Authorization: Bearer $POSTTAI_TOKEN"/posts/:idUm post com publicações por rede (link e erro de cada uma) e histórico.
curl https://api.posttai.com/posts/ID_DO_POST -H "Authorization: Bearer $POSTTAI_TOKEN"/postsCria um rascunho. canais e midias são ids; variacoes é opcional.
curl -X POST https://api.posttai.com/posts -H "Authorization: Bearer $POSTTAI_TOKEN" \
-H "Content-Type: application/json" \
-d '{"conteudo":"Novidade na loja!","canais":["ID_DO_CANAL"],"midias":[]}'/posts/:idAltera texto, canais, mídias, variações ou data (os mesmos campos do POST).
curl -X PUT https://api.posttai.com/posts/ID_DO_POST -H "Authorization: Bearer $POSTTAI_TOKEN" \
-H "Content-Type: application/json" \
-d '{"conteudo":"Texto novo"}'/posts/:id/agendarAgenda. Se a marca exige aprovação, o post vai para a fila de aprovação em vez de agendar.
curl -X POST https://api.posttai.com/posts/ID_DO_POST/agendar -H "Authorization: Bearer $POSTTAI_TOKEN" \
-H "Content-Type: application/json" \
-d '{"agendadoPara":"2026-10-09T18:30:00-03:00"}'/posts/:id/publicar-agoraManda para a fila de publicação agora.
curl -X POST https://api.posttai.com/posts/ID_DO_POST/publicar-agora -H "Authorization: Bearer $POSTTAI_TOKEN"/posts/:id/cancelarTira um post agendado da fila (volta a rascunho).
curl -X POST https://api.posttai.com/posts/ID_DO_POST/cancelar -H "Authorization: Bearer $POSTTAI_TOKEN"/posts/:idExclui ideia, rascunho, cancelado ou com erro.
curl -X DELETE https://api.posttai.com/posts/ID_DO_POST -H "Authorization: Bearer $POSTTAI_TOKEN"/calendario?de=…&ate=…Posts do período em todos os status do calendário.
curl "https://api.posttai.com/calendario?de=2026-10-01&ate=2026-10-31" -H "Authorization: Bearer $POSTTAI_TOKEN"/sugestoes/horarios?rede=instagram&dias=7Horários sugeridos e livres nos próximos dias.
curl "https://api.posttai.com/sugestoes/horarios?rede=instagram&dias=7" -H "Authorization: Bearer $POSTTAI_TOKEN"/midias/urlTraz uma imagem ou vídeo de um endereço público e devolve o _id para usar em midias.
curl -X POST https://api.posttai.com/midias/url -H "Authorization: Bearer $POSTTAI_TOKEN" \
-H "Content-Type: application/json" \
-d '{"url":"https://exemplo.com/foto.jpg"}'/midiasEnvia um arquivo (multipart, campo arquivo, até 100 MB).
curl -X POST https://api.posttai.com/midias -H "Authorization: Bearer $POSTTAI_TOKEN" -F "[email protected]"/midiasBiblioteca de mídias da marca.
curl https://api.posttai.com/midias -H "Authorization: Bearer $POSTTAI_TOKEN"/fluxoEtapas do quadro da marca.
curl https://api.posttai.com/fluxo -H "Authorization: Bearer $POSTTAI_TOKEN"/posts/:id/etapaMove o post de etapa (com responsável e prazo opcionais).
curl -X POST https://api.posttai.com/posts/ID_DO_POST/etapa -H "Authorization: Bearer $POSTTAI_TOKEN" \
-H "Content-Type: application/json" \
-d '{"etapa":"revisao"}'/posts/:id/comentariosComentários da equipe no post.
curl https://api.posttai.com/posts/ID_DO_POST/comentarios -H "Authorization: Bearer $POSTTAI_TOKEN"/posts/:id/comentariosComenta no post.
curl -X POST https://api.posttai.com/posts/ID_DO_POST/comentarios -H "Authorization: Bearer $POSTTAI_TOKEN" \
-H "Content-Type: application/json" \
-d '{"texto":"Pronto para revisar"}'Os links curtos saem em https://api.posttai.com/l/<codigo>. Na hora de publicar, o Posttai acrescenta ?r=<rede> para saber de onde veio cada clique. Nenhum IP é guardado.
/links/encurtarTroca as URLs de um texto por links curtos e devolve o texto novo.
curl -X POST https://api.posttai.com/links/encurtar -H "Authorization: Bearer $POSTTAI_TOKEN" \
-H "Content-Type: application/json" \
-d '{"texto":"Compre em https://loja.com/produto"}'/links/posts/:id/cliquesCliques dos links curtos do post, no total e por rede.
curl https://api.posttai.com/links/posts/ID_DO_POST/cliques -H "Authorization: Bearer $POSTTAI_TOKEN"/links/cliques?posts=id1,id2Total de cliques de vários posts (até 100).
curl "https://api.posttai.com/links/cliques?posts=ID1,ID2" -H "Authorization: Bearer $POSTTAI_TOKEN" Em Configurações → Webhooks, dono e admin cadastram até 5 URLs por marca e escolhem os eventos. Cada envio é um POST com JSON, saindo do nosso worker (nunca trava o app).
post.publicado o post saiu em todas as redes (ou em parte delas, com status: "parcial").post.erro uma ou mais redes recusaram de vez.post.aprovado aprovado pela equipe ou pelo cliente (dados.por).post.reprovado reprovado pela equipe ou ajuste pedido pelo cliente, com dados.motivo.canal.desconectado a conta saiu, expirou ou teve o acesso removido na rede (dados.motivo).webhook.teste só no botão “Testar”.POST https://seu-sistema.com/webhooks/posttai
Content-Type: application/json
X-Posttai-Evento: post.publicado
X-Posttai-Entrega: 6702f0c1a9e4b1d2c3e4f5a6
X-Posttai-Assinatura: t=1791403800,v1=5f0c…e9
{
"id": "6702f0c1a9e4b1d2c3e4f5a6",
"evento": "post.publicado",
"criadoEm": "2026-10-09T21:30:04.120Z",
"idMarca": "66fe…",
"dados": {
"post": { "id": "6701…", "status": "publicado", "trecho": "Lançamento amanhã…", "agendadoPara": "2026-10-09T21:30:00.000Z", "publicadoEm": "2026-10-09T21:30:04.000Z" },
"publicacoes": [{ "idCanal": "66ff…", "rede": "instagram", "status": "publicado", "url": "https://www.instagram.com/p/…", "erro": null }]
}
}id (igual a X-Posttai-Entrega) para ignorar repetidos: a mesma entrega pode chegar mais de uma vez.https://. Endereços internos ou privados (localhost, 10/8, 172.16/12, 192.168/16, 169.254/16, ::1, fc00::/7…) são recusados, inclusive quando o nome resolve para eles no DNS. O segredo (whsec_…) aparece uma vez, ao criar o webhook. A assinatura é HMAC-SHA256(segredo, t + "." + corpo cru) em hexadecimal. Confira sempre com o corpo exatamente como chegou, antes de interpretar o JSON, e recuse t com mais de 5 minutos.
import crypto from 'node:crypto'
import express from 'express'
const app = express()
// Corpo CRU: a assinatura é sobre os bytes que chegaram.
app.post('/webhooks/posttai', express.raw({ type: 'application/json' }), (req, res) => {
const corpo = req.body.toString('utf8')
const { t, v1 } = Object.fromEntries(String(req.get('X-Posttai-Assinatura')).split(',').map(p => p.split('=')))
const esperado = crypto.createHmac('sha256', process.env.POSTTAI_WEBHOOK_SEGREDO).update(`${t}.${corpo}`).digest('hex')
const ok = v1 && esperado.length === v1.length && crypto.timingSafeEqual(Buffer.from(esperado), Buffer.from(v1))
if (!ok || Math.abs(Date.now() / 1000 - Number(t)) > 300) return res.sendStatus(401)
const evento = JSON.parse(corpo)
// ...trate evento.evento e evento.dados (ignore ids de entrega já vistos)
res.sendStatus(204)
})Crie a conta, conecte o time e deixe o calendário pronto. Quando as redes liberarem, é só o Posttai publicar.