Pular para o conteúdo

Guia do desenvolvedor

Envie publicações para o Amaposta a partir do seu próprio fluxo de conteúdo: envie arquivos de mídia, crie uma publicação para todos os canais, agende-a e receba a confirmação quando ela for publicada.

Autenticação

Crie uma chave de API no painel em Configurações, API e webhooks. As chaves começam por ss_live_, pertencem a um espaço de trabalho e podem ser limitadas a determinados projetos. Envie a chave como token bearer em cada requisição:

Verificar uma chave
curl https://www.amaposta.com/api/v1/me \
  -H "Authorization: Bearer ss_live_…"

A resposta indica o nome da chave, as suas permissões e o espaço de trabalho. Cada chave tem uma ou mais permissões:

EscopoPermite
content:readLer projetos, canais, publicações e arquivos de mídia.
content:writeEnviar arquivos de mídia e criar ou editar publicações.
posts:publishAgendar e publicar sem revisão. Sem esta permissão, as publicações vão para a caixa de revisão nos projetos com aprovações e mantêm-se como rascunhos nos restantes.

Cada chave pode fazer 120 requisições por minuto. Acima desse limite, você recebe 429 com o código rate_limited; espere um momento e tente novamente.

Projetos e canais

As publicações pertencem a um projeto. Liste os projetos que sua chave pode acessar e depois os canais de um deles. Você precisará do ID de um canal para selecioná-lo ou personalizar seu texto.

Listar projetos e canais
curl https://www.amaposta.com/api/v1/projects \
  -H "Authorization: Bearer $AMAPOSTA_KEY"

curl https://www.amaposta.com/api/v1/projects/$PROJECT_ID/channels \
  -H "Authorization: Bearer $AMAPOSTA_KEY"

Um canal tem um provider (youtube, instagram, tiktok, x, facebook, custom ou sandbox), um status (active, expiring, needs_reconnect, error ou disabled) e os tipos de publicação que supports.

Enviar arquivos de mídia

As imagens e os vídeos são enviados uma vez por projeto e podem ser usados em qualquer número de publicações. Há três formas de os adicionar.

Envio direto

Envie o arquivo como dados de formulário multipart em um campo chamado file. Ideal para arquivos até algumas centenas de MB.

POST /api/v1/projects/{project_id}/media
curl https://www.amaposta.com/api/v1/projects/$PROJECT_ID/media \
  -H "Authorization: Bearer $AMAPOSTA_KEY" \
  -F "[email protected]"

Envio pré-assinado para arquivos grandes

Solicite uma URL de envio, envie os bytes diretamente para o armazenamento com PUT e informe ao Amaposta que terminou.

Três requisições
# 1. Ask for an upload URL. The response is {"media": { … }, "upload_url": "…"}
curl https://www.amaposta.com/api/v1/projects/$PROJECT_ID/media/uploads \
  -H "Authorization: Bearer $AMAPOSTA_KEY" \
  -H "Content-Type: application/json" \
  -d '{"filename": "batch-142.mp4", "content_type": "video/mp4", "size_bytes": 48213844}'

# 2. Upload the bytes to upload_url
curl -X PUT "$UPLOAD_URL" \
  -H "Content-Type: video/mp4" \
  --upload-file batch-142.mp4

# 3. Finish the upload
curl -X POST https://www.amaposta.com/api/v1/media/$MEDIA_ID/complete \
  -H "Authorization: Bearer $AMAPOSTA_KEY"

Importar de uma URL

Forneça uma URL pública ao Amaposta para baixar o arquivo em segundo plano. Você também pode pular esta etapa e passar media_url ao criar a publicação.

POST /api/v1/projects/{project_id}/media/import
curl https://www.amaposta.com/api/v1/projects/$PROJECT_ID/media/import \
  -H "Authorization: Bearer $AMAPOSTA_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://cdn.example.com/batch-142.mp4"}'

Cada envio retorna um objeto de mídia. Seu status passa de pending para processing e depois para ready (ou failed, com um error). Após o processamento, ele inclui width, height, duration_ms e uma miniatura. Consulte periodicamente GET /api/v1/media/{id} ou aguarde o webhook media.ready. A url retornada é assinada e válida por 12 horas.

Criar uma publicação

POST /api/v1/projects/{project_id}/posts cria uma publicação com uma entrega por canal. Amaposta adapta-a a cada plataforma: os títulos só são enviados quando existe um campo de título, as hashtags tornam-se tags no YouTube e texto integrado nas restantes.

