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:
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:
| Escopo | Permite |
|---|---|
content:read | Ler projetos, canais, publicações e arquivos de mídia. |
content:write | Enviar arquivos de mídia e criar ou editar publicações. |
posts:publish | Agendar 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.
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.
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.
# 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.
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.
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
| Campo | O que faz |
|---|---|
kind | text, image ou video. Obrigatório. |
title | Usado pelas plataformas com um campo de título: YouTube, publicações de fotos do TikTok, vídeos do Facebook. |
description | A legenda, a descrição ou o texto da publicação. Também aceito como body, caption ou text. |
hashtags | Uma lista, com ou sem #. |
media_id, media_url | Um 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_url | Uma imagem de capa para vídeos, quando a plataforma o permite. |
channels | IDs dos canais onde publicar. Omita-os para usar todos os canais ativos do projeto que suportam este tipo de publicação. |
overrides | Alterações por canal, indexadas pelo ID do canal: title, description, hashtags e options da plataforma, como privacy do YouTube. |
schedule | mode é 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_ref | A sua própria referência, devolvida na publicação e nas entregas de API personalizada. |
metadata | JSON 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.
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}.
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": [
{
"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.
{
"error": {
"code": "validation",
"message": "Please fix the highlighted fields.",
"fields": {
"kind": "Use text, image or video."
}
}
}
| Status | Código | Significado |
|---|---|---|
| 400 | bad_request | A requisição não pode ser executada como solicitada, como no caso de agendar uma publicação que não passa nas verificações. |
| 401 | unauthorized | A chave de API está em falta, incorreta ou revogada. |
| 402 | plan_limit | O plano do espaço de trabalho não permite isto; limit indica o limite. |
| 403 | forbidden | Falta à chave uma permissão ou acesso ao projeto. |
| 404 | not_found | Esse projeto, publicação, arquivo de mídia ou endpoint não existe. |
| 409 | conflict | A alteração entra em conflito com o estado atual, como editar uma publicação que já está sendo publicada. |
| 422 | validation | Um ou mais campos precisam de correção; consulte fields. |
| 429 | rate_limited | Mais de 120 requisições por minuto com esta chave. |
| 502 | provider_error | Uma 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.
| Evento | Enviado quando |
|---|---|
post.created | Uma publicação foi criada (painel ou API) |
post.scheduled | Uma publicação foi agendada |
post.approved | Uma publicação foi aprovada |
post.published | Uma publicação ficou disponível em um canal |
post.failed | Uma publicação falhou em um canal |
channel.connected | Um canal foi conectado ou reconectado |
channel.disconnected | Um canal perdeu a conexão |
media.ready | O processamento de um envio terminou |
media.failed | Não foi possível processar um envio |
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.
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);
}
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:
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" }
}
Authorization- Sua chave de API. O nome do cabeçalho e o prefixo (
Bearerpor padrão) são definidos no canal. Idempotency-Key- O ID da entrega. Uma nova tentativa da mesma entrega envia a mesma chave, para você poder ignorar trabalho já realizado.
X-Amaposta-Delivery- O ID da entrega novamente, para seus registros.
X-Amaposta-Signature- Assinados como os webhooks, com o segredo de assinatura do próprio canal.
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.
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. | |||||
| 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. | |||||
| 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. | |||||