Guia rápido da API REST do Shager: de uma chave nova a um post rastreável em 40 contas, em sete chamadas

Um tour prático pela API REST do Shager em curl e TypeScript: autenticação, workspaces, canais, mídia, rascunhos por conta, agendamento, status e cliques.

A API REST do Shager fica em https://app.shager.ai/api/v1, autentica com Authorization: Bearer shgr_live_..., devolve todo resultado como { "data": ... } e todo erro como { "error": { "code", "message" } }. Uma execução completa de distribuição são sete chamadas: conferir a chave, escolher um workspace, listar os canais, enviar a mídia, criar um rascunho com legendas por conta, agendar e depois ler o status e os cliques. A especificação legível por máquina é o documento OpenAPI 3.1.

Tudo o que está abaixo roda do jeito que está escrito, assim que você define duas variáveis de ambiente. As mesmas operações existem como ferramentas MCP com os mesmos nomes, então o que você aprende aqui vale também para Claude Code, Codex ou Cursor.

Do que você precisa antes da primeira chamada?

De uma chave. Ou uma pessoa cria uma em https://app.shager.ai/dashboard/agents com os escopos de que você precisa, ou o seu agente cria um ambiente de teste pelo cadastro feito pelo próprio agente. Os escopos funcionam assim:

Escopo Permite
read whoami, listar workspaces, canais, grupos e posts, ler um post, analytics
write Criar workspaces, grupos, mídias, rascunhos de posts, links de conexão, pedidos de aprovação, cancelar
publish Agendar, incluindo create_post com schedule_at
export SHAGER_API_KEY="shgr_live_your_key_here"
export API="https://app.shager.ai/api/v1"
Uma requisição curl que cria um post com a API REST do Shager: legenda, grupo de contas, link rastreável e horário de publicação.
As mesmas operações do servidor MCP, documentadas em OpenAPI.

Chamada 1: quem sou eu?

curl -s "$API/me" -H "Authorization: Bearer $SHAGER_API_KEY"
{ "data": { "organization_id": "...", "organization": "Northwind Agency", "sandbox": false, "scopes": ["read", "write"] } }

Se sandbox for true, o agendamento e os links de conexão ficam bloqueados até uma pessoa assumir a chave. Se publish não estiver em scopes, você consegue montar rascunhos, mas não agendá-los. Saber disso logo de cara evita um 403 confuso mais tarde.

Chamada 2: escolha ou crie um workspace

Um workspace costuma ser um cliente ou uma marca.

curl -s "$API/workspaces" -H "Authorization: Bearer $SHAGER_API_KEY"

curl -s -X POST "$API/workspaces" \
  -H "Authorization: Bearer $SHAGER_API_KEY" -H "Content-Type: application/json" \
  -d '{"name": "Summit Physio", "timezone": "Europe/London", "approval_required": true}'

Sempre defina o timezone (um nome IANA) na criação. Os horários de agendamento são guardados com o offset, e o fuso do workspace é como o Shager os mostra para as pessoas. approval_required: true significa que os posts precisam ser aprovados pelo cliente antes de serem agendados, um bom padrão para clientes novos.

Exporte o id da resposta para que os próximos comandos funcionem:

export WS="the_workspace_id"

Chamada 3: liste canais e grupos

curl -s "$API/workspaces/$WS/channels" -H "Authorization: Bearer $SHAGER_API_KEY"
curl -s "$API/workspaces/$WS/groups" -H "Authorization: Bearer $SHAGER_API_KEY"

Cada canal volta com id, network, name, handle, status, os formats que ele suporta e connected_by_client. Os grupos devolvem id, name e channel_ids. Grupos são a forma de falar com quarenta contas sem listar quarenta ids: passe group_ids para create_post e todos os canais ativos do grupo entram.

Se o workspace ainda não tem canais, crie um link de conexão com POST /workspaces/{workspace_id}/connect-links e envie para o dono da conta. Ele mesmo conecta Facebook, Instagram, YouTube, X, LinkedIn ou TikTok, sem login no Shager.