Criar uma publicação de vídeo e adicioná-la à fila
curl https://www.amaposta.com/api/v1/projects/$PROJECT_ID/posts \
  -H "Authorization: Bearer $AMAPOSTA_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: episode-142" \
  -d @- <<'JSON'
{
  "kind": "video",
  "title": "How we roast a batch in 12 minutes",
  "description": "From green beans to first crack. We filmed one batch start to finish.",
  "hashtags": ["coffee", "behindthescenes"],
  "media_url": "https://cdn.example.com/batch-142.mp4",
  "cover_url": "https://cdn.example.com/batch-142-cover.jpg",
  "overrides": {
    "<x-channel-id>": {
      "description": "Batch 142 is out: green beans to first crack in 12 minutes."
    },
    "<youtube-channel-id>": {
      "options": { "privacy": "unlisted" }
    }
  },
  "schedule": { "mode": "queue" },
  "external_ref": "episode-142",
  "metadata": {
    "pipeline": { "name": "nightly-cut", "run": "2026-10-17" }
  }
}
JSON

Campos

CampoO que faz
kindtext, image ou video. Obrigatório.
titleUsado pelas plataformas com um campo de título: YouTube, publicações de fotos do TikTok, vídeos do Facebook.
descriptionA legenda, a descrição ou o texto da publicação. Também aceito como body, caption ou text.
hashtagsUma lista, com ou sem #.
media_id, media_urlUm ID de arquivo de mídia enviado ou uma URL pública de onde o Amaposta baixa o arquivo para você. Necessário para publicações de imagem e vídeo.
cover_media_id, cover_urlUma imagem de capa para vídeos, quando a plataforma o permite.
channelsIDs dos canais onde publicar. Omita-os para usar todos os canais ativos do projeto que suportam este tipo de publicação.
overridesAlterações por canal, indexadas pelo ID do canal: title, description, hashtags e options da plataforma, como privacy do YouTube.
schedulemode é at (com um at em ISO 8601), now ou queue para o próximo horário livre de publicação. Omita-o para criar um rascunho.
external_refA sua própria referência, devolvida na publicação e nas entregas de API personalizada.
metadataJSON de formato livre salvo com a publicação. Inclua "pipeline" para identificar conteúdo gerado; o painel apresenta-o e os webhooks indicam a origem como pipeline.

A resposta é a publicação, incluindo uma entrada em deliveries por canal.

Novas tentativas seguras

As redes perdem requisições. Envie um cabeçalho Idempotency-Key ao criar uma publicação e uma nova tentativa com a mesma chave devolve a publicação da primeira tentativa em vez de criar outra. Use um valor estável do seu lado, como um ID de tarefa ou episódio. As chaves são truncadas a 200 caracteres.

Agendar e publicar

Agende um rascunho, publique-o agora, adicione-o à fila ou retire-o do calendário com POST /api/v1/posts/{post_id}/schedule.

Agendar para uma hora
curl https://www.amaposta.com/api/v1/posts/$POST_ID/schedule \
  -H "Authorization: Bearer $AMAPOSTA_KEY" \
  -H "Content-Type: application/json" \
  -d '{"mode": "at", "at": "2026-10-20T07:00:00Z"}'
  • atPublica no horário indicado, com até dois anos de antecedência.
  • nowPublica imediatamente.
  • queueUsa o próximo horário de publicação livre para os canais da publicação nas próximas 12 semanas.
  • unscheduleMove a publicação de volta para os rascunhos.

Antes de qualquer agendamento, são executadas as mesmas verificações do editor. Se alguma falhar, a requisição retorna 400 com uma mensagem como Corrija isto antes de agendar: o YouTube precisa de um título. O agendamento exige a permissão posts:publish ou um projeto com aprovações ativadas; nesse caso, a publicação aguarda na caixa de revisão.

Ler publicações e entregas

Liste as publicações de um projeto, filtradas por status (status separados por vírgulas ou inbox, queue ou history), um intervalo from/to, limit e offset. A resposta é {"items": […], "total": n}.

O que vem a seguir e uma publicação em detalhe
curl "https://www.amaposta.com/api/v1/projects/$PROJECT_ID/posts?status=queue" \
  -H "Authorization: Bearer $AMAPOSTA_KEY"

curl https://www.amaposta.com/api/v1/posts/$POST_ID \
  -H "Authorization: Bearer $AMAPOSTA_KEY"

