Flux by Reportei MCP
Flux by Reportei helps agencies approve and schedule social posts 10x faster with AI. Flux AI creates images, captions and carousels. Clients approve by link with no login, and the Flux MCP server lets you plan and schedule from Claude, ChatGPT or Cursor. 8 networks, unlimited users and posts, from USD 6/month per project.
Servidor MCP hospedado
npx add-mcp 'https://flux.reportei.com/mcp/v1'Instala no Claude Code, Codex, Cursor e outros
Documentação
Bem-vindo à API do Flux
O Flux é a plataforma de planejamento, aprovação e agendamento de conteúdo para redes sociais do ecossistema Reportei. A API v1 é pública e lê e escreve: responde o que está agendado, o que está esperando aprovação e o que já foi publicado, e também envia mídias, cria posts, agenda, publica e registra aprovações, com as mesmas regras da tela.
O modelo é simples. Um projeto é o cliente final da agência, com contas sociais conectadas e fuso horário próprio. Um post é uma peça para uma conta; a mesma peça publicada em várias redes compartilha um grupo de conteúdo. Antes de ir ao ar, o conteúdo pode passar por ciclos de aprovação com revisores.
Projetos
Os clientes que o seu token alcança, com fuso, idioma e as contas conectadas de cada um.
Posts e agendamentos
Filtre por projeto, período, status, rede e tipo de peça. Legenda, mídias e grupo de conteúdo incluídos.
Mídias
Imagem, vídeo e PDF por URL, por arquivo ou em partes, até o teto da rede social (300 MB).
Criar, agendar e publicar
Uma peça em várias contas de uma vez: rascunho, agendamento, publicação imediata ou envio para aprovação.
Aprovações
Quem aprovou, quem pediu ajuste e o que escreveu, e a sua própria decisão, registrada pela API.
Contas conectadas
Detecte uma autorização expirada antes de a publicação falhar, e descubra o que cada conta aceita.
Base URL
https://flux.reportei.com/api/v1
Autenticação
Toda requisição exige um token de acesso no header Authorization, no formato Bearer. O token é emitido pelo Reportei Auth com os escopos que você autorizou, e é vinculado a uma conta: só devolve dados dessa conta. Não existe parâmetro capaz de alcançar dados de outra.
Bearer token
Envie o token em toda requisição, junto do header Accept.
Authorization: Bearer flux_19ZcURVroVw2mRBj41EPxstH8IPgH2XpC6ZtSlBeSJ1XNK6K
Accept: application/json
Como gerar o token
Já autenticado no Flux, acesse Empresa → API e MCP, em /company/edit/api
- 1Na seção Chaves de acesso, clique em Criar chave. A tela de autorização do Reportei abre dentro do próprio Flux.
- 2Entre com a sua conta do Reportei, se ela pedir. O token nasce para a conta (company) que está aberta no Flux.
- 3Marque as permissões que a integração precisa: leitura, escrita ou as duas. Dá para conceder só uma parte; um endpoint chamado sem o escopo correspondente responde 403.
- 4Autorize. O token aparece uma única vez, começando com flux_.
- 5Copie e guarde num gerenciador de segredos. Para revogar, use o botão de revogar na mesma tela. O efeito é imediato.
O token aparece uma única vez
Só o hash fica guardado: depois de fechar a tela, o valor não é recuperável. Se você perder o token, ou se ele for exposto, revogue-o e emita outro. Nunca coloque o token em código versionado ou em aplicação client-side.
Autorização pelo Reportei
Quem emite o token é o Reportei Auth, o mesmo login do ecossistema, num fluxo OAuth. O Flux guarda só o que o Auth não precisa saber: o nome do token e os projetos que ele alcança.
Você escolhe as permissões na tela de consentimento
A tela lista cada escopo pedido, com a descrição do que ele alcança, e deixa desmarcar o que você não quer conceder. Ela nunca concede mais do que foi pedido.
Os escopos vão dentro da credencial
A conta autorizada viaja junto de cada escopo (31:posts:create, por exemplo). Por isso um token alcança uma conta só: uma credencial com escopos de duas contas é recusada.
Revogação e expiração valem na hora
A cada requisição o Flux confirma a credencial com o Reportei Auth, sem cache. Um token revogado ou expirado responde 401 já na chamada seguinte.
Escopos
Cada token carrega os escopos concedidos na autorização. Os quatro de leitura consultam dados; os quatro de escrita criam e alteram conteúdo. Um endpoint chamado sem o escopo correspondente responde 403 com o escopo exigido em details.required_scope.
| Escopo | Na tela de consentimento | Concede |
|---|---|---|
| projects:read | Ver os projetos da conta | GET /projects, GET /projects/{id} |
| posts:read | Ver os posts e o calendário | GET /posts, GET /posts/{id}, GET /posts/group/{asset_group_id} |
| reviews:read | Ver as aprovações e os comentários | GET /posts/{id}/reviews, GET /review-groups, GET /review-groups/{id} |
| integrations:read | Ver as contas conectadas | GET /integrations, GET /integrations/{id}/options |
| media:write Escrita | Enviar mídias | POST /media, GET /media/{id}, /media/uploads/* |
| posts:create Escrita | Criar posts | POST /posts, POST /integrations/{id}/pinterest-boards |
| posts:update Escrita | Alterar posts | PATCH /posts/{id}, POST /posts/group/{asset_group_id}/publish |
| reviews:create Escrita | Criar aprovações | POST /posts/{id}/reviews, POST /posts/group/{asset_group_id}/review-status |
Conceda escrita só para o que a integração faz: um token de relatório não precisa de posts:create. GET /media/{id} é a única leitura liberada por um escopo de escrita: ela devolve o estado de um envio que o próprio token fez, não o acervo.
Alcance de projetos
Além dos escopos, o token tem um alcance de projetos, e ele é sempre o de quem o cria: a tela não pergunta, e ninguém emite um token que alcance mais do que ele próprio alcança no Flux.
Quem alcança todos os projetos
O token alcança todos os projetos da conta, inclusive os criados depois da emissão.
Quem alcança alguns projetos
O token alcança exatamente esses projetos, como estavam na emissão. Um projeto liberado depois não entra; é preciso emitir um token novo.
Precisa de um token restrito a projetos específicos, ou com data de expiração? O suporte do Reportei emite a pedido da conta.
Fora do alcance responde 404, não 403
Projeto fora do alcance do token responde 404, igual a projeto inexistente: a API não distingue os dois casos, para não revelar a existência de dados que você não pode ler. Isso vale para GET /projects/{id}, GET /posts/{id}, o filtro?project_id= e qualquer combinação de filtros na listagem.
Se você não sabe qual é o alcance do seu token, GET /api/v1/projects responde exatamente com o que ele enxerga.
Convenções
Paginação, fuso horário, expiração das mídias, limite de requisições e idempotência valem para todos os endpoints.
Paginação
As listagens usam o formato padrão {data, links, meta}. O parâmetro per_page aceita de 1 a 50, com padrão 15. Acima de 50 a API responde 422. O parâmetro page começa em 1.
{
"data": [],
"links": {
"first": "https://flux.reportei.com/api/v1/projects?per_page=2&page=1",
"last": "https://flux.reportei.com/api/v1/projects?per_page=2&page=3",
"prev": null,
"next": "https://flux.reportei.com/api/v1/projects?per_page=2&page=2"
},
"meta": {
"current_page": 1,
"from": 1,
"last_page": 3,
"path": "https://flux.reportei.com/api/v1/projects",
"per_page": 2,
"to": 2,
"total": 5
}
}
Siga links.next como ele vem, sem remontar a URL: ele já carrega os filtros e o per_page da chamada original.
Datas e fuso horário
Toda data e hora sai em ISO-8601 com o offset do fuso do projeto. Cada projeto tem o seu, e o mesmo instante aparece com offsets diferentes em projetos diferentes.
"schedule_at": "2026-09-15T07:00:00-03:00" // projeto em America/Sao_Paulo
"schedule_at": "2026-09-15T07:00:00+01:00" // projeto em Europe/Lisbon
Os filtros start_date e end_date recebem apenas a data (AAAA-MM-DD) e são interpretados no fuso do projeto, com os limites inclusivos (de 00:00:00 a 23:59:59).
URLs de mídia expiram em 48 horas
As URLs em media[].url são assinadas e temporárias: expiram 48 horas após a resposta, como indicado em media[].url_expires_at. O mesmo vale para o thumbnail dos posts de um grupo.
Não persista essas URLs. Se precisar do arquivo, baixe-o e armazene o binário do seu lado: guardar a URL resulta em link quebrado dois dias depois. Para obter uma URL nova, consulte o post outra vez.
Limite de requisições
120requisições por minuto, por token
20escritas por minuto, por token
Os dois limites valem ao mesmo tempo: uma escrita consome dos dois. Ao exceder, a API responde 429 com o header Retry-After indicando quantos segundos aguardar. Respeite o intervalo em vez de tentar de novo imediatamente.
Idempotência
Todo POST que cria algo aceita o header Idempotency-Key: um valor único por operação, gerado por você (um uuid serve). Ele é opcional, mas recomendado. Com a chave, o Flux guarda a resposta da primeira chamada e, se a mesma chave voltar com o mesmo corpo, devolve essa resposta em vez de criar um segundo registro. É o que protege a sua automação de um post duplicado depois de um timeout ou de um retry de fila. Sem a chave, cada envio é atendido como novo. Os endpoints que aceitam a chave vêm marcados com Idempotency-Key.
Idempotency-Key: 2c9a1f77-5c1e-4d3a-91f0-7b2e4a6d8c10
- •Mesma chave, mesmo corpo: a resposta original, com o header Idempotent-Replay: true.
- •Mesma chave, corpo diferente: 422 idempotency_key_reused. Gere outra chave.
- •O corpo é comparado byte a byte: o mesmo JSON com os campos em outra ordem conta como corpo diferente. Ao repetir, reenvie exatamente o mesmo corpo.
- •Chave ausente: a requisição é atendida normalmente, sem proteção contra reenvio.
- •Mesma chave enquanto a primeira ainda está em andamento: 409 conflict. Aguarde alguns segundos e reenvie com a mesma chave. Se a primeira foi interrompida no meio, a chave é liberada depois de 5 minutos.
- •Resposta de erro não é guardada: corrija o corpo e reenvie com a mesma chave.
- •A resposta fica guardada por 24 horas. Depois disso, a chave vale como nova.
- •A chave vale para a conta inteira, em qualquer endpoint e com qualquer token: a mesma chave em outro endpoint conta como corpo diferente (422 idempotency_key_reused). Outra conta pode usar o mesmo valor sem colidir.
- •PATCH não exige a chave: reenviar o mesmo corpo leva ao mesmo estado.
Como usar
- 1.Gere a chave uma vez por operação, antes da primeira tentativa. Um uuid v4 serve.
- 2.Guarde a chave junto da operação (na mensagem da fila, no registro do job) para que o retry use a mesma, mesmo depois de o processo reiniciar.
- 3.Em timeout, falha de rede, 409, 429 ou 5xx, reenvie com a mesma chave e o mesmo corpo. Um 2xx com Idempotent-Replay: true é o resultado da primeira chamada: trate como sucesso.
- 4.Em outro 4xx, corrija o corpo antes de reenviar. Operação nova, chave nova.
# One key per operation, created before the first attempt and reused on every retry
KEY=$(uuidgen)
for attempt in 1 2 3 4 5; do
status=$(curl -s -o response.json -w "%{http_code}" -X POST "https://flux.reportei.com/api/v1/posts" \
-H "Authorization: Bearer $FLUX_TOKEN" \
-H "Idempotency-Key: $KEY" \
-H "Content-Type: application/json" \
-d @post.json)
case "$status" in
2*) break ;; # created now, or the stored response (Idempotent-Replay: true)
000|409|429|5*) sleep $((attempt * attempt)) ;; # network, in progress, rate limit, server: same key, same body
*) break ;; # other 4xx: fix the body; a new operation gets a new key
esac
done
Status de post
O campo status usa um vocabulário público estável, que agrupa os estados internos do Flux. Os estados internos podem mudar entre versões; estes sete valores, não.
draft
Rascunho, ainda em edição
in_review
Em aprovação com o cliente ou revisor
scheduled
Aprovado e agendado, aguardando a hora de publicar
publishing
Em publicação neste momento
published
Publicado com sucesso
failed
A publicação falhou
archived
Arquivado
Situação da aprovação
O campo review_status só é preenchido enquanto o post está em in_review; nos demais status vem null. Em in_review ele é sempre um dos três valores abaixo, nunca null.
pending
Enviado para revisão, sem resposta ainda
approved
Aprovado pelo revisor
request_changes
Revisor pediu ajustes
Redes e tipos de peça
O campo network identifica a integração específica e network_group agrupa as variações da mesma rede: instagram e instagram_business, por exemplo, compartilham o grupo instagram.
network
instagraminstagram_businessfacebookthreadsxyoutubelinkedinlinkedin_personaltiktokpinterestgoogle_my_business
network_group
instagramfacebookthreadsxyoutubelinkedintiktokpinterestgoogle_my_business
type
feedstoryreelsshortsphoto
Projetos
Um projeto é o cliente final da agência. É por aqui que se começa: o id devolvido aqui é o project_id dos demais endpoints, e o timezone do projeto é o fuso de todas as datas dos posts dele.
GET /api/v1/projects projects:read
Listar projetos
Projetos da conta do token, com as contas conectadas de cada um. Por padrão a listagem traz apenas os ativos.
| Nome | Tipo | Descrição |
|---|---|---|
| archived | boolean | 1 retorna somente os projetos arquivados |
| all | boolean | 1 retorna ativos e arquivados juntos |
| per_page | integer | 1 a 50, padrão 15 |
| page | integer | Página, a partir de 1 |
curl -H "Authorization: Bearer $FLUX_TOKEN" \
-H "Accept: application/json" \
"https://flux.reportei.com/api/v1/projects?per_page=2"
GET /api/v1/projects/{id} projects:read
Consultar um projeto
Um projeto pelo id, com as contas conectadas. Um projeto que não existe, que foi excluído ou que pertence a outra conta responde 404.
curl -H "Authorization: Bearer $FLUX_TOKEN" \
-H "Accept: application/json" \
"https://flux.reportei.com/api/v1/projects/5"
O campo status de cada integração indica a saúde da conexão: active quando a conta está conectada e válida, e outro valor quando exige reconexão pelo painel do Flux.
Mídias
Imagem, vídeo e PDF entram por aqui antes de virar post. A mídia nasce solta, dentro de um projeto, e só passa a fazer parte de um post quando POST /posts a referencia em media_ids. O teto é o da rede social: 300 MB.
Por URL
Envie source_url e o próprio Flux baixa o arquivo. Arquivo grande nasce processing e termina em segundo plano.
Por arquivo
multipart/form-data com o campo file, até 40 MB numa requisição só.
Em partes
Acima de 40 MB, com o arquivo em mãos: abra uma sessão, envie as partes e feche. Dá para retomar se a conexão cair.
POST /api/v1/media media:write Idempotency-Key
Enviar uma mídia
Cria a mídia a partir de uma URL (JSON com source_url) ou do arquivo (multipart com file). O recurso criado é idêntico nos dois caminhos: 201 Created, com Location apontando para GET /media/{id}.
Cabeçalhos
| Nome | Tipo | Descrição |
|---|---|---|
| Idempotency-Key | string | Opcional. Um valor único por operação (um uuid serve). Reenviar a mesma chave com o mesmo corpo devolve a resposta guardada, sem criar um segundo registro. Sem a chave, a requisição é atendida normalmente. Ver como funciona a idempotência |
Corpo da Requisição
| Campo | Tipo | Descrição |
|---|---|---|
| project_id | integer | Obrigatório. Projeto dono da mídia |
| source_url | string | https apenas. Não pode vir junto de file |
| file | file | Envio multipart, até 40 MB. Acima disso, use source_url ou o envio em partes |
| description | string | Opcional, até 200 caracteres |
curl -X POST "https://flux.reportei.com/api/v1/media" \
-H "Authorization: Bearer $FLUX_TOKEN" \
-H "Idempotency-Key: 8f1b6c2e-3a44-4f0b-9c21-1d5a7e9f0c33" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{ "project_id": 3312, "source_url": "https://cdn.cliente.com/setembro/pao-na-pedra.jpg" }'
curl -X POST "https://flux.reportei.com/api/v1/media" \
-H "Authorization: Bearer $FLUX_TOKEN" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Accept: application/json" \
-F "project_id=3312" \
-F "file=@pao-na-pedra.jpg"
Status da mídia
ready
Pronta para usar em um post
processing
Ainda baixando ou processando; um post não aceita mídia neste estado
failed
A origem não respondeu; envie o arquivo de novo
O que o Flux confere no envio
O tipo é decidido pelo conteúdo do arquivo, nunca pela extensão. Aceitamos imagem, vídeo e PDF.
source_url precisa ser https e apontar para um endereço público: endereço interno, http e redirecionamento para rede privada respondem 422. A url devolvida expira em 48 horas, como as demais.
GET /api/v1/media/{id} media:write
Consultar o estado de uma mídia
Mesmo corpo do envio. É assim que quem enviou um vídeo por URL sabe quando pode criar o post: status passa de processing para ready, ou para failed.
curl -H "Authorization: Bearer $FLUX_TOKEN" \
-H "Accept: application/json" \
"https://flux.reportei.com/api/v1/media/998812"
Envio em partes
É o caminho do arquivo acima de 40 MB com o arquivo em mãos. Toda parte tem exatamente part_size bytes, menos a última, e a parte 1 vai primeiro: é nela que o tipo do arquivo é decidido. As demais podem ir em qualquer ordem, e reenviar uma parte a sobrescreve. A sessão vale 24 horas.
POST /api/v1/media/uploads media:write Idempotency-Key
Abrir um envio em partes
Devolve o upload_id, o tamanho de cada parte e quantas partes o arquivo terá.
Cabeçalhos
| Nome | Tipo | Descrição |
|---|---|---|
| Idempotency-Key | string | Opcional. Um valor único por operação (um uuid serve). Reenviar a mesma chave com o mesmo corpo devolve a resposta guardada, sem criar um segundo registro. Sem a chave, a requisição é atendida normalmente. Ver como funciona a idempotência |
Corpo da Requisição
| Campo | Tipo | Descrição |
|---|---|---|
| project_id | integer | Obrigatório |
| file_name | string | Nome do arquivo, até 255 caracteres |
| size | integer | Tamanho total em bytes, até 300 MB |
| description | string | Opcional, até 200 caracteres |
curl -X POST "https://flux.reportei.com/api/v1/media/uploads" \
-H "Authorization: Bearer $FLUX_TOKEN" \
-H "Idempotency-Key: b1d9c4e7-2f60-4a81-9e35-70cc2d1a4f88" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{ "project_id": 3312, "file_name": "reels-setembro.mp4", "size": 214958080 }'
PUT /api/v1/media/uploads/{upload_id}/parts/{n} media:write
Enviar uma parte
Corpo binário (application/octet-stream). Responde 204 No Content.
curl -X PUT "https://flux.reportei.com/api/v1/media/uploads/upl_01j9x7qk2p8vyq4h5t3m6n0rzb/parts/1" \
-H "Authorization: Bearer $FLUX_TOKEN" \
-H "Content-Type: application/octet-stream" \
--data-binary @parte-001.bin
GET /api/v1/media/uploads/{upload_id} media:write
Consultar o envio
received_parts diz o que já chegou: se a conexão caiu no meio, continue de onde parou.
curl -H "Authorization: Bearer $FLUX_TOKEN" \
-H "Accept: application/json" \
"https://flux.reportei.com/api/v1/media/uploads/upl_01j9x7qk2p8vyq4h5t3m6n0rzb"
POST /api/v1/media/uploads/{upload_id}/complete media:write
Fechar o envio
Responde 201 com o mesmo corpo de POST /media. Daqui em diante a mídia é igual a qualquer outra. Não pede Idempotency-Key: a sessão identifica a operação, e fechar duas vezes devolve a mesma mídia.
curl -X POST "https://flux.reportei.com/api/v1/media/uploads/upl_01j9x7qk2p8vyq4h5t3m6n0rzb/complete" \
-H "Authorization: Bearer $FLUX_TOKEN" \
-H "Accept: application/json"
Quando quem tem o arquivo não tem a chave
É o caso de um assistente conversando pelo MCP: a ferramenta flux_prepare_media_upload devolve um endereço assinado de uso único, válido por 15 minutos, ou abre um envio em partes com um segredo próprio. Esse segredo alcança só aquela sessão (nem leitura, nem post) e a sua chave de API nunca entra no comando.
Posts
Posts são as peças de conteúdo, uma por conta de destino. A mesma peça publicada em várias redes compartilha um grupo de conteúdo, cujo id vem em asset_group_id.
GET /api/v1/posts posts:read
Listar posts
Posts com filtros combináveis de projeto, janela de datas, status, rede, tipo de peça e situação de aprovação.
| Nome | Tipo | Descrição |
|---|---|---|
| project_id | integer | Restringe a um projeto. Um id fora do alcance do token responde 404 |
| start_date | date | Posts com schedule_at a partir desta data, inclusive (AAAA-MM-DD) |
| end_date | date | Posts com schedule_at até esta data, inclusive. Precisa ser maior ou igual a start_date |
| status | string | array | Um ou mais status públicos. Aceita status=scheduled e status[]=scheduled&status[]=published |
| network | string | array | Filtra pela rede. Aceita valor único ou lista |
| network_group | string | Filtra pelo grupo de rede |
| type | string | array | feed, story, reels, shorts ou photo |
| review_status | string | pending, approved ou request_changes. Como só posts em revisão têm esse campo, o filtro restringe implicitamente a status=in_review |
| order | string | schedule_at (padrão) ou created_at |
| direction | string | asc (padrão) ou desc |
| per_page | integer | 1 a 50, padrão 15 |
| page | integer | Página, a partir de 1 |
curl -H "Authorization: Bearer $FLUX_TOKEN" \
-H "Accept: application/json" \
"https://flux.reportei.com/api/v1/posts?status=published&per_page=1"
Filtro inválido responde 422
Parâmetros desconhecidos são ignorados, mas um valor inválido em um parâmetro conhecido responde 422: a API não devolve lista vazia para filtro errado.
Campos do post
| Campo | Descrição |
|---|---|
| id | Identificador do post no Flux |
| asset_group_id | Grupo de conteúdo do post: a mesma peça publicada em várias redes compartilha esse id |
| project | Projeto dono do post, com o fuso usado nas datas |
| network | Rede de destino (network) e o grupo que reúne suas variações (network_group) |
| account | Conta conectada onde o post será publicado; id é o identificador na rede |
| type | feed, story, reels, shorts ou photo |
| status | Status público do post |
| review_status | Situação da aprovação, apenas quando status é in_review |
| caption | Legenda final em texto plano, já com os placeholders resolvidos. Quando o post não tem legenda própria, cai para a legenda do grupo de conteúdo |
| first_comment | Primeiro comentário programado (Instagram), quando houver |
| schedule_at | Data e hora do agendamento. null em post sem agendamento definido |
| published_url | URL do post na rede, preenchida após a publicação |
| media | Arquivos anexados, na ordem de publicação |
Campos da mídia
| Campo | Descrição |
|---|---|
| id | Identificador do arquivo |
| type | image, video ou pdf |
| url | URL temporária assinada: expira em 48h, não persista |
| url_expires_at | Momento exato da expiração da URL |
| width | Largura em pixels, quando conhecida |
| height | Altura em pixels, quando conhecida |
| aspect_ratio | Proporção, por exemplo 4:5 |
Campos podem vir null quando o arquivo foi enviado antes de o Flux passar a extrair aquele metadado.
GET /api/v1/posts/{id} posts:read
Consultar um post
O mesmo objeto da listagem, sob a chave data, mais o bloco review com o agregado da aprovação. Um post que não existe, que foi excluído ou que pertence a outra conta responde 404.
curl -H "Authorization: Bearer $FLUX_TOKEN" \
-H "Accept: application/json" \
"https://flux.reportei.com/api/v1/posts/30"
O bloco review
GET /posts/{id} devolve o mesmo objeto da listagem mais o bloco review, com o agregado da aprovação. Ele só é preenchido enquanto o post está em in_review; nos demais status vem null. O bloco não existe na listagem: agregá-lo por linha custaria uma consulta por post.
| Campo | Descrição |
|---|---|
| status | Situação agregada da aprovação. Sempre igual ao review_status do mesmo post |
| cycle_started_at | Início do ciclo de aprovação corrente. null em post que nunca foi reenviado para revisão |
| reviewers_total | Revisores atribuídos ao post neste momento |
| decided | Decisões válidas no ciclo corrente, uma por revisor |
| approved | Quantas dessas decisões foram aprovações |
| request_changes | Quantas dessas decisões pediram ajuste |
| pending | Revisores atribuídos que ainda não decidiram no ciclo corrente |
decided + pending pode não fechar com reviewers_total
decided conta decisões, pending conta revisores. Um revisor que decidiu e depois foi retirado do post continua em decided mas não entra em reviewers_total. A leitura confiável de "falta alguém aprovar" é pending > 0.
GET /api/v1/posts/group/{asset_group_id} posts:read
Consultar um grupo de conteúdo
O resumo do lote (o que ele é como um todo) e os posts, resumidos. Um grupo que não existe, cujos posts foram excluídos ou que pertence a outra conta responde 404.
curl -H "Authorization: Bearer $FLUX_TOKEN" \
-H "Accept: application/json" \
"https://flux.reportei.com/api/v1/posts/group/71"
Campos do grupo de conteúdo
Um grupo de conteúdo é a peça escrita uma vez e publicada em várias redes: cada rede vira um post, e todos carregam o mesmo asset_group_id.
| Campo | Descrição |
|---|---|
| id | Identificador do grupo. É o asset_group_id que os posts carregam |
| project | Projeto dono do grupo, com o fuso usado nas datas |
| review_group_id | Grupo de aprovação a que o lote pertence. null quando nunca foi enviado para revisão |
| posts_count | Posts do grupo, um por rede |
| networks | Redes alcançadas pelo lote, sem repetir |
| accounts | Contas conectadas onde o lote será publicado, sem repetir |
| status_summary | Quantos posts em cada status, só os status presentes, na ordem do ciclo de vida |
| schedule_dates | Datas de agendamento do lote, sem repetir e em ordem. Post sem agendamento não entra |
O grupo vem inteiro, sem paginação: são poucos posts, um por rede. Cada post vem resumido, com um thumbnail da primeira mídia. Legenda, mídias e o bloco review continuam em GET /posts/{id}.
Criar e alterar posts
A criação acontece por peça: o nível raiz é a peça (legenda, mídias, título interno) e posts[] traz um item por conta, com o que diverge dela. O corpo devolvido é o grupo de conteúdo: foi ele que nasceu, e é por ele que você acompanha a peça inteira.
POST /api/v1/posts posts:create Idempotency-Key
Criar um post
Cria uma peça em uma ou mais contas conectadas do mesmo projeto. A peça precisa ter mídia ou legenda. Responde 201 Created, com Location apontando para GET /posts/group/{asset_group_id}.
Cabeçalhos
| Nome | Tipo | Descrição |
|---|---|---|
| Idempotency-Key | string | Opcional. Um valor único por operação (um uuid serve). Reenviar a mesma chave com o mesmo corpo devolve a resposta guardada, sem criar um segundo registro. Sem a chave, a requisição é atendida normalmente. Ver como funciona a idempotência |
Corpo da Requisição
| Campo | Tipo | Descrição |
|---|---|---|
| project_id | integer | Obrigatório |
| intent | string | draft, schedule, publish_now ou send_to_review (ver abaixo) |
| caption | string | Legenda da peça, herdada por todo post que não trouxer a sua |
| media_ids | integer[] | Mídias já enviadas, na ordem. Herdadas por todo post que não trouxer as suas |
| title | string | Opcional, até 255 caracteres. Nome interno, nunca publicado |
| category_ids | integer[] | Opcional. Categorias do mesmo projeto |
| schedule_at | datetime | ISO-8601, lido no fuso do projeto. Obrigatório com intent schedule; com send_to_review, é o pré-agendamento |
| review_group_id | integer | Grupo de aprovação que recebe a peça. Com send_to_review, informe este campo ou individual_approval |
| individual_approval | boolean | true envia só esta peça para revisão, sem grupo, com um link de aprovação próprio |
| publish_only_if_approved | boolean | Obrigatório no pré-agendamento, sem valor padrão: true só publica na data se aprovado; false publica mesmo sem aprovação |
| posts | object[] | 1 a 20 itens, um por conta (ver abaixo) |
curl -X POST "https://flux.reportei.com/api/v1/posts" \
-H "Authorization: Bearer $FLUX_TOKEN" \
-H "Idempotency-Key: 2c9a1f77-5c1e-4d3a-91f0-7b2e4a6d8c10" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"project_id": 3312,
"intent": "schedule",
"schedule_at": "2026-09-25T07:00:00-03:00",
"caption": "O pão na pedra sai às 7h.",
"media_ids": [998812],
"posts": [
{ "integration_id": 88104, "type": "feed", "options": { "first_comment": "#padaria" } },
{ "integration_id": 88105, "type": "feed" }
]
}'
intent: o que acontece com a peça
| Campo | Descrição |
|---|---|
| draft | Rascunho. Nada é publicado |
| schedule | Agenda para schedule_at. Na hora marcada o post vai ao ar sozinho, sem nova confirmação |
| publish_now | Publica em instantes e não tem volta, como o botão Publicar agora da tela. Não aceita schedule_at nem campos de aprovação |
| send_to_review | Envia para aprovação, num grupo (review_group_id) ou sozinha (individual_approval). Com schedule_at, vira pré-agendamento |
Itens de posts[]
| Campo | Descrição |
|---|---|
| integration_id | Conta conectada de destino, do mesmo projeto (GET /integrations) |
| type | Um dos supported_types da conta |
| caption | Legenda só desta conta, no lugar da legenda da peça |
| media_ids | Mídias só desta conta, no lugar das mídias da peça |
| options | O que só aquela rede entende: first_comment, board_id, privacy, category_id, cover_media_id… Os campos aceitos por rede estão em limits |
O que observar
schedule_at é lido no fuso do projeto; outro offset é convertido, não recusado. O mínimo é 5 minutos à frente, ou 120 minutos quando o post depende de aprovação.
publish_now põe o post na fila de publicação na hora. Use só com a confirmação expressa de quem responde pelo conteúdo.
Pré-agendamento é send_to_review com schedule_at: o post vai para aprovação já com a data, e publish_only_if_approved decide o que acontece se a data chegar sem aprovação.
Uma conta pode aparecer em tipos diferentes (feed e story), nunca duas vezes no mesmo tipo.
Um item inválido no meio de posts[] não deixa meio grupo criado: ou nasce a peça inteira, ou nada.
Mídia ainda processing responde 422, apontando GET /media/{id}.
Regras por rede
Pinterest: o quadro é obrigatório
options.board_id precisa ser um quadro da própria conta; um id fora da lista responde 422 com os quadros válidos. Quem escolhe o quadro é a pessoa. Se nenhum servir, crie um com POST /integrations/{id}/pinterest-boards.
TikTok: privacidade e divulgação são escolhas da pessoa
options.privacy precisa ser um dos níveis que a conta libera (GET /integrations/{id}/options). duet e stitch não existem em foto; interação desativada na conta não pode ser ligada; brand_content true exige my_brand e/ou paid_content; paid_content não aceita SELF_ONLY. Ao postar, a pessoa concorda com a Confirmação de Uso de Música do TikTok e, com paid_content, com a Política de Conteúdo de Marca. Mostre isso a ela antes.
YouTube: título, privacidade e categoria do Shorts
title e privacy_status são obrigatórios, e os valores de privacy_status e category_id vêm de GET /integrations/{id}/options. tags, content_for_kids e notify_subscribers são opcionais.
Capa de reels (Instagram e Facebook)
Envie a imagem da capa como mídia antes e informe o id em options.cover_media_id. Ela não entra em media_ids.
PATCH /api/v1/posts/{id} posts:update
Alterar um post
Altera um post que ainda não saiu. Todos os campos são opcionais: o que não vier fica como está. Também aceita cover_media_id e os campos do Shorts do YouTube (title, privacy_status, category_id, tags, content_for_kids, notify_subscribers). Responde 200 com o post; post já publicado, publicando, com falha ou arquivado responde 409, com details.current_status.
Corpo da Requisição
| Campo | Tipo | Descrição |
|---|---|---|
| caption | string | Legenda deste post |
| media_ids | integer[] | Substitui as mídias, na ordem enviada |
| first_comment | string | Só Instagram |
| alt_text | string | Texto alternativo |
| schedule_at | datetime | Reagenda, com os mesmos mínimos da criação. Post em aprovação que recebe data vira pré-agendado |
| intent | string | draft ou send_to_review |
| review_group_id | integer | Grupo de aprovação, quando o post ainda não tem um |
| publish_only_if_approved | boolean | Escolha do pré-agendamento, quando o post ainda não era pré-agendado |
curl -X PATCH "https://flux.reportei.com/api/v1/posts/184931" \
-H "Authorization: Bearer $FLUX_TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{ "caption": "O pão na pedra sai às 7h, hoje com fermentação de 48h." }'
POST /api/v1/posts/group/{asset_group_id}/publish posts:update Idempotency-Key
Publicar posts de um grupo agora
O Publicar da tela: os posts escolhidos vão ao ar em instantes, seja qual for o estado: rascunho, em aprovação, pré-agendado, agendado ou com falha. Responde 200 com o grupo; o post aparece como scheduled até começar a sair.
Cabeçalhos
| Nome | Tipo | Descrição |
|---|---|---|
| Idempotency-Key | string | Opcional. Um valor único por operação (um uuid serve). Reenviar a mesma chave com o mesmo corpo devolve a resposta guardada, sem criar um segundo registro. Sem a chave, a requisição é atendida normalmente. Ver como funciona a idempotência |
Corpo da Requisição
| Campo | Tipo | Descrição |
|---|---|---|
| post_ids | integer[] | 1 a 20 posts do grupo |
curl -X POST "https://flux.reportei.com/api/v1/posts/group/71204/publish" \
-H "Authorization: Bearer $FLUX_TOKEN" \
-H "Idempotency-Key: 7d1c2e3f-4a5b-4c6d-8e9f-0a1b2c3d4e5f" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{ "post_ids": [184931, 184932] }'
Publicar agora passa por cima de tudo e não tem volta
POST /posts/group/{asset_group_id}/publish ignora a data marcada, a aprovação e a janela mínima de 120 minutos do pré-agendamento. Post que já saiu ou está saindo responde 409 com current_status, e post de outro grupo responde 404.
Contas conectadas
Lista as contas de rede social conectadas aos projetos da conta, com o que cada uma aceita. É o endpoint que permite detectar uma conta expirada antes de a publicação falhar, e montar posts[] sem adivinhar.
GET /api/v1/integrations integrations:read
Listar contas conectadas
As contas de rede social conectadas aos projetos que o token alcança, com a situação de cada conexão e o que cada uma aceita.
| Nome | Tipo | Descrição |
|---|---|---|
| project_id | integer | Restringe a um projeto |
| network | string | array | Filtra por rede. Aceita network=facebook ou network[]=facebook&network[]=instagram |
| status | string | active ou expired |
| per_page | integer | 1 a 50, padrão 15 |
| page | integer | Página, a partir de 1 |
curl -H "Authorization: Bearer $FLUX_TOKEN" \
-H "Accept: application/json" \
"https://flux.reportei.com/api/v1/integrations?project_id=3312&network=instagram_business"
O que cada conta aceita
| Campo | Descrição |
|---|---|
| supported_types | Tipos de peça que a conta publica (feed, story, reels…). O type de cada item de posts[] precisa estar aqui |
| limits | Por tipo: tamanho da legenda, quantidade, formato e proporção das mídias, opções obrigatórias e opções aceitas. Não vem nas contas listadas dentro de GET /projects |
Status da conta conectada
active
Conectada e válida
expired
A autorização caiu; a conta precisa ser reconectada no Flux
deleted
A conta foi desconectada do projeto. Só aparece dentro de um post publicado por ela
Conta desconectada sai da listagem
Uma conta desconectada do projeto não aparece em GET /integrations nem em GET /integrations/{id}/options (404): ela não é mais destino de publicação. Um post publicado por ela continua trazendo a conta no próprio corpo, com status deleted.
Reconexão da mesma conta no mesmo projeto faz o registro antigo voltar a valer: o registro expirado passa a responder active e não aparece mais em?status=expired. O filtro sempre concorda com o status que vem no corpo.
GET /api/v1/integrations/{id}/options integrations:read
Descobrir as opções de uma conta
Três campos obrigatórios dependem de valores que só a conta conectada conhece: o quadro do Pinterest, a privacidade que o TikTok libera e a privacidade e a categoria do YouTube. Os valores vêm da rede no momento da chamada e mudam. Consulte antes de criar, em vez de guardar. Rede sem campo próprio devolve options vazio; conta expirada responde 422.
Conta do TikTok traz também account_settings, o que o criador desativou nas configurações da rede:
"account_settings": {
"comment_disabled": false,
"duet_disabled": true,
"stitch_disabled": false,
"max_video_post_duration_sec": 600
}
curl -H "Authorization: Bearer $FLUX_TOKEN" \
-H "Accept: application/json" \
"https://flux.reportei.com/api/v1/integrations/88110/options"
POST /api/v1/integrations/{id}/pinterest-boards posts:create Idempotency-Key
Criar um quadro do Pinterest
Cria o quadro direto na conta do Pinterest, como o botão Criar quadro do compositor. Liste os quadros antes e ofereça as opções à pessoa: criar é para quando nenhum serve. O id devolvido vai em options.board_id. Nome igual ao de um quadro existente responde 409, com o quadro em error.details.board.
Cabeçalhos
| Nome | Tipo | Descrição |
|---|---|---|
| Idempotency-Key | string | Opcional. Um valor único por operação (um uuid serve). Reenviar a mesma chave com o mesmo corpo devolve a resposta guardada, sem criar um segundo registro. Sem a chave, a requisição é atendida normalmente. Ver como funciona a idempotência |
Corpo da Requisição
| Campo | Tipo | Descrição |
|---|---|---|
| name | string | Obrigatório, até 255 caracteres |
| privacy | string | PUBLIC (padrão) ou PROTECTED, o quadro secreto da tela |
curl -X POST "https://flux.reportei.com/api/v1/integrations/88107/pinterest-boards" \
-H "Authorization: Bearer $FLUX_TOKEN" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{ "name": "Vitrine", "privacy": "PUBLIC" }'
Aprovações
Grupos de aprovação são os pacotes de posts enviados de uma vez ao cliente. Cada post dentro deles acumula decisões de revisores, e esse histórico é auditoria: nada é removido dele.
GET /api/v1/posts/{id}/reviews reviews:read
Listar as decisões de aprovação de um post
Histórico das decisões de aprovação do post, em ordem cronológica. É auditoria: nada é removido dessa lista. Um post fora do alcance do token responde 404.
| Nome | Tipo | Descrição |
|---|---|---|
| per_page | integer | 1 a 50, padrão 15 |
| page | integer | Página, a partir de 1 |
curl -H "Authorization: Bearer $FLUX_TOKEN" \
-H "Accept: application/json" \
"https://flux.reportei.com/api/v1/posts/84/reviews"
Campos da decisão
| Campo | Descrição |
|---|---|
| reviewer | Quem decidiu. Apenas nome e e-mail. Nenhum outro dado do revisor é exposto |
| status | approved ou request_changes. Nunca pending: pendente é ausência de decisão |
| reasons | Motivos marcados no pedido de ajuste, quando houver |
| comments | Comentário livre do revisor |
| is_invalidated | true quando a decisão foi anulada por uma edição posterior do post |
| decided_at | Momento da decisão |
| created_at | Momento em que a decisão foi registrada |
GET /api/v1/review-groups reviews:read
Listar grupos de aprovação
Os pacotes de posts enviados de uma vez ao cliente. Os mais recentes vêm primeiro.
| Nome | Tipo | Descrição |
|---|---|---|
| project_id | integer | Restringe a um projeto |
| per_page | integer | 1 a 50, padrão 15 |
| page | integer | Página, a partir de 1 |
curl -H "Authorization: Bearer $FLUX_TOKEN" \
-H "Accept: application/json" \
"https://flux.reportei.com/api/v1/review-groups?project_id=1"
Campos do grupo de aprovação
| Campo | Descrição |
|---|---|
| posts_count | Todos os posts do grupo, em qualquer status |
| review_summary | Quantos posts ainda em revisão estão em cada situação |
| reviewers_count | Revisores atribuídos ao grupo |
review_summary pode somar menos que posts_count
review_summary cobre só os posts que ainda estão em in_review. Um post que já foi agendado ou publicado saiu da fila de aprovação e não entra na soma. A diferença é intencional: chamar de "pendente" um post já publicado seria pior que deixar a conta aberta.
GET /api/v1/review-groups/{id} reviews:read
Consultar um grupo de aprovação
O mesmo grupo da listagem e, junto, todos os posts do pacote. É o endpoint para abrir um grupo: saber o que foi enviado ao cliente e em que pé está cada post.
curl -H "Authorization: Bearer $FLUX_TOKEN" \
-H "Accept: application/json" \
"https://flux.reportei.com/api/v1/review-groups/419"
O grupo vem inteiro, sem paginação: um pacote é fechado quando é enviado ao cliente. A ordem é a do grupo, a mesma que o cliente vê na tela de aprovação, e é ela que dá sentido à numeração usada no feedback ("o terceiro post"). Post excluído não aparece e não conta em posts_count.
Registrar aprovações
Dois caminhos, para dois papéis: a decisão de um revisor sobre um post, e o Marcar como da tela, com que quem responde pelo conteúdo define o status da revisão de vários posts de um grupo.
POST /api/v1/posts/{id}/reviews reviews:create Idempotency-Key
Registrar uma decisão de aprovação
A decisão do dono do token, como revisor, sobre um post em ciclo de aprovação. Dispara a mesma notificação que a tela, e uma segunda decisão sua no mesmo ciclo substitui a primeira. Responde 201 com a decisão; post fora de ciclo de aprovação responde 409.
Cabeçalhos
| Nome | Tipo | Descrição |
|---|---|---|
| Idempotency-Key | string | Opcional. Um valor único por operação (um uuid serve). Reenviar a mesma chave com o mesmo corpo devolve a resposta guardada, sem criar um segundo registro. Sem a chave, a requisição é atendida normalmente. Ver como funciona a idempotência |
Corpo da Requisição
| Campo | Tipo | Descrição |
|---|---|---|
| status | string | approved ou request_changes |
| comments | string | Obrigatório quando status é request_changes |
| reasons | string[] | Opcional. Motivos do pedido de ajuste |
curl -X POST "https://flux.reportei.com/api/v1/posts/184931/reviews" \
-H "Authorization: Bearer $FLUX_TOKEN" \
-H "Idempotency-Key: 55f0e1a2-9b7c-4d8e-a1f2-3c4d5e6f7a8b" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{ "status": "request_changes", "comments": "Trocar a foto: a segunda está desfocada." }'
Quem assina é o dono do token
A decisão sai com o nome e o e-mail de quem criou o token. Não existe reviewer_email no corpo. Enviá-lo é recusado: aprovar em nome de outra pessoa seria falsificar a assinatura de quem responde pelo conteúdo.
POST /api/v1/posts/group/{asset_group_id}/review-status reviews:create Idempotency-Key
Marcar o status da revisão
O Marcar como da tela: define o status da revisão de posts de um grupo e abre um ciclo novo. Não é a decisão de um revisor. Vale para rascunho, post em aprovação e pré-agendado; agendado comum, post com falha e post que já saiu respondem 409. Responde 200 com o grupo.
Cabeçalhos
| Nome | Tipo | Descrição |
|---|---|---|
| Idempotency-Key | string | Opcional. Um valor único por operação (um uuid serve). Reenviar a mesma chave com o mesmo corpo devolve a resposta guardada, sem criar um segundo registro. Sem a chave, a requisição é atendida normalmente. Ver como funciona a idempotência |
Corpo da Requisição
| Campo | Tipo | Descrição |
|---|---|---|
| post_ids | integer[] | 1 a 20 posts do grupo |
| status | string | pending (Aguardando revisão), approved (Aprovado) ou request_changes (Pedido de ajuste) |
| comment | string | Opcional. Aparece no histórico do post |
curl -X POST "https://flux.reportei.com/api/v1/posts/group/71204/review-status" \
-H "Authorization: Bearer $FLUX_TOKEN" \
-H "Idempotency-Key: 1b2c3d4e-5f6a-4b7c-8d9e-0f1a2b3c4d5e" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{ "post_ids": [184931, 184932], "status": "approved", "comment": "Liberado pelo atendimento." }'
Como funciona a aprovação no Flux
Quatro regras explicam praticamente todas as dúvidas sobre os campos de aprovação.
1. Pendente é ausência de decisão, não um valor gravado
Uma decisão só existe como approved ou request_changes. "Pendente" quer dizer que o revisor ainda não respondeu: não há linha nenhuma em GET /posts/{id}/reviews para ele. Exemplo: post com 3 revisores atribuídos e nenhuma resposta devolve "data": [] no histórico.
"review": { "status": "pending", "reviewers_total": 3, "decided": 0, "pending": 3 }
2. "Pedido de mudança" tem precedência
Basta um revisor pedir ajustes para o post inteiro ficar em request_changes, mesmo que os outros já tenham aprovado. É a mesma regra que o Flux usa na tela.
3 revisores: um aprovou, um pediu ajustes, um não respondeu
"review": {
"status": "request_changes",
"reviewers_total": 3, "decided": 2, "approved": 1, "request_changes": 1, "pending": 1
}
Os 3 aprovaram
"review": {
"status": "approved",
"reviewers_total": 3, "decided": 3, "approved": 3, "request_changes": 0, "pending": 0
}
3. Um post pode voltar para aprovação quantas vezes for preciso
Depois de um pedido de ajustes, o post é corrigido e reenviado. Isso abre um ciclo novo. cycle_started_at marca o começo do ciclo corrente, e decisões anteriores a ele pertencem ao passado: continuam visíveis em GET /posts/{id}/reviews, mas não entram no agregado. Exemplo: aprovação em 01/09, reenvio em 05/09 e pedido de ajustes em 06/09, com 3 revisores.
"review": {
"status": "request_changes",
"cycle_started_at": "2026-09-05T09:00:00-03:00",
"reviewers_total": 3, "decided": 1, "approved": 0, "request_changes": 1, "pending": 2
}
A aprovação de 01/09 aparece no histórico, mas decided é 1: só a decisão do ciclo atual conta. Um post que nunca foi reenviado tem cycle_started_at null e considera todas as decisões válidas.
4. Decisão anulada aparece marcada, não desaparece
Editar um post já aprovado anula as aprovações: elas passam a valer como se não tivessem acontecido, e o post volta a esperar resposta. No histórico, essas decisões vêm com is_invalidated true; no agregado, não são contadas.
"data": [
{
"id": 55020,
"status": "approved",
"is_invalidated": true,
"decided_at": "2026-09-08T10:12:00-03:00"
}
]
Erros
Todo erro sai no mesmo envelope, com um código estável para tratamento programático e um identificador de requisição para o suporte.
{
"error": {
"type": "invalid_request",
"message": "Os parâmetros enviados são inválidos.",
"details": { "per_page": ["The per page field must not be greater than 50."] },
"request_id": "01M1EGMBW481B34NQKA1Z2MYKN"
}
}
| Campo | Descrição |
|---|---|
| type | Código estável, adequado para tratamento programático |
| message | Descrição legível. Pode mudar entre versões. Não use em condicional |
| details | Presente apenas em alguns erros, com os campos rejeitados |
| request_id | Também devolvido no header X-Request-Id. Informe-o ao suporte ao relatar um problema; é por ele que rastreamos a requisição |
Códigos HTTP
401 unauthorized
Token ausente, inválido, expirado ou revogado
403 insufficient_scope
Token válido, sem o escopo do endpoint. details.required_scope traz o escopo exigido
404 not_found
Recurso inexistente, excluído ou de outra conta
405 method_not_allowed
Método HTTP não suportado pelo endpoint
409 conflict
O estado do recurso não permite a operação (details.current_status traz o estado atual), ou uma requisição com a mesma Idempotency-Key ainda está em andamento
413 payload_too_large
Arquivo acima do teto do envio direto. A mensagem traz o limite e as saídas
422 invalid_request
Parâmetro inválido. details lista os campos
422 idempotency_key_reused
A mesma Idempotency-Key já foi usada com outro corpo. Gere uma chave nova
429 rate_limit_exceeded
Passou de 120 requisições ou de 20 escritas por minuto. Aguarde o que indica Retry-After
500 internal_error
Falha no Flux. Informe o request_id ao suporte
Por que 401 e 404 são propositalmente opacos
O 401 é idêntico para token ausente, inexistente, expirado e revogado: a API não confirma se um token existe. Pelo mesmo motivo, um recurso de outra conta responde 404 e nunca 403: a API não revela a existência de dados de terceiros.
Exemplos reais
401: token inválido
{
"error": {
"type": "unauthorized",
"message": "Token de acesso ausente ou inválido.",
"request_id": "01M1EGMBJ7JED66J067A9CBZF2"
}
}
403: token sem o escopo posts:read
{
"error": {
"type": "insufficient_scope",
"message": "Este token não possui o escopo necessário para esta operação.",
"details": { "required_scope": "posts:read" },
"request_id": "01M1EGN1165BP5NP8Z5B2X7M79"
}
}
404: post de outra conta
{
"error": {
"type": "not_found",
"message": "Recurso não encontrado.",
"request_id": "01M1EGMBPV0Q361CWZKH74W5X9"
}
}
422: rede inexistente no filtro network
{
"error": {
"type": "invalid_request",
"message": "Os parâmetros enviados são inválidos.",
"details": { "network.0": ["The selected network.0 is invalid."] },
"request_id": "01M1EGMC1DFAZ2TXZ1B5707WTA"
}
}
409: alterar um post já publicado
{
"error": {
"type": "conflict",
"message": "Este post está em \`published\` e não pode mais ser alterado pela API.",
"details": { "current_status": "published" },
"request_id": "01M1EH2Q9XK4N7B3T6V8Y0ZC5D"
}
}
Receita: o que está agendado e o que ainda não foi aprovado
O caso de uso mais comum da API, ponta a ponta. Não é preciso varrer todos os posts para acompanhar um mês: filtre por período e status, e siga links.next até o fim de cada listagem.
1
Descubra os projetos que o token alcança
A resposta é exatamente o que o seu token enxerga. Guarde os ids para usar como project_id.
curl -H "Authorization: Bearer $FLUX_TOKEN" \
"https://flux.reportei.com/api/v1/projects"
2
Liste os posts da semana que ainda esperam aprovação
Trocando review_status por request_changes você recebe os que voltaram com ajustes, e por approved os que já passaram e estão prontos para agendar.
curl -H "Authorization: Bearer $FLUX_TOKEN" \
"https://flux.reportei.com/api/v1/posts?project_id=1&status=in_review&review_status=pending&start_date=2026-09-07&end_date=2026-09-13"
3
Liste o que já está agendado no período
Mesma janela de datas, agora com status=scheduled: é a agenda confirmada do cliente.
curl -H "Authorization: Bearer $FLUX_TOKEN" \
"https://flux.reportei.com/api/v1/posts?project_id=1&status=scheduled&start_date=2026-09-07&end_date=2026-09-13"
4
Para um post travado, veja quem falta e o que foi pedido
O bloco review do primeiro diz quantos revisores faltam; o segundo diz o que cada um respondeu.
curl -H "Authorization: Bearer $FLUX_TOKEN" \
"https://flux.reportei.com/api/v1/posts/84"
curl -H "Authorization: Bearer $FLUX_TOKEN" \
"https://flux.reportei.com/api/v1/posts/84/reviews"
5
Antes de confiar no agendamento, confira as contas conectadas
Qualquer resultado aqui é uma publicação que vai falhar se a conta não for reconectada.
curl -H "Authorization: Bearer $FLUX_TOKEN" \
"https://flux.reportei.com/api/v1/integrations?status=expired"
Receita: da imagem ao post aprovado
Os quatro passos que uma automação de escrita faz, na ordem. Para agendar direto, troque o passo 3 por intent schedule com schedule_at.
1
Envie a imagem
Guarde o data.id da resposta: é o media_id. Se enviou por URL, confira o status antes de seguir.
curl -X POST "https://flux.reportei.com/api/v1/media" \
-H "Authorization: Bearer $FLUX_TOKEN" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Accept: application/json" \
-F "project_id=3312" \
-F "file=@pao-na-pedra.jpg"
2
Veja o que as contas aceitam
De cada conta você precisa do id e de um type que esteja em supported_types. Em Pinterest, TikTok e YouTube, chame também GET /integrations/{id}/options.
curl -H "Authorization: Bearer $FLUX_TOKEN" \
"https://flux.reportei.com/api/v1/integrations?project_id=3312"
3
Crie a peça e mande para aprovação
Um item em posts[] por conta. A resposta é o grupo de conteúdo, com os ids dos posts criados.
curl -X POST "https://flux.reportei.com/api/v1/posts" \
-H "Authorization: Bearer $FLUX_TOKEN" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"project_id": 3312,
"intent": "send_to_review",
"review_group_id": 4471,
"caption": "O pão na pedra sai às 7h.",
"media_ids": [998812],
"posts": [
{ "integration_id": 88104, "type": "feed" },
{ "integration_id": 88105, "type": "feed" }
]
}'
4
Registre a aprovação
Quando quem responde pelo token é quem aprova. Senão, o revisor decide pela tela ou pelo link de aprovação.
curl -X POST "https://flux.reportei.com/api/v1/posts/184931/reviews" \
-H "Authorization: Bearer $FLUX_TOKEN" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{ "status": "approved" }'
Boas práticas
Guarde o token em segredo
Ele dá acesso aos dados da conta e, com escopos de escrita, a criar e publicar conteúdo. Nunca o coloque em código versionado ou em aplicação client-side.
Baixe as mídias, não guarde as URLs
Elas expiram em 48 horas. Armazene o binário do seu lado.
Trate type, não message
As mensagens são texto para humanos e podem mudar entre versões.
Respeite o Retry-After
Ao receber 429, aguarde o intervalo indicado em vez de tentar de novo imediatamente.
Pagine sempre
Uma conta com muitos posts tem centenas de páginas. Siga links.next como ele vem, sem remontar a URL.
Filtre por data e status
Em vez de varrer tudo e filtrar do seu lado, é mais rápido e consome menos do seu limite.
Registre o request_id dos erros
É o que permite ao suporte investigar o que aconteceu naquela requisição.
Gere uma Idempotency-Key por operação
E reenvie a mesma chave ao repetir a chamada depois de um timeout. Chave nova para operação nova.
Confira o status da mídia
Antes de criar o post: mídia processing é recusada.
Consulte supported_types e limits
Em GET /integrations, antes de montar posts[]. É mais barato que descobrir o limite pelo 422.