# Do zero ao primeiro vídeo publicado

> 7 passos para a API do Praeko: conta, chave de API, primeira requisição, seu primeiro vídeo (SDK, CLI ou agente), mídia, agendamento e webhook, com exemplos em 10 linguagens.

Fonte: https://praeko.app/docs/get-started

7 passos: conta, chave, primeira requisição, seu primeiro vídeo, mídia, agendamento e webhook. Os exemplos usam `curl`; troque a aba para ver o mesmo passo em outra linguagem.

> **Prefere fazer com um agente de IA?** O guia [Começar com o seu agente](https://praeko.app/docs/get-started-with-agent) leva do zero ao primeiro vídeo com um prompt só: o agente faz quase tudo e você aprova e faz o que só você pode fazer.

### 1. Criar a conta

Entre com o Google em `praeko.app` e conecte pelo menos um canal (YouTube, Instagram ou TikTok) em Canais.

> **Acesso por lista de espera** Hoje o Praeko é um beta fechado: o botão [Entrar na lista de espera](https://praeko.app/#lista) leva ao formulário.

### 2. Criar uma chave de API

No painel, Desenvolvedores, Chaves de API. Escolha o menor escopo que serve: cada nível inclui o anterior.

| Escopo | Serve para |
|---|---|
| (read) | Ler canais, posts, métricas, comentários e uso. |
| (write) | Tudo do read, mais criar e cancelar posts, subir mídia e responder comentários. |
| (admin) | Tudo do write, mais chaves, webhooks, conexões de canal e importações. |

> **O segredo aparece uma vez** Copie a chave `praeko_…` ao criar e guarde em uma variável de ambiente: `export PRAEKO_KEY=…`

### 3. Fazer a primeira requisição

Liste seus canais. Se voltar a lista, a chave e o cabeçalho estão certos.

**curl**

```bash
curl "https://praeko.app/v1/channels" \
  -H "Authorization: Bearer $PRAEKO_KEY" \
  -H "X-Praeko-Contract: en"
```

**JavaScript**

```js
const res = await fetch("https://praeko.app/v1/channels", {
  method: "GET",
  headers: {
    "Authorization": `Bearer ${process.env.PRAEKO_KEY}`,
    "X-Praeko-Contract": "en",
  },
});
console.log(res.status, await res.json());
```

**Node**

```js
import { Praeko } from "@praeko/sdk";

const praeko = new Praeko({ url: "https://praeko.app", key: process.env.PRAEKO_KEY });
const resultado = await praeko.channels.list();
console.log(resultado);
```

**Python**

```python
import os
import requests

resp = requests.get(
    "https://praeko.app/v1/channels",
    headers={
        "Authorization": f"Bearer {os.environ['PRAEKO_KEY']}",
        "X-Praeko-Contract": "en",
    },
)
print(resp.status_code, resp.json())
```

**PHP**

```php
<?php
$ch = curl_init('https://praeko.app/v1/channels');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer " . getenv("PRAEKO_KEY"),
        'X-Praeko-Contract: en',
    ],
]);
$resposta = curl_exec($ch);
echo curl_getinfo($ch, CURLINFO_HTTP_CODE), " ", $resposta, PHP_EOL;
curl_close($ch);
```

**Go**

```go
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
)

func main() {
	req, err := http.NewRequest("GET", "https://praeko.app/v1/channels", nil)
	if err != nil {
		panic(err)
	}
	req.Header.Set("Authorization", "Bearer "+os.Getenv("PRAEKO_KEY"))
	req.Header.Set("X-Praeko-Contract", "en")
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()
	out, _ := io.ReadAll(resp.Body)
	fmt.Println(resp.Status, string(out))
}
```

**Ruby**

```ruby
require "net/http"
require "uri"

uri = URI("https://praeko.app/v1/channels")
request = Net::HTTP::Get.new(uri)
request["Authorization"] = "Bearer #{ENV['PRAEKO_KEY']}"
request["X-Praeko-Contract"] = "en"

response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
puts response.code, response.body
```

**C#**

```csharp
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;

using var client = new HttpClient();
using var request = new HttpRequestMessage(HttpMethod.Get, "https://praeko.app/v1/channels");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", Environment.GetEnvironmentVariable("PRAEKO_KEY"));
request.Headers.Add("X-Praeko-Contract", "en");

using var response = await client.SendAsync(request);
Console.WriteLine($"{(int)response.StatusCode} {await response.Content.ReadAsStringAsync()}");
```

**Java**

```java
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class Main {
    public static void main(String[] args) throws Exception {
        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create("https://praeko.app/v1/channels"))
            .header("Authorization", "Bearer " + System.getenv("PRAEKO_KEY"))
            .header("X-Praeko-Contract", "en")
            .method("GET", HttpRequest.BodyPublishers.noBody())
            .build();
        HttpResponse<String> response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());
        System.out.println(response.statusCode() + " " + response.body());
    }
}
```

**HTTPie**

```bash
http GET "https://praeko.app/v1/channels" \
  "Authorization: Bearer $PRAEKO_KEY" \
  "X-Praeko-Contract: en"
```

**Resposta 200**

```json
{
  "channels": [
    {
      "network": "youtube",
      "supported": true,
      "id": "01KA3V0R5D8M2WQ7X4HT9NZ1BF",
      "connected": true,
      "detail": "Canal do Marcone",
      "name": "Canal do Marcone",
      "timezone": "America/Sao_Paulo",
      "slots": 3,
      "avatar": "/v1/channels/youtube/avatar",
      "default": true
    },
    {
      "network": "instagram",
      "supported": true,
      "id": "01KA3V1G4C7N9PXS2WQ6HM8TDZ",
      "connected": true,
      "detail": "via API da Meta",
      "timezone": "America/Sao_Paulo",
      "slots": 0,
      "meta": {
        "connected": true,
        "username": "dev.ocioso"
      },
      "name": "dev.ocioso"
    },
    {
      "network": "tiktok",
      "supported": true,
      "connected": false,
      "detail": "não conectado (faltam os secrets TIKTOK_CLIENT_KEY e TIKTOK_CLIENT_SECRET)"
    }
  ]
}
```

### 4. Seu primeiro vídeo

**Ainda não tem o vídeo? Faça com o Praeko Studio**, usando o seu próprio agente de código (Claude Code, Codex, Gemini CLI, Cursor, opencode). Depois, publique pelos caminhos abaixo.

**Praeko Studio**

```bash
npm install -g @praeko/studio
praeko-studio doctor
praeko-studio init my-channel --agent claude
cd my-channel   # abra o seu agente aqui e peça o vídeo
```

Guia completo, com o texto para colar no agente, licenças (o Remotion não é MIT) e como publicar: [Praeko Studio](https://praeko.app/docs/studio). Agente sem terminal (como o Claude Desktop)? Use o [MCP local do Studio](https://praeko.app/docs/studio/mcp): ele faz o vídeo e sobe os arquivos, mas quem publica é o servidor MCP remoto `praeko`.

**Já tenho o vídeo:** publique pelo SDK, pela CLI ou pelo agente (MCP).

Você tem um vídeo vertical pronto (MP4 ou MOV, 9:16 para Shorts, Reels e TikTok) e quer vê-lo publicado. Há três caminhos e os três chegam à mesma API. O exemplo usa `clipe.mp4`, um clipe de 20 s (1080×1920, 18 MiB) que sobe primeiro como **privado** no YouTube: você confere antes de torná-lo público.

> **Antes de começar** Conecte um canal do YouTube em Canais, no painel, e deixe a chave do passo 2 em `PRAEKO_KEY`.

**Pelo SDK, em TypeScript ou JavaScript.** O pacote traz os tipos do TypeScript e não tem dependências.

**Instalar**

```bash
npm install @praeko/sdk
```

**publicar.mjs**

```js
// publicar.mjs: node publicar.mjs
import { Praeko } from "@praeko/sdk";
import { uploadFile } from "@praeko/sdk/node"; // só Node: lê o arquivo do disco em partes

const praeko = new Praeko({ url: "https://praeko.app", key: process.env.PRAEKO_KEY });

// 1) envia o vídeo (até 50 MiB vai numa requisição só; acima disso o SDK divide em partes)
const video = await uploadFile(praeko, "./clipe.mp4", { type: "video" });

// 2) cria o post: um item por rede. No YouTube, mode "private" sobe agora e fica privado
const post = await praeko.posts.create(
  {
    title: "Como o cache derrubou o deploy",
    media: { video: video.id },
    texts: { youtube: { title: "Como o cache derrubou o deploy", text: "20 segundos sobre o bug que só aparecia depois do deploy.\n\n#programação #shorts" } },
    items: [{ network: "youtube", mode: "private" }],
  },
  { idempotencyKey: "first-video-clipe-01" }, // repetir o script não cria um segundo post (a chave vale 24 h)
);

console.log(post.id, post.items[0].state);
```

O mesmo código serve em `.ts`: rode-o com o executor de TypeScript que você já usa. O `uploadFile` devolve a mídia pronta; o `posts.create` devolve o post:

**Mídia pronta (resposta do envio)**

```json
{
  "id": "01KA3VQ7M2T9XE4HB8N5RZ6C0D",
  "type": "video",
  "name": "clipe.mp4",
  "mime": "video/mp4",
  "size": 18874368,
  "state": "ready",
  "publicUrl": "https://praeko.app/v1/m/01KA3VQ7M2T9XE4HB8N5RZ6C0D/k7Qm2vXz9Rt4Lp8Wc3Nd6Hy1Bs5Fa0J/clipe.mp4",
  "durationMs": 20040,
  "width": 1080,
  "height": 1920,
  "createdAt": "2026-11-07T14:02:11.482Z"
}
```

**Resposta 201 de POST /v1/posts**

```json
{
  "id": "01KA3W2Y6H1RC5ZQ8M0T4VXE7N",
  "items": [
    {
      "id": "01KA3W2Y6J9D3BNF7G2K5PQS8A",
      "network": "youtube",
      "channel": "01KA3V0R5D8M2WQ7X4HT9NZ1BF",
      "state": "scheduled",
      "scheduledFor": null,
      "custom": false,
      "mode": "private",
      "runAt": "2026-11-07T14:02:12.000Z"
    }
  ]
}
```

O item entra com `state: "scheduled"` e `runAt` agora; o Praeko sobe o vídeo ao YouTube em seguida. Quando o item passar a `private`, o vídeo já está no YouTube, privado, esperando você. Confira com `GET /v1/posts/:id` e, quando estiver satisfeito, publique com `praeko.posts.scheduleYoutube(post.id, "2026-11-14T17:30:00Z")` ou torne-o público no YouTube Studio.

**Pela CLI.** A CLI lê uma pasta-pacote com o vídeo, a capa e um `publication.json`, e confere os textos antes de enviar. Ela também precisa de um `praeko.json` na pasta atual (ou acima).

**A pasta-pacote**

```text
package/
  clipe.mp4          # o vídeo
  cover.png          # a capa (o nome precisa conter capa, cover ou thumb)
  publication.json   # título, textos de cada rede e hashtags
```

**package/publication.json**

```json
{
  "title": "Como o cache derrubou o deploy",
  "format": "short",
  "files": { "video": "clipe.mp4", "cover": "cover.png" },
  "yt": { "description": "20 segundos sobre o bug que só aparecia depois do deploy." },
  "ig": { "caption": "O bug que só aparecia depois do deploy." },
  "tiktok": { "caption": "O bug que só aparecia depois do deploy." },
  "hashtags": { "youtube": ["#programação", "#shorts"], "instagram": ["#programação"], "tiktok": ["#programação"] }
}
```

**praeko.json**

```json
{
  "name": "Meu canal",
  "links": { "main": "https://example.com" }
}
```

No `praeko.json`, `links.main` é opcional: é o link que a CLI acrescenta, com UTM, ao fim da descrição do YouTube. Os textos de cada rede vêm do `publication.json`.

**Terminal**

```bash
npm install -g @praeko/cli        # ou use npx @praeko/cli no lugar de praeko
export PRAEKO_SERVER=https://praeko.app
export PRAEKO_KEY="praeko_…"

praeko post ./package --networks yt --yt-mode private           # SIMULA: nada é enviado
praeko post ./package --networks yt --yt-mode private --send    # envia de verdade
```

**Saída da simulação**

```text
SIMULATION (nothing will be sent; use --send) [remote]: Como o cache derrubou o deploy
package: /home/you/package
video: clipe.mp4  cover: cover.png
  YouTube    now  mode private  text 126 chars
```

Para as três redes de uma vez, troque as opções por `--when "2026-11-14T17:30" --networks yt,ig,tt` (horário no fuso do `praeko.json`, `-03:00` por padrão) ou por `--queue`, que usa o próximo horário livre de cada canal. Sem `--send` a CLI só simula. Todos os comandos estão em [SDK e CLI](https://praeko.app/docs/sdk#cli).

**Pelo seu agente, via MCP.** Conecte o Claude Code, o Codex ou outro agente ao servidor `https://praeko.app/mcp` (com uma chave de API ou entrando com a sua conta) e peça: "publique `~/clipes/clipe.mp4` como vídeo privado no YouTube, com o título tal". O agente mostra uma prévia com um código de confirmação antes de qualquer coisa ser publicada, e sobe o arquivo do disco com as ferramentas de envio. Veja [Servidor MCP](https://praeko.app/docs/mcp) e [Agentes de IA](https://praeko.app/docs/agents).

Ainda não tem o vídeo? Veja [Gerar o vídeo com o Praeko Studio](#studio).

### 5. Subir a mídia, por baixo do SDK

O SDK, a CLI e o agente fazem isto por você. Crie a mídia, envie os bytes e use o `id` no post. Até 50 MiB, dá para mandar o arquivo todo com `simple: true`; acima disso, em partes de pelo menos 5 MiB, e depois `POST /v1/media/:id/complete`. Detalhes em [Enviar mídia](https://praeko.app/docs/guides/media).

**curl**

```bash
curl -X POST https://praeko.app/v1/media -H "Authorization: Bearer $PRAEKO_KEY" \
  -H "X-Praeko-Contract: en" -H "Content-Type: application/json" \
  -d '{ "type": "video", "name": "v.mp4", "mime": "video/mp4", "size": 8123456, "simple": true }'
# resposta: { "id": "…", "state": "uploading", … }
curl -X PUT https://praeko.app/v1/media/$MEDIA_ID/content -H "Authorization: Bearer $PRAEKO_KEY" \
  -H "Content-Type: video/mp4" --data-binary @v.mp4
```

### 6. Agendar um post, por baixo do SDK

Um item por rede. Cada item vai para a fila (`queue`), para um horário fixo (`scheduledFor`) ou fica como rascunho (`draft`). No YouTube e no TikTok, sem horário, o item sobe agora.

**curl**

```bash
curl -X POST https://praeko.app/v1/posts -H "Authorization: Bearer $PRAEKO_KEY" \
  -H "X-Praeko-Contract: en" -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{ "title": "Meu vídeo", "media": { "video": "'$MEDIA_ID'" },
        "texts": { "youtube": { "text": "Descrição" } },
        "items": [ { "network": "youtube", "queue": true } ] }'
```

### 7. Ouvir um webhook

Cadastre uma URL https pública (escopo admin). O segredo `whsec_…` volta uma vez. Cada entrega traz `Praeko-Signature`, assinada com HMAC-SHA256.

> **Pronto** Quando o post sair, você recebe `post.sent`. Próximo: [conferir a assinatura](https://praeko.app/docs/guides/webhooks) e tratar repetições.

## Gerar o vídeo com o Praeko Studio

O Praeko Studio é a ferramenta de vídeo como código do Praeko: você escreve o roteiro e ele monta um Short vertical. O caminho é este: **roteiro** (um texto simples) → **voz** (narração com ElevenLabs ou uma voz local; há uma versão rápida e muda só para montar as cenas) → **legenda** palavra a palavra, com o tempo de cada palavra → **cenas** (peças de interface descritas em YAML e TSX, renderizadas com Remotion ou HyperFrames) → **capa** → **pacote**, a pasta com o vídeo, a capa e o `publication.json` que a CLI e o SDK sabem publicar. Os comandos são `praeko studio new`, `voice`, `render`, `cover` e `package`.

> **Instale e comece** `npm install -g @praeko/studio` e siga o guia [Praeko Studio](https://praeko.app/docs/studio): requisitos, primeiro vídeo em 10 minutos com o seu agente, chaves, licenças e como publicar pelo Praeko. Sem terminal, use o [MCP local do Studio](https://praeko.app/docs/studio/mcp) (`@praeko/studio-mcp`, que nunca publica). O Remotion, motor padrão, **não é MIT**: grátis até 3 pessoas na empresa.
