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.

Hosted MCP Server

npx add-mcp 'https://flux.reportei.com/mcp/v1'

Installs into Claude Code, Codex, Cursor and more

Documentation

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

  1. 1Na seção Chaves de acesso, clique em Criar chave. A tela de autorização do Reportei abre dentro do próprio Flux.
  2. 2Entre com a sua conta do Reportei, se ela pedir. O token nasce para a conta (company) que está aberta no Flux.
  3. 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.
  4. 4Autorize. O token aparece uma única vez, começando com flux_.
  5. 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.

EscopoNa tela de consentimentoConcede
projects:readVer os projetos da contaGET /projects, GET /projects/{id}
posts:readVer os posts e o calendárioGET /posts, GET /posts/{id}, GET /posts/group/{asset_group_id}
reviews:readVer as aprovações e os comentáriosGET /posts/{id}/reviews, GET /review-groups, GET /review-groups/{id}
integrations:readVer as contas conectadasGET /integrations, GET /integrations/{id}/options
media:write EscritaEnviar mídiasPOST /media, GET /media/{id}, /media/uploads/*
posts:create EscritaCriar postsPOST /posts, POST /integrations/{id}/pinterest-boards
posts:update EscritaAlterar postsPATCH /posts/{id}, POST /posts/group/{asset_group_id}/publish
reviews:create EscritaCriar aprovaçõesPOST /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. 1.Gere a chave uma vez por operação, antes da primeira tentativa. Um uuid v4 serve.
  2. 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. 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. 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.

NomeTipoDescrição
archivedboolean1 retorna somente os projetos arquivados
allboolean1 retorna ativos e arquivados juntos
per_pageinteger1 a 50, padrão 15
pageintegerPá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

NomeTipoDescrição
Idempotency-KeystringOpcional. 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

CampoTipoDescrição
project_idintegerObrigatório. Projeto dono da mídia
source_urlstringhttps apenas. Não pode vir junto de file
filefileEnvio multipart, até 40 MB. Acima disso, use source_url ou o envio em partes
descriptionstringOpcional, 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

NomeTipoDescrição
Idempotency-KeystringOpcional. 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

CampoTipoDescrição
project_idintegerObrigatório
file_namestringNome do arquivo, até 255 caracteres
sizeintegerTamanho total em bytes, até 300 MB
descriptionstringOpcional, 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.

NomeTipoDescrição
project_idintegerRestringe a um projeto. Um id fora do alcance do token responde 404
start_datedatePosts com schedule_at a partir desta data, inclusive (AAAA-MM-DD)
end_datedatePosts com schedule_at até esta data, inclusive. Precisa ser maior ou igual a start_date
statusstring | arrayUm ou mais status públicos. Aceita status=scheduled e status[]=scheduled&status[]=published
networkstring | arrayFiltra pela rede. Aceita valor único ou lista
network_groupstringFiltra pelo grupo de rede
typestring | arrayfeed, story, reels, shorts ou photo
review_statusstringpending, approved ou request_changes. Como só posts em revisão têm esse campo, o filtro restringe implicitamente a status=in_review
orderstringschedule_at (padrão) ou created_at
directionstringasc (padrão) ou desc
per_pageinteger1 a 50, padrão 15
pageintegerPá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

CampoDescrição
idIdentificador do post no Flux
asset_group_idGrupo de conteúdo do post: a mesma peça publicada em várias redes compartilha esse id
projectProjeto dono do post, com o fuso usado nas datas
networkRede de destino (network) e o grupo que reúne suas variações (network_group)
accountConta conectada onde o post será publicado; id é o identificador na rede
typefeed, story, reels, shorts ou photo
statusStatus público do post
review_statusSituação da aprovação, apenas quando status é in_review
captionLegenda 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_commentPrimeiro comentário programado (Instagram), quando houver
schedule_atData e hora do agendamento. null em post sem agendamento definido
published_urlURL do post na rede, preenchida após a publicação
mediaArquivos anexados, na ordem de publicação

Campos da mídia

CampoDescrição
idIdentificador do arquivo
typeimage, video ou pdf
urlURL temporária assinada: expira em 48h, não persista
url_expires_atMomento exato da expiração da URL
widthLargura em pixels, quando conhecida
heightAltura em pixels, quando conhecida
aspect_ratioProporçã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.

CampoDescrição
statusSituação agregada da aprovação. Sempre igual ao review_status do mesmo post
cycle_started_atInício do ciclo de aprovação corrente. null em post que nunca foi reenviado para revisão
reviewers_totalRevisores atribuídos ao post neste momento
decidedDecisões válidas no ciclo corrente, uma por revisor
approvedQuantas dessas decisões foram aprovações
request_changesQuantas dessas decisões pediram ajuste
pendingRevisores 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.

CampoDescrição
idIdentificador do grupo. É o asset_group_id que os posts carregam
projectProjeto dono do grupo, com o fuso usado nas datas
review_group_idGrupo de aprovação a que o lote pertence. null quando nunca foi enviado para revisão
posts_countPosts do grupo, um por rede
networksRedes alcançadas pelo lote, sem repetir
accountsContas conectadas onde o lote será publicado, sem repetir
status_summaryQuantos posts em cada status, só os status presentes, na ordem do ciclo de vida
schedule_datesDatas 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

NomeTipoDescrição
Idempotency-KeystringOpcional. 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

CampoTipoDescrição
project_idintegerObrigatório
intentstringdraft, schedule, publish_now ou send_to_review (ver abaixo)
captionstringLegenda da peça, herdada por todo post que não trouxer a sua
media_idsinteger[]Mídias já enviadas, na ordem. Herdadas por todo post que não trouxer as suas
titlestringOpcional, até 255 caracteres. Nome interno, nunca publicado
category_idsinteger[]Opcional. Categorias do mesmo projeto
schedule_atdatetimeISO-8601, lido no fuso do projeto. Obrigatório com intent schedule; com send_to_review, é o pré-agendamento
review_group_idintegerGrupo de aprovação que recebe a peça. Com send_to_review, informe este campo ou individual_approval
individual_approvalbooleantrue envia só esta peça para revisão, sem grupo, com um link de aprovação próprio
publish_only_if_approvedbooleanObrigatório no pré-agendamento, sem valor padrão: true só publica na data se aprovado; false publica mesmo sem aprovação
postsobject[]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

CampoDescrição
draftRascunho. Nada é publicado
scheduleAgenda para schedule_at. Na hora marcada o post vai ao ar sozinho, sem nova confirmação
publish_nowPublica 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_reviewEnvia para aprovação, num grupo (review_group_id) ou sozinha (individual_approval). Com schedule_at, vira pré-agendamento

Itens de posts[]

CampoDescrição
integration_idConta conectada de destino, do mesmo projeto (GET /integrations)
typeUm dos supported_types da conta
captionLegenda só desta conta, no lugar da legenda da peça
media_idsMídias só desta conta, no lugar das mídias da peça
optionsO 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

CampoTipoDescrição
captionstringLegenda deste post
media_idsinteger[]Substitui as mídias, na ordem enviada
first_commentstringSó Instagram
alt_textstringTexto alternativo
schedule_atdatetimeReagenda, com os mesmos mínimos da criação. Post em aprovação que recebe data vira pré-agendado
intentstringdraft ou send_to_review
review_group_idintegerGrupo de aprovação, quando o post ainda não tem um
publish_only_if_approvedbooleanEscolha 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

NomeTipoDescrição
Idempotency-KeystringOpcional. 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

CampoTipoDescrição
post_idsinteger[]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.

NomeTipoDescrição
project_idintegerRestringe a um projeto
networkstring | arrayFiltra por rede. Aceita network=facebook ou network[]=facebook&network[]=instagram
statusstringactive ou expired
per_pageinteger1 a 50, padrão 15
pageintegerPá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

CampoDescrição
supported_typesTipos de peça que a conta publica (feed, story, reels…). O type de cada item de posts[] precisa estar aqui
limitsPor 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

NomeTipoDescrição
Idempotency-KeystringOpcional. 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

CampoTipoDescrição
namestringObrigatório, até 255 caracteres
privacystringPUBLIC (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.

NomeTipoDescrição
per_pageinteger1 a 50, padrão 15
pageintegerPá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

CampoDescrição
reviewerQuem decidiu. Apenas nome e e-mail. Nenhum outro dado do revisor é exposto
statusapproved ou request_changes. Nunca pending: pendente é ausência de decisão
reasonsMotivos marcados no pedido de ajuste, quando houver
commentsComentário livre do revisor
is_invalidatedtrue quando a decisão foi anulada por uma edição posterior do post
decided_atMomento da decisão
created_atMomento 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.

NomeTipoDescrição
project_idintegerRestringe a um projeto
per_pageinteger1 a 50, padrão 15
pageintegerPá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

CampoDescrição
posts_countTodos os posts do grupo, em qualquer status
review_summaryQuantos posts ainda em revisão estão em cada situação
reviewers_countRevisores 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

NomeTipoDescrição
Idempotency-KeystringOpcional. 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

CampoTipoDescrição
statusstringapproved ou request_changes
commentsstringObrigatório quando status é request_changes
reasonsstring[]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

NomeTipoDescrição
Idempotency-KeystringOpcional. 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

CampoTipoDescrição
post_idsinteger[]1 a 20 posts do grupo
statusstringpending (Aguardando revisão), approved (Aprovado) ou request_changes (Pedido de ajuste)
commentstringOpcional. 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"
  }
}
CampoDescrição
typeCódigo estável, adequado para tratamento programático
messageDescrição legível. Pode mudar entre versões. Não use em condicional
detailsPresente apenas em alguns erros, com os campos rejeitados
request_idTambé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.