Diagrama: briefing, rascunho por conta, aprovação do cliente, publicação escalonada e relatório de cliques por conta.
Cinco etapas fixas. A aprovação de cada post é opcional por cliente; para publicar, é preciso uma pessoa como dona e uma permissão de publicação separada na chave.

Chamada 4: envie a mídia a partir de uma URL

curl -s -X POST "$API/workspaces/$WS/media" \
  -H "Authorization: Bearer $SHAGER_API_KEY" -H "Content-Type: application/json" \
  -d '{
    "url": "https://cdn.summitphysio.example/video/knee-mobility.mp4",
    "file_name": "knee-mobility.mp4",
    "width": 1080, "height": 1920, "duration_ms": 42000
  }'

O Shager baixa o arquivo no servidor e devolve id, kind, mime_type e size_bytes. Para Reels, Shorts e stories, passe width, height e duration_ms quando souber esses valores. Assim o Shager confere as regras de formato de cada rede antes de o post ser agendado, em vez de falhar na hora do envio.

Chamada 5: crie um rascunho com legendas por conta

Esta é a chamada que importa. Aqui está em TypeScript com fetch puro, incluindo uma pequena função auxiliar que você vai reaproveitar:

const API = "https://app.shager.ai/api/v1";

async function shager<T>(method: string, path: string, body?: unknown): Promise<T> {
  const res = await fetch(`${API}${path}`, {
    method,
    headers: {
      Authorization: `Bearer ${process.env.SHAGER_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: body ? JSON.stringify(body) : undefined,
  });
  const json = await res.json();
  if (!res.ok) {
    const err = new Error(`${res.status} ${json.error.code}: ${json.error.message}`);
    (err as any).status = res.status;
    throw err;
  }
  return json.data as T;
}

const WS = process.env.SHAGER_WORKSPACE_ID!;
const mediaId = process.env.SHAGER_MEDIA_ID!; // the id returned by call 4
const channels = await shager<Array<{ id: string; name: string; network: string; status: string }>>(
  "GET", `/workspaces/${WS}/channels`,
);

const post = await shager<{ id: string; status: string }>("POST", `/workspaces/${WS}/posts`, {
  label: "Knee mobility, week 42",
  caption: "Three minutes a day for stiffer knees. Full routine in the video.",
  channel_ids: channels.map((c) => c.id),
  media_ids: [mediaId],
  format: "REEL",
  youtube_title: "3-minute knee mobility routine",
  youtube_privacy: "public",
  per_channel: channels.map((c) => ({
    channel_id: c.id,
    caption: `${c.name}: three minutes a day for stiffer knees. Our physios show the routine.`,
  })),
  cta_url: "https://summitphysio.example/book",
  cta_text: "Book an assessment",
  campaign: "knee-mobility-oct",
  first_comment: "Book an assessment: https://summitphysio.example/book",
  stagger_seconds: [45, 120],
});

console.log(post.id, post.status); // DRAFT

O que cada campo traz para você:

  1. per_channel dá a cada conta a própria legenda. Na prática, quem escreve essas legendas é um agente; o template acima ocupa o lugar dessa etapa, e o raciocínio está em como evitar bloqueios por spam em escala.
  2. format é aplicado onde a rede suporta; caso contrário, SHORT ou REEL é resolvido por rede. youtube_title e youtube_privacy só afetam canais do YouTube.
  3. cta_url gera um link curto e um conjunto de UTMs separados para cada conta, com utm_content identificando a conta. É sobre isso que se constrói a atribuição de leads por conta.
  4. stagger_seconds define uma pausa aleatória entre contas da mesma rede. O padrão é [30, 90].

Sem schedule_at, o resultado é um rascunho. Guarde o id para as próximas chamadas com export POST_ID="the_post_id".

Chamada 6: aprovação ou agendamento

Se o workspace exige aprovação, envie para o cliente. A resposta inclui uma approval_url que o revisor abre sem fazer login:

curl -s -X POST "$API/workspaces/$WS/posts/$POST_ID/approval" \
  -H "Authorization: Bearer $SHAGER_API_KEY" -H "Content-Type: application/json" \
  -d '{"reviewer_name": "Dana Ellis", "reviewer_email": "dana@summitphysio.example", "send_email": true}'

Depois de aprovado (ou se a aprovação não for exigida), agende. Isso exige o escopo publish, e schedule_at precisa estar em ISO 8601 com offset:

curl -s -X POST "$API/workspaces/$WS/posts/$POST_ID/schedule" \
  -H "Authorization: Bearer $SHAGER_API_KEY" -H "Content-Type: application/json" \
  -d '{"schedule_at": "2026-10-20T08:30:00+01:00"}'

Nesse momento, o Shager valida cada destino contra as regras da rede. Se alguma conta fosse rejeitar o post, você recebe um 422 rejected com o motivo, e nada entra na fila.

Chamada 7: confira o status e os cliques

curl -s "$API/workspaces/$WS/posts/$POST_ID" -H "Authorization: Bearer $SHAGER_API_KEY"
curl -s "$API/workspaces/$WS/posts?status=SCHEDULED&limit=50" -H "Authorization: Bearer $SHAGER_API_KEY"
curl -s "$API/workspaces/$WS/analytics?from=2026-10-01T00:00:00Z&to=2026-10-31T23:59:59Z" \
  -H "Authorization: Bearer $SHAGER_API_KEY"

get_post devolve uma linha por destino com state, dispatch_at, published_at, a url publicada e qualquer error. O analytics devolve total_clicks, by_account e by_post, contando os cliques nos links rastreáveis do Shager, sem o tráfego de bots. Para cancelar um post agendado que ainda não começou a ser publicado, use POST /workspaces/{workspace_id}/posts/{post_id}/cancel.

Quais erros o seu código deve tratar?

Status e código Significado O que fazer
401 unauthorized Cabeçalho ausente ou malformado Envie Authorization: Bearer shgr_...
403 forbidden A chave não tem o escopo necessário Crie um rascunho, ou peça publish a uma pessoa
403 sandbox_unclaimed Chave de cadastro do agente ainda não assumida Mostre o link de transferência a uma pessoa
404 not_found Id de workspace, post ou canal errado Liste de novo; os ids são por workspace
409 not_scheduled Cancelamento de um post que não está agendado Leia o status do post antes
422 rejected Uma regra da rede falhou Mostre a mensagem; ela diz qual é o problema
429 rate_limited Mais de 120 requisições por minuto por chave Espere um pouco e tente de novo

O limite de requisições raramente incomoda um cliente bem projetado. Um único create_post cobre centenas de contas, então você não deveria precisar de uma chamada por conta.

Perguntas frequentes

Existe um SDK?

Não um dedicado. O documento OpenAPI 3.1 funciona com os geradores padrão, se você quiser clientes tipados, e a API é pequena o bastante para que uma função auxiliar como a de cima costume ser tudo de que você precisa. Uma CLI do Shager está a caminho.

REST e MCP são mesmo a mesma coisa?

Sim. Cada ferramenta MCP corresponde a uma operação REST com o mesmo nome, as mesmas entradas, os mesmos escopos, o mesmo limite de requisições e o mesmo registro de auditoria. Use REST em scripts e serviços, e MCP em clientes de agentes. A lista completa de ferramentas está na página para agentes.

Como publicar textos diferentes no Facebook e no YouTube no mesmo post?

Use per_channel com o id e a legenda de cada canal, e youtube_title para o título do YouTube. Um objeto de post, muitos destinos, cada um com a própria legenda, o próprio formato e, se precisar, o próprio primeiro comentário.

Próximo passo

Quando essa sequência rodar sem problemas à mão, transforme-a em algo que um agente possa repetir. Como criar uma skill do Claude para o Shager mostra como empacotar essas chamadas, e as regras em volta delas, numa skill reutilizável.

Experimente nas suas próprias contas.

Grátis durante o lançamento, sem cartão. Conecte, escreva uma vez, e o Shager publica e mede.