Edita título, textos, mídia, etiquetas e itens, ou move para rascunho ou fila. Só vai o que mudou; o resto fica. Um item do YouTube já enviado e ainda agendado também muda de horário e de dados (conferido ao vivo no YouTube).
CabeçalhosAuthorization: Bearer praeko_… e X-Praeko-Contract: en. Sempre envie os dois.
Parâmetros
Nome
Onde
Descrição
id
caminho
Id do post.
Idempotency-Key
cabeçalho
Chave de idempotência (1 a 255 caracteres visíveis, por exemplo um UUID). Repetir o MESMO pedido com a mesma chave, em até 24 h, devolve a resposta guardada (com Idempotent-Replayed: true) sem executar de novo; outro pedido com a mesma chave dá 422 idempotency_key_reuse; um pedido ainda em andamento dá 409 idempotency_in_progress. Erros 5xx não são guardados. A chave vale por workspace e por rota. Veja Repetir uma requisição.
Corpo da requisição
JSON. Campos obrigatórios precisam ir; os outros podem ser omitidos. Envie só o que muda. Um post adotado do Buffer só aceita texto, horário e rascunho (o resto dá 409 post_adopted). YouTube já enviado: um item do YouTube em estado scheduled (o Praeko já subiu o vídeo como privado, com publishAt no futuro) ou private pode mudar scheduledFor (vira videos.update com status.publishAt; o resto do status é preservado), título, descrição (texts.youtube), videoTags, categoryId e o pinnedComment ainda não postado. Antes de agir o servidor confere AO VIVO no YouTube (videos.list, 1 unidade de cota; cada escrita custa 50). Se o vídeo já foi publicado, o horário agendado já passou, o vídeo foi apagado ou não foi enviado pelo Praeko, nada é escrito e a resposta é 409 com o motivo e o link do Studio (https://studio.youtube.com/video/<id>/edit). O novo horário precisa ser daqui a pelo menos 5 minutos (senão 422 time_in_past). Pedir o mesmo horário de novo não chama o YouTube. Um PATCH com vários itens aplica cada um por conta própria e devolve itemResults (um por item do YouTube já enviado: applied, changed, fields, notApplied, reason, message, publishAt, studio); se NENHUM item do pedido pôde mudar, a resposta é o 409 do primeiro. Instagram e TikTok pendentes seguem as regras de sempre.
Campo
Tipo
Descrição
title (opcional)
texto
Novo título. 1 a 200 caracteres.
texts (opcional)
objeto
Textos por rede que mudam. Os campos enviados substituem; os outros ficam. Um text não pode ficar vazio nem trazer marcador como [LINK_DO_LONGO].
texts.youtube (opcional)
objeto
Textos do YouTube.
texts.youtube.title (opcional)
texto
Título.
texts.youtube.text (opcional)
texto
Descrição.
texts.youtube.pinnedComment (opcional)
texto
Comentário fixo.
texts.instagram (opcional)
objeto
Textos do Instagram.
texts.instagram.text (opcional)
texto
Legenda.
texts.instagram.pinnedComment (opcional)
texto
Comentário fixo.
texts.tiktok (opcional)
objeto
Textos do TikTok.
texts.tiktok.text (opcional)
texto
Legenda.
media (opcional)
objeto
Troca de mídia.
media.cover (opcional)
texto
Id da nova capa (ou null para tirar).
media.video (opcional)
texto
Id do novo vídeo (só em post adotado ou ainda em rascunho; senão 409 media_locked).
tags (opcional)
string[]
Etiquetas (substituem as atuais).
items (opcional)
objeto[]
Itens a editar, escolhidos por id ou por network. Só dá para editar item ainda pendente.
items[].id (opcional)
texto
Id do item.
items[].network (opcional)
texto
Rede do item (alternativa ao id). Valores: youtube, instagram, tiktok.
items[].mode (opcional)
texto
Novo modo (YouTube: private, scheduled, public; TikTok: draft, direct). Valores: private, scheduled, public, draft, direct, now.
items[].scheduledFor (opcional)
texto
Novo horário fixo. Data e hora ISO 8601 em UTC, por exemplo 2026-11-14T20:30:00Z.
items[].queue (opcional)
verdadeiro/falso
Volta para o próximo horário livre do canal.
items[].draft (opcional)
verdadeiro/falso
Vira rascunho.
items[].privacy (opcional)
texto
TikTok: quem vê. Valores: PUBLIC_TO_EVERYONE, MUTUAL_FOLLOW_FRIENDS, FOLLOWER_OF_CREATOR, SELF_ONLY.
items[].coverFrameMs (opcional)
inteiro
TikTok: quadro da capa em milissegundos. Mínimo 0.
items[].videoTags (opcional)
string[]
YouTube, só em vídeo já enviado e ainda agendado: tags do vídeo (substituem as atuais).
items[].categoryId (opcional)
texto
YouTube, só em vídeo já enviado e ainda agendado: número da categoria (ex.: 28).
moveTo (opcional)
texto
Move TODOS os itens editáveis para rascunho ou para a fila. Valores: draft, queue.
Exemplo de corpo
{
"title": "O teste que só falhava na segunda (versão final)",
"tags": [
"bastidores",
"testes"
],
"items": [
{
"network": "youtube",
"scheduledFor": "2026-11-10T20:30:00.000Z"
}
]
}
Exemplo
curl -X PATCH "https://praeko.app/v1/posts/01KA3W2Y6H1RC5ZQ8M0T4VXE7N" \
-H "Authorization: Bearer $PRAEKO_KEY" \
-H "X-Praeko-Contract: en" \
-H "Content-Type: application/json" \
-d '{
"title": "O teste que só falhava na segunda (versão final)",
"tags": [
"bastidores",
"testes"
],
"items": [
{
"network": "youtube",
"scheduledFor": "2026-11-10T20:30:00.000Z"
}
]
}'
const res = await fetch("https://praeko.app/v1/posts/01KA3W2Y6H1RC5ZQ8M0T4VXE7N", {
method: "PATCH",
headers: {
"Authorization": `Bearer ${process.env.PRAEKO_KEY}`,
"X-Praeko-Contract": "en",
"Content-Type": "application/json",
},
body: JSON.stringify({
"title": "O teste que só falhava na segunda (versão final)",
"tags": [
"bastidores",
"testes"
],
"items": [
{
"network": "youtube",
"scheduledFor": "2026-11-10T20:30:00.000Z"
}
]
}),
});
console.log(res.status, await res.json());
import { Praeko } from "@praeko/sdk";
const praeko = new Praeko({ url: "https://praeko.app", key: process.env.PRAEKO_KEY });
const resultado = await praeko.posts.update("01KA3W2Y6H1RC5ZQ8M0T4VXE7N", {
"title": "O teste que só falhava na segunda (versão final)",
"tags": [
"bastidores",
"testes"
],
"items": [
{
"network": "youtube",
"scheduledFor": "2026-11-10T20:30:00.000Z"
}
]
});
console.log(resultado);
import os
import requests
resp = requests.patch(
"https://praeko.app/v1/posts/01KA3W2Y6H1RC5ZQ8M0T4VXE7N",
headers={
"Authorization": f"Bearer {os.environ['PRAEKO_KEY']}",
"X-Praeko-Contract": "en",
},
json={
"title": "O teste que só falhava na segunda (versão final)",
"tags": [
"bastidores",
"testes",
],
"items": [
{
"network": "youtube",
"scheduledFor": "2026-11-10T20:30:00.000Z",
},
],
},
)
print(resp.status_code, resp.json())
package main
import (
"fmt"
"io"
"net/http"
"os"
"strings"
)
func main() {
body := strings.NewReader(`{
"title": "O teste que só falhava na segunda (versão final)",
"tags": [
"bastidores",
"testes"
],
"items": [
{
"network": "youtube",
"scheduledFor": "2026-11-10T20:30:00.000Z"
}
]
}`)
req, err := http.NewRequest("PATCH", "https://praeko.app/v1/posts/01KA3W2Y6H1RC5ZQ8M0T4VXE7N", body)
if err != nil {
panic(err)
}
req.Header.Set("Authorization", "Bearer "+os.Getenv("PRAEKO_KEY"))
req.Header.Set("X-Praeko-Contract", "en")
req.Header.Set("Content-Type", "application/json")
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))
}
require "net/http"
require "uri"
uri = URI("https://praeko.app/v1/posts/01KA3W2Y6H1RC5ZQ8M0T4VXE7N")
request = Net::HTTP::Patch.new(uri)
request["Authorization"] = "Bearer #{ENV['PRAEKO_KEY']}"
request["X-Praeko-Contract"] = "en"
request["Content-Type"] = "application/json"
request.body = <<~'JSON'
{
"title": "O teste que só falhava na segunda (versão final)",
"tags": [
"bastidores",
"testes"
],
"items": [
{
"network": "youtube",
"scheduledFor": "2026-11-10T20:30:00.000Z"
}
]
}
JSON
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
puts response.code, response.body
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using var client = new HttpClient();
using var request = new HttpRequestMessage(HttpMethod.Patch, "https://praeko.app/v1/posts/01KA3W2Y6H1RC5ZQ8M0T4VXE7N");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", Environment.GetEnvironmentVariable("PRAEKO_KEY"));
request.Headers.Add("X-Praeko-Contract", "en");
request.Content = new StringContent("""
{
"title": "O teste que só falhava na segunda (versão final)",
"tags": [
"bastidores",
"testes"
],
"items": [
{
"network": "youtube",
"scheduledFor": "2026-11-10T20:30:00.000Z"
}
]
}
""", Encoding.UTF8, "application/json");
using var response = await client.SendAsync(request);
Console.WriteLine($"{(int)response.StatusCode} {await response.Content.ReadAsStringAsync()}");
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 {
String body = """
{
"title": "O teste que só falhava na segunda (versão final)",
"tags": [
"bastidores",
"testes"
],
"items": [
{
"network": "youtube",
"scheduledFor": "2026-11-10T20:30:00.000Z"
}
]
}
""";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://praeko.app/v1/posts/01KA3W2Y6H1RC5ZQ8M0T4VXE7N"))
.header("Authorization", "Bearer " + System.getenv("PRAEKO_KEY"))
.header("X-Praeko-Contract", "en")
.header("Content-Type", "application/json")
.method("PATCH", HttpRequest.BodyPublishers.ofString(body))
.build();
HttpResponse<String> response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode() + " " + response.body());
}
}
http PATCH "https://praeko.app/v1/posts/01KA3W2Y6H1RC5ZQ8M0T4VXE7N" \
"Authorization: Bearer $PRAEKO_KEY" \
"X-Praeko-Contract: en" \
"Content-Type: application/json" \
--raw='{
"title": "O teste que só falhava na segunda (versão final)",
"tags": [
"bastidores",
"testes"
],
"items": [
{
"network": "youtube",
"scheduledFor": "2026-11-10T20:30:00.000Z"
}
]
}'
SDK oficial para NodeInstale com npm install @praeko/sdk (veja SDK e CLI).
Sem SDK oficialExemplo com a biblioteca padrão (ou o cliente HTTP) da linguagem. Só o SDK de JavaScript existe.
Sem SDK oficialExemplo com a biblioteca padrão (ou o cliente HTTP) da linguagem. Só o SDK de JavaScript existe.
Sem SDK oficialExemplo com a biblioteca padrão (ou o cliente HTTP) da linguagem. Só o SDK de JavaScript existe.
Sem SDK oficialExemplo com a biblioteca padrão (ou o cliente HTTP) da linguagem. Só o SDK de JavaScript existe.
Sem SDK oficialExemplo com a biblioteca padrão (ou o cliente HTTP) da linguagem. Só o SDK de JavaScript existe.
Sem SDK oficialExemplo com a biblioteca padrão (ou o cliente HTTP) da linguagem. Só o SDK de JavaScript existe.
Resposta
Status de sucesso
Quando
200
Sucesso.
Resposta 200
{
"id": "01KA3W2Y6H1RC5ZQ8M0T4VXE7N",
"title": "O teste que só falhava na segunda (versão final)",
"state": "queued",
"type": "short",
"kind": "video",
"origin": "api",
"media": {
"video": "01KA3VQ7M2T9XE4HB8N5RZ6C0D",
"cover": null
},
"texts": {
"youtube": {
"title": "O teste que só falhava na segunda",
"text": "Um teste que passava de terça a domingo. O que ele escondia.\n\n#programação #testes"
}
},
"tags": [
"bastidores",
"testes"
],
"thumb": null,
"items": [
{
"id": "01KA3W2Y6J9D3BNF7G2K5PQS8A",
"network": "youtube",
"channel": "01KA3V0R5D8M2WQ7X4HT9NZ1BF",
"state": "scheduled",
"scheduledFor": "2026-11-10T20:30:00.000Z",
"custom": true,
"mode": "scheduled",
"runAt": "2026-11-10T19:30:00.000Z",
"thumb": null
}
],
"createdAt": "2026-11-07T14:02:11.482Z",
"updatedAt": "2026-11-07T15:40:03.120Z",
"actions": []
}
Erros
Status
code
Quando
400
empty_body
O corpo veio vazio.
400
invalid_json
O corpo não é um objeto JSON.
413
body_too_large
O corpo passa de 1 MB.
404
post_not_found
O post não existe.
404
item_not_found
O item não existe neste post.
409
not_editable
O item já saiu ou está em andamento (YouTube já enviado: só muda enquanto o vídeo segue privado e agendado; se o horário agendado já passou, não muda mais).
409
post_adopted
Post adotado do Buffer: só texto, horário e rascunho mudam.
409
media_locked
O vídeo só troca em post adotado ou em rascunho; a imagem de um post de imagem não troca por PATCH.
409
video_not_private
YouTube já enviado: o vídeo já está público no YouTube, então o horário e os dados só mudam pelo Studio (o details.studio traz o link).
409
video_not_found
YouTube já enviado: o vídeo foi apagado no YouTube.
422
time_in_past
O novo horário precisa ser daqui a pelo menos 5 minutos.
502
youtube_error
O YouTube não respondeu ou recusou a conferência/escrita; nada foi alterado (ou o itemResults diz o que ficou).
422
invalid_field
Algum campo inválido.
422
idempotency_key_reuse
A Idempotency-Key já foi usada com outro pedido (método, caminho, query ou corpo diferentes).
409
idempotency_in_progress
Um pedido com a mesma Idempotency-Key ainda está em andamento (repita em instantes).
409
idempotency_response_too_large
A resposta original passou de 256 KB e não foi guardada; consulte o recurso por GET.
Erros de qualquer rota
Status
code
Quando
401
unauthorized
Faltou o cabeçalho Authorization: Bearer ….
401
invalid_api_key
A chave não existe.
401
revoked_api_key
A chave foi revogada.
401
expired_api_key
A chave expirou.
403
forbidden
O escopo da chave não basta para esta rota (veja o selo de escopo).
429
rate_limited
Passou do limite de requisições por minuto.
O corpo de todo erro é { "error": { "code", "message", "details"? } }. Veja todos os códigos.
Testar
Testar
O teste ao vivo usa a sua chave e a sua conta. Para quem não entrou, fica desligado.