> ## Documentation Index
> Fetch the complete documentation index at: https://docs.so-me.studio/llms.txt
> Use this file to discover all available pages before exploring further.

# Posts e mídia

> Publique imediatamente, agende posts e envie mídia para clientes embedded

Os posts pertencem a um usuário final e devem ter como destino uma das conexões sociais
desse usuário final. A plataforma de `connectionId` deve corresponder a `socialMedia`.

## Criar um post de texto

Omita `scheduledAt` para colocar o post na fila imediatamente:

```ts theme={null}
const post = await soMe.posts.create(
  endUser.id,
  {
    connectionId: connection.id,
    socialMedia: "THREADS",
    postType: "TEXT",
    text: "Published through our app",
  },
  { idempotencyKey: "customer_123:post_456" },
);
```

Para agendá-lo, passe um timestamp ISO 8601:

```ts theme={null}
const post = await soMe.posts.create(
  endUser.id,
  {
    connectionId: connection.id,
    socialMedia: "THREADS",
    postType: "TEXT",
    text: "See you tomorrow",
    scheduledAt: "2026-08-20T10:00:00Z",
  },
  { idempotencyKey: "customer_123:post_457" },
);
```

> [!WARNING]
>
> Use uma chave de idempotência estável e única para cada post lógico. Se a sua requisição
> atingir o tempo limite, tente novamente com a mesma chave. As chaves devem ter de 1 a 255 caracteres e são
> restritas ao espaço de trabalho do usuário final.

## Listar e buscar posts

```ts theme={null}
const page = await soMe.posts.list(endUser.id, {
  page: 1,
  limit: 20,
});

const post = await soMe.posts.get(endUser.id, "post_uuid");
```

`limit` é restrito a 1 a 100. A resposta da listagem contém `data`, `page`,
`limit` e `total`.

## Enviar mídia

Os envios de mídia usam um fluxo de três etapas:

1. Solicite ao Social media studio uma URL de envio pré-assinada.
2. Envie os bytes brutos do arquivo diretamente para essa URL com HTTP `PUT`. Envie um
   cabeçalho `Content-Type` igual ao `mimetype` que você declarou: a URL é
   assinada com ele, então um `PUT` sem o cabeçalho, ou com outro valor, falha com
   `403 SignatureDoesNotMatch`.
3. Anexe as informações do arquivo retornadas ao criar o post.

```ts theme={null}
import { readFile, stat } from "node:fs/promises";

const filename = "launch.jpg";
const mimetype = "image/jpeg";
const size = (await stat(filename)).size;

const [media] = await soMe.posts.presignMedia(endUser.id, {
  postType: "IMAGE",
  socialMedia: "THREADS",
  files: [{ filename, mimetype, size }],
});

const upload = await fetch(media.uploadUrl, {
  method: "PUT",
  headers: { "Content-Type": mimetype },
  body: await readFile(filename),
});

if (!upload.ok) {
  throw new Error(`Media upload failed: ${upload.status}`);
}

const post = await soMe.posts.create(
  endUser.id,
  {
    connectionId: connection.id,
    socialMedia: "THREADS",
    postType: "IMAGE",
    text: "Our launch is live",
    files: [
      {
        id: media.fileId,
        filename,
        mimetype,
        size,
        s3Prefix: media.s3Prefix,
        fileSrc: media.fileSrc,
      },
    ],
  },
  { idempotencyKey: "customer_123:post_458" },
);
```

Para vídeos, inclua `duration` em segundos ao solicitar a URL e ao anexar
o arquivo. As URLs de envio são temporárias; solicite uma nova se um envio tiver expirado.

## Status do post

A resposta de criação confirma que o post foi aceito e colocado na fila; ela não
garante que a plataforma social o publicou. Use `post.status`, consulte
`posts.get` repetidamente ou assine os webhooks `post.published` e `post.failed` para obter o
resultado final.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.