Uma publicação tem um status global (draft, in_review, changes_requested, ready, scheduled, publishing, published, partial ou failed) e uma entrega por canal:

deliveries[]
"deliveries": [
  {
    "id": "0192b7d4-…",
    "channel_id": "0192b7a1-…",
    "status": "published",
    "url": "https://www.youtube.com/watch?v=…",
    "error": null,
    "published_at": "2026-10-20T07:00:41Z"
  },
  {
    "id": "0192b7d4-…",
    "channel_id": "0192b7a9-…",
    "status": "failed",
    "url": null,
    "error": {
      "code": "endpoint_unavailable",
      "message": "Your endpoint returned 503 Service Unavailable",
      "hint": "Amaposta will retry with backoff."
    },
    "published_at": null
  }
]

Os estados de entrega são pending, scheduled, publishing, processing, published, failed e cancelled. DELETE /api/v1/posts/{post_id} remove uma publicação.

Erros

Todos os erros têm a mesma estrutura: um objeto error com um code estável, uma message que você pode mostrar às pessoas e, por vezes, fields (mensagens por campo) e uma hint.

422 Unprocessable Entity
{
  "error": {
    "code": "validation",
    "message": "Please fix the highlighted fields.",
    "fields": {
      "kind": "Use text, image or video."
    }
  }
}
StatusCódigoSignificado
400bad_requestA requisição não pode ser executada como solicitada, como no caso de agendar uma publicação que não passa nas verificações.
401unauthorizedA chave de API está em falta, incorreta ou revogada.
402plan_limitO plano do espaço de trabalho não permite isto; limit indica o limite.
403forbiddenFalta à chave uma permissão ou acesso ao projeto.
404not_foundEsse projeto, publicação, arquivo de mídia ou endpoint não existe.
409conflictA alteração entra em conflito com o estado atual, como editar uma publicação que já está sendo publicada.
422validationUm ou mais campos precisam de correção; consulte fields.
429rate_limitedMais de 120 requisições por minuto com esta chave.
502provider_errorUma plataforma recusou ou falhou; hint indica o que fazer.

Webhooks

Adicione um endpoint em Configurações, API e webhooks, escolha os eventos e copie o segredo de assinatura. Amaposta envia JSON por POST para sua URL para cada evento. Qualquer resposta diferente de 2xx ou a ausência de resposta em 15 segundos origina novas tentativas com intervalos crescentes; os endpoints que continuam a falhar são desativados com um aviso aos administradores.

EventoEnviado quando
post.createdUma publicação foi criada (painel ou API)
post.scheduledUma publicação foi agendada
post.approvedUma publicação foi aprovada
post.publishedUma publicação ficou disponível em um canal
post.failedUma publicação falhou em um canal
channel.connectedUm canal foi conectado ou reconectado
channel.disconnectedUm canal perdeu a conexão
media.readyO processamento de um envio terminou
media.failedNão foi possível processar um envio
post.published
POST /your/webhook HTTP/1.1
Content-Type: application/json
User-Agent: Amaposta-Webhooks/1.0
X-Amaposta-Event: post.published
X-Amaposta-Event-Id: 0192b7e0-…
X-Amaposta-Signature: t=1792479641,v1=5f2b0c…

{
  "id": "0192b7e0-…",
  "type": "post.published",
  "created_at": "2026-10-20T07:00:41Z",
  "project_id": "0192a3f1-…",
  "data": {
    "post_id": "0192b7c8-…",
    "delivery_id": "0192b7d4-…",
    "channel_id": "0192b7a1-…",
    "provider": "youtube",
    "external_id": "…",
    "url": "https://www.youtube.com/watch?v=…"
  }
}

Verificar a assinatura

X-Amaposta-Signature é t=<unix seconds>,v1=<hex>, em que v1 é HMAC_SHA256(secret, t + "." + body) calculado sobre o corpo bruto da requisição. Calcule-o, compare em tempo constante e rejeite timestamps antigos para impedir reenvios maliciosos.

Node.js
import crypto from "node:crypto";

