Referência da API no servidor
API de publicação do SosoAPI: autenticação, requisições e resultados
Crie uma integração de publicação no servidor com um Scheduled Post por destino. Esta referência abrange o contrato da API de publicação revisado em 20 de outubro de 2026. Os exemplos contêm placeholders e não são executados nesta página.
Ler como MarkdownRevisado pela equipe SosoAPI ·
1. Autentique pelo servidor
Crie uma API key no app SosoAPI → Configurações → Agentes e acesso à API. Armazene como SOSOAPI_API_KEY no ambiente do servidor. As requisições usam Authorization: Bearer <your-key> e Content-Type: application/json. Nunca incorpore a chave em um site, pacote de app móvel, URL ou repositório público.
Todos os endpoints abaixo usam POST com corpo JSON. Chaves e concessões delegadas de agente são limitadas pelas suas capacidades, Workspaces permitidos e participação atual do proprietário. Consultas exigem agent:operate e acesso mínimo viewer; mutações de publicação exigem agent:publish e acesso mínimo editor. Uma concessão não pode ampliar os direitos do proprietário.
Use o workspace atual do app e as contas conectadas ou chame /identity-api/workspace/list e /identity-api/user/social-accounts/list para encontrar IDs que você tem autorização para usar. Não adivinhe o ID do workspace ou da conta de um cliente.
// Node.js 20+; run only on your server.
const apiKey = process.env.SOSOAPI_API_KEY;
if (!apiKey) throw new Error("Set SOSOAPI_API_KEY on your server");
const apiBase = "https://gqeshlawtcexsapabaui.supabase.co/functions/v1";
async function sosoPost(path, body) {
const response = await fetch(apiBase + path, {
method: "POST",
headers: {
Authorization: "Bearer " + apiKey,
"Content-Type": "application/json"
},
body: JSON.stringify(body)
});
const result = await response.json();
if (!response.ok) {
const requestId = result.request_id ?? response.headers.get("x-request-id");
// Handler errors use code/message; schema-validation 400s instead use
// success:false and error:{name:"ZodError",message:...}.
// Preserve status, available code and requestId in server diagnostics.
// Never log the key or an Authorization header.
throw new Error("SosoAPI " + response.status + " (" +
(requestId ?? "no request id") + ")");
}
return result;
}2. Mapa de endpoints de publicação
Estes caminhos são relativos à base da API usada no helper de servidor. Consulte o detalhe do Scheduled Post para obter a versão atual, ações disponíveis e resultado de publicação.
| Caminho | Requisição | Resposta e limite |
|---|---|---|
| /studio-api/scheduled-posts/list | workspace_id; project_id, status, par de horários, limit e cursor opcionais. | posts, next_cursor, returned_count. Consulta restrita ao Workspace. |
| /studio-api/scheduled-posts/get | id. | post, delivery, actions, attempts, outcomes. Consulte a versão atual aqui. |
| /studio-api/scheduled-posts/eligibility | workspace_id, targets; include_quota opcional. | destinos e cota opcional. Verificação prévia somente de leitura, não uma reserva. |
| /studio-api/scheduled-posts/create | workspace_id, conta exata, provider_payload, conteúdo, scheduled_at, idempotency_key. | post e deduped. 201 para novo agendamento; 200 para repetição correspondente. |
| /studio-api/scheduled-posts/bulk-create | workspace_id e 1–50 targets, cada um com sua própria idempotency_key. | batch_id, successes, failures. 201 quando pelo menos um tem sucesso; 422 quando nenhum tem sucesso. Consulte ambos os arrays. |
| /studio-api/scheduled-posts/update | id, expected_version, patch; provider_payload correspondente opcional. | post. Uma versão desatualizada é rejeitada; o destino é imutável. |
| /studio-api/scheduled-posts/publish-now | id e expected_version. | post. Solicita execução imediata; não comprova publicação. |
| /studio-api/scheduled-posts/retry | id, expected_version; scheduled_at futuro opcional. | post. Recuperação apenas de falhas, condicionada a evidências; nunca um reenvio cego. |
| /studio-api/scheduled-posts/cancel | id e expected_version. | post. Cancela trabalho não publicado; o cancelamento remoto pode continuar pendente. |
| /studio-api/scheduled-posts/delete | id e expected_version. | post. Chamadores de máquina não podem excluir conteúdo do provedor já publicado. |
| /studio-api/scheduled-posts/withdraw-delete | id e expected_version. | post. Retira uma solicitação interrompida de exclusão do Instagram Login apenas para verificação; mantém o conteúdo no provedor. |
3. Liste e pagine sem perder o escopo
limit tem padrão 50 e aceita 1–200. O status opcional é scheduled, publishing, published, failed, expired, needs_reschedule, cancelled ou deleted. scheduled_from e scheduled_to devem ser informados juntos como instantes ISO-8601 com deslocamento de fuso; o fim deve ser posterior ao início.
next_cursor é null ou um objeto com scheduled_at e id. Envie esse objeto completo como cursor com o mesmo Workspace e filtros. Este endpoint não aceita filtros page, offset, platform ou social_account_id.
await sosoPost("/studio-api/scheduled-posts/list", {
"workspace_id": "<workspace-uuid>",
"limit": 50
});const first = await sosoPost("/studio-api/scheduled-posts/list", {
workspace_id: "<workspace-uuid>", limit: 50
});
if (first.next_cursor) {
const next = await sosoPost("/studio-api/scheduled-posts/list", {
workspace_id: "<workspace-uuid>", limit: 50, cursor: first.next_cursor
});
// Consume next.posts; continue only while next_cursor is not null.
}4. Valide e crie um post revisado
Substitua todos os placeholders por valores do seu escopo autorizado e um horário futuro. Este exemplo agenda um post de texto real no Threads ao ser executado. Obtenha a confirmação da pessoa sobre a conta, o conteúdo e o horário antes da chamada de criação.
Defina provider_payload.platform e publish_options dessa plataforma. O servidor verifica se correspondem à conta selecionada. Você pode incluir project_id para registrar a origem do post; o projeto não concede acesso de publicação nem controla o agendamento.
| Campo | Contrato |
|---|---|
| workspace_id / social_account_id | UUIDs obrigatórios do Workspace autorizado e do destino exato. |
| provider_payload | Discriminador platform obrigatório e publish_options específicas da plataforma. |
| scheduled_at / display_timezone | Instante ISO-8601 obrigatório com deslocamento; fuso IANA de exibição válido, padrão UTC. |
| idempotency_key | String obrigatória sem espaços nas extremidades, de 8–160 caracteres, estável para esta única intenção. |
| caption / hashtags | Caption aceita null e no máximo 5,000 caracteres; o padrão é null. Hashtags têm padrão []; no máximo 100 strings de 100 caracteres. Os limites do provedor podem ser menores. |
| media | Padrão []; no máximo 20 referências de mídia registradas. Cada uma tem kind image/video e url canônica; inclua seu asset_id pronto. As regras da plataforma podem ser mais restritas. |
| link_url | URL opcional ou null. Destino e tipo de post devem oferecer suporte. |
| local_scheduled_at / schedule_dst_disambiguation | Par opcional: horário local sem deslocamento e exact/earlier/later. Informe ambos ou nenhum; eles devem corresponder ao instante e fuso pretendidos. |
| expires_at / automatic_retry_enabled | Validade opcional após scheduled_at; null significa sem validade. A repetição automática tem padrão true e continua sujeita à segurança do provedor. |
| project_id / source_ref | UUID de Project opcional que aceita null e objeto de proveniência do chamador. Nenhum altera a autoridade. |
await sosoPost("/studio-api/scheduled-posts/eligibility", {
"workspace_id": "<workspace-uuid>",
"include_quota": true,
"targets": [
{
"social_account_id": "<threads-account-uuid>",
"media": [],
"provider_payload": {
"platform": "threads",
"publish_options": {
"post_type": "TEXT"
}
},
"draft": {
"caption": "A reviewed update from our team.",
"hashtags": [],
"scheduled_at": "<future-ISO-8601-instant-with-offset>",
"display_timezone": "Asia/Hong_Kong"
}
}
]
});await sosoPost("/studio-api/scheduled-posts/create", {
"workspace_id": "<workspace-uuid>",
"social_account_id": "<threads-account-uuid>",
"caption": "A reviewed update from our team.",
"hashtags": [],
"media": [],
"provider_payload": {
"platform": "threads",
"publish_options": {
"post_type": "TEXT"
}
},
"scheduled_at": "<future-ISO-8601-instant-with-offset>",
"display_timezone": "Asia/Hong_Kong",
"idempotency_key": "<stable-key-for-this-one-intent>"
});5. Leia o resultado e cancele com segurança
Create retorna { post, deduped }. List retorna { posts, next_cursor, returned_count }. Get retorna { post, delivery, actions, attempts, outcomes }. Um post inclui id, status, version, destination, schedule e identidade/permalink disponíveis do provedor; delivery e actions explicam o progresso atual e os próximos passos permitidos.
Um post com status scheduled ou publishing ainda está pendente. Um resultado terminal de publicação com status published confirma a publicação e inclui as evidências disponíveis do provedor para esse post; o permalink pode estar ausente. Se o cliente desconectar ou uma resposta atrasar, consulte o post existente antes de informar um resultado.
Antes de cancelar, consulte o detalhe do post e informe sua versão numérica atual. O resultado pode ser cancellation_pending enquanto o SosoAPI cancela um agendamento mantido pelo provedor. Cancelar um agendamento não exclui um post já publicado.
await sosoPost("/studio-api/scheduled-posts/get", {
"id": "<scheduled-post-uuid>"
});const detail = await sosoPost("/studio-api/scheduled-posts/get", {
id: "<scheduled-post-uuid>"
});
// Run only after the person confirms cancelling this unpublished post.
await sosoPost("/studio-api/scheduled-posts/cancel", {
id: detail.post.id, expected_version: detail.post.version
});6. Idempotência, conflitos e gravações incertas
Use a mesma idempotency_key ao repetir a mesma solicitação de criação. Uma repetição correspondente retorna o post existente com deduped=true. Alterar o conteúdo reutilizando a chave causa conflito. Isso impede criações duplicadas no SosoAPI; não garante entrega exatamente uma vez pelo provedor.
Para atualizações e ações, informe expected_version da resposta de detalhes mais recente. Se houver conflito, consulte o post novamente e revise a alteração conforme a nova versão. Uma resposta perdida é motivo para conferir o estado existente, não para criar outro post com nova chave.
A proteção contra conteúdo duplicado pode rejeitar outra solicitação com o mesmo conteúdo público normalizado, conta e horário de publicação próximo. Consulte a referência do post existente se tiver autorização para lê-lo e pergunte ao usuário antes de alterar a solicitação. Requisições em lote retornam um resultado por destino; algumas podem funcionar enquanto outras falham.
7. Erros, limites de taxa e limites de integração
Erros do handler usam um envelope com error, message, code opcional, retryable, request_id, details opcional e retry_after_seconds. Erros 400 de validação de schema retornam outro formato: { success: false, error: { name: "ZodError", message: "…" } }. A mensagem de validação atualmente contém os problemas serializados dos campos, incluindo seus caminhos; não presuma a presença dos campos do envelope do handler.
Ao diagnosticar uma falha, mantenha status HTTP, código de erro e ID de correlação de result.request_id ?? response.headers.get("x-request-id"). Use os caminhos dos campos de validação para corrigir a requisição. Para erros de autenticação ou permissão, corrija a credencial ou concessão antes de tentar novamente.
O limite atual de studio-api é 240 requisições por minuto por usuário humano e 480 por minuto no bucket separado de credenciais de máquina desse usuário. São tetos de requisições, não capacidade de publicação nem cotas de plano. Outros endpoints e provedores sociais têm limites separados. Siga o cabeçalho Retry-After atual em 429 ou 503 repetível; não execute um loop contínuo.
Consulte o status em intervalos limitados enquanto o usuário acompanha o post ou use a visualização de status ao vivo do app. Esta API não promete webhooks de saída, SLA para assinantes, recursos idênticos em todas as plataformas nem horário fixo de publicação.
| Status | Significado e resposta |
|---|---|
| 400 | A validação de schema pode retornar success:false com um ZodError em error, em vez do envelope do handler. Corrija os problemas dos campos; use x-request-id se o corpo não tiver request_id. Requisições inválidas ou incompatíveis no nível do handler também podem usar 400. |
| 401 / 403 | Credencial ausente/expirada ou capacidade, função, Workspace ou acesso à conta negados. Corrija a permissão ou participação exata. |
| 404 | O recurso está indisponível no escopo autorizado. Verifique a identidade. |
| 409 | Conflito de estado/versão, idempotência, conteúdo duplicado ou elegibilidade. Consulte novamente; não reenvie cegamente. |
| 422 para bulk-create | Nenhum destino teve sucesso. Consulte failures; sucesso parcial usa 201. |
| 429 | Limitação de requisições. Respeite Retry-After e mantenha a mesma identidade de intenção. |
| 503 / outros 5xx | Falha temporária do serviço ou erro interno. Preserve request_id; consulte o estado existente antes de repetir uma mutação incerta. |