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"

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.

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ê:
per_channeldá 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.formaté aplicado onde a rede suporta; caso contrário,SHORTouREELé resolvido por rede.youtube_titleeyoutube_privacysó afetam canais do YouTube.cta_urlgera um link curto e um conjunto de UTMs separados para cada conta, comutm_contentidentificando a conta. É sobre isso que se constrói a atribuição de leads por conta.stagger_secondsdefine 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.