// rawBody: the request body exactly as received (string or Buffer).
export function verifySignature(rawBody, header, secret, toleranceSeconds = 300) {
  const parts = Object.fromEntries(header.split(",").map((p) => p.split("=", 2)));
  const t = Number(parts.t);
  if (!t || Math.abs(Date.now() / 1000 - t) > toleranceSeconds) return false;
  const expected = crypto
    .createHmac("sha256", secret)
    .update(`${t}.${rawBody}`)
    .digest();
  const given = Buffer.from(parts.v1 ?? "", "hex");
  return given.length === expected.length && crypto.timingSafeEqual(given, expected);
}
Python
import hashlib
import hmac
import time


def verify_signature(raw_body: bytes, header: str, secret: str, tolerance: int = 300) -> bool:
    parts = dict(p.split("=", 1) for p in header.split(","))
    t = int(parts.get("t", "0"))
    if abs(time.time() - t) > tolerance:
        return False
    expected = hmac.new(secret.encode(), f"{t}.".encode() + raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, parts.get("v1", ""))

Canais de API personalizada

Um canal de API personalizada publica em um endpoint HTTPS que você gerencia: seu CMS, uma ferramenta de newsletters, uma plataforma que Amaposta ainda não abrange. Aparece no calendário e tem verificações, aprovações e novas tentativas como qualquer outro canal. Quando uma publicação sai, Amaposta envia um POST por entrega:

O que seu endpoint recebe
POST /amaposta/publish HTTP/1.1
Authorization: Bearer <your API key>
Content-Type: application/json
Idempotency-Key: 0192b7d4-…
X-Amaposta-Delivery: 0192b7d4-…
X-Amaposta-Signature: t=1792479600,v1=9ac41e…

{
  "id": "0192b7d4-…",
  "type": "post.publish",
  "created_at": "2026-10-20T07:00:00Z",
  "content": {
    "kind": "video",
    "title": "How we roast a batch in 12 minutes",
    "text": "From green beans to first crack. We filmed one batch start to finish.",
    "hashtags": ["coffee", "behindthescenes"],
    "media": {
      "url": "https://…",
      "content_type": "video/mp4",
      "size_bytes": 48213844,
      "width": 1080,
      "height": 1920,
      "duration_ms": 58000,
      "filename": "batch-142.mp4"
    },
    "cover": null,
    "options": {}
  },
  "post": {
    "id": "0192b7c8-…",
    "external_ref": "episode-142",
    "scheduled_at": "2026-10-20T07:00:00Z",
    "metadata": {
      "pipeline": { "name": "nightly-cut" }
    }
  },
  "project": { "id": "0192a3f1-…", "name": "Spring launch" },
  "channel": { "id": "0192b7a9-…", "name": "api.example.com" }
}

Como responder

  • 2xxPublicada. Você pode devolver {"id": "…", "url": "…"} e o link aparece na publicação.
  • 401, 403A chave foi rejeitada. O canal é marcado para reconexão e os administradores são avisados. Não use estes códigos para uma assinatura inválida.
  • 5xx, 408, 429Temporário. Amaposta tenta novamente com intervalos crescentes.
  • Outros 4xxA publicação é marcada com falha e mostra sua mensagem, para que alguém possa corrigi-la e clicar em Tentar novamente.
Um receptor em Express
app.post("/amaposta/publish", express.raw({ type: "application/json" }), async (req, res) => {
  const signature = req.get("X-Amaposta-Signature") ?? "";
  if (!verifySignature(req.body, signature, process.env.AMAPOSTA_SIGNING_SECRET)) {
    return res.status(400).json({ message: "Bad signature" });
  }
  const delivery = JSON.parse(req.body);
  const item = await publishToYourSystem(delivery.content, req.get("Idempotency-Key"));
  res.json({ id: item.id, url: item.url });
});

Seu endpoint precisa estar acessível pela internet; os redirecionamentos não são seguidos. Quando você conecta o canal, o Amaposta faz uma verificação com GET na URL de verificação de funcionamento, se você definir uma, ou com uma requisição OPTIONS para o endpoint.

Canais Sandbox

Um canal Sandbox comporta-se como um canal real, mas nada sai de Amaposta. Use-o para criar e testar sua integração de ponta a ponta: as publicações são agendadas, entram no ar, são publicadas ou falham e acionam os mesmos webhooks. Os canais Sandbox são gratuitos em todos os planos e não contam para os limites de canais.

Escolha como se comporta ao adicioná-lo:

  • Sempre funcionarTodas as publicações são publicadas.
  • Falhar de vez em quandoVeja as falhas e as novas tentativas sem esperar por uma interrupção real.
  • Sempre falharTeste seu tratamento de post.failed.
  • Conexão expiradaVeja os alertas e os links para restabelecer o acesso quando este expira.

