# API de publicação do SosoAPI: autenticação, requisições e resultados

URL canônica: https://sosoapi.ai/pt-br/docs/publishing-api-reference

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.

## 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.

Endpoints de Scheduled Posts; todas as requisições são POST

| 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.

Campos e valores padrão da requisição de criação

| 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.

Respostas HTTP e próximas ações úteis

| 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. |

- [Matriz de capacidades das plataformas](https://sosoapi.ai/pt-br/docs/publishing-capabilities)

- [Configure seu próprio agente de IA](https://sosoapi.ai/pt-br/docs/quickstart)