Regras da plataforma

O que cada tipo de canal aceita. As verificações usam os mesmos limites, para a maioria dos problemas surgir antes do agendamento da publicação e não quando é publicada.

Plataforma Publicação Título Texto Hashtags Mídia
YouTube Vídeo TítuloObrigatório, até 100 caracteres DescriçãoAté 5.000 caracteres Enviadas como tags, até 60 MP4, MOV, WebM, AVI, MKV; até 256 GB; 1 s a 12 h
As contas sem número de telefone verificado podem enviar até 15 minutos e não podem definir miniaturas personalizadas. Cada envio consome cota da API; a cota padrão do Google permite cerca de seis envios por dia por aplicativo.
Instagram Imagem Sem título LegendaAté 2.200 caracteres Adicionadas ao texto, até 30 JPEG; até 8 MB
Vídeo Sem título LegendaAté 2.200 caracteres Adicionadas ao texto, até 30 MP4, MOV; até 300 MB; 3 s a 15 min
Exige uma conta Instagram Business ou Creator. O Instagram permite 50 publicações pela API por conta em cada período móvel de 24 horas. Não são possíveis publicações apenas de texto no Instagram.
TikTok Imagem TítuloAté 90 caracteres DescriçãoAté 4.000 caracteres Adicionadas ao texto JPEG, WebP; até 20 MB
Vídeo Sem título LegendaAté 2.200 caracteres Adicionadas ao texto MP4, MOV, WebM; até 4 GB; 3 s a 10 min
As publicações de aplicativos que não concluíram a auditoria do TikTok só são visíveis para o criador. O TikTok escolhe a capa a partir de um quadro do vídeo; não são suportadas imagens de capa personalizadas. Não são possíveis publicações apenas de texto no TikTok.
X Texto Sem título PublicaçãoObrigatório, até 280 (os links contam como 23, os emojis como 2) Adicionadas ao texto Nenhum
Imagem Sem título PublicaçãoAté 280 (os links contam como 23, os emojis como 2) Adicionadas ao texto JPEG, PNG, WebP, GIF; até 5 MB
Vídeo Sem título PublicaçãoAté 280 (os links contam como 23, os emojis como 2) Adicionadas ao texto MP4, MOV; até 512 MB; 0,5 s a 2:20 min
Com seu próprio aplicativo de desenvolvedor do X, as publicações usam os créditos da API dele, cobrados por uso. As hashtags contam para o limite de caracteres.
Facebook Texto Sem título PublicaçãoObrigatório, até 63.206 caracteres Adicionadas ao texto Nenhum
Imagem Sem título LegendaAté 63.206 caracteres Adicionadas ao texto JPEG, PNG, GIF, WebP; até 10 MB
Vídeo TítuloAté 255 caracteres DescriçãoAté 63.206 caracteres Adicionadas ao texto MP4, MOV; até 1 GB; 1 s a 20 min
Publica apenas em Páginas; não é possível publicar em perfis pessoais pela API.
API personalizada Texto TítuloSem limite de tamanho DescriçãoSem limite de tamanho Enviadas como tags Nenhum
Imagem TítuloSem limite de tamanho DescriçãoSem limite de tamanho Enviadas como tags JPEG, PNG, WebP, GIF
Vídeo TítuloSem limite de tamanho DescriçãoSem limite de tamanho Enviadas como tags MP4, MOV, WebM
Cada requisição é assinada com um cabeçalho HMAC-SHA256 para que você possa verificar se ela veio do Amaposta. Responda com 2xx e, opcionalmente, JSON {"id": "…", "url": "…"}. As respostas 408, 429 e 5xx originam novas tentativas com intervalos crescentes; 401/403 assinalam o canal para reconectar; outros 4xx fazem a entrega falhar para você poder corrigir e tentar novamente.
Sandbox Texto TítuloAté 200 caracteres DescriçãoAté 5.000 caracteres Adicionadas ao texto, até 30 Nenhum
Imagem TítuloAté 200 caracteres DescriçãoAté 5.000 caracteres Adicionadas ao texto, até 30 JPEG, PNG, WebP, GIF
Vídeo TítuloAté 200 caracteres DescriçãoAté 5.000 caracteres Adicionadas ao texto, até 30 MP4, MOV, WebM
A publicação demora um momento para você poder acompanhar a mudança de estado em tempo real.