# SDK and CLI

> The npm packages @praeko/sdk (JavaScript client) and @praeko/cli (the praeko command): install with npm, yarn, pnpm or bun, quick start, safe retries with idempotencyKey and commands.

Source: https://praeko.app/docs/en/sdk

Node 22 or newer · No dependencies · ESM only

Two packages on npm: `@praeko/sdk`, to call the API from your code, and `@praeko/cli`, the `praeko` command in your terminal.

## Install

### SDK, in your project

**npm**

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

**yarn**

```bash
yarn add @praeko/sdk
```

**pnpm**

```bash
pnpm add @praeko/sdk
```

**bun**

```bash
bun add @praeko/sdk
```

### CLI, in your terminal

**npm**

```bash
npm install -g @praeko/cli
```

**yarn**

```bash
yarn global add @praeko/cli
```

**pnpm**

```bash
pnpm add -g @praeko/cli
```

**bun**

```bash
bun add -g @praeko/cli
```

**Without installing the CLI**

```bash
npx @praeko/cli --help
pnpm dlx @praeko/cli --help
bunx @praeko/cli --help
yarn dlx @praeko/cli --help   # yarn 2 or newer
```

The SDK has no dependencies, ships TypeScript types and runs on Node 22 or newer, Cloudflare Workers, Deno, Bun and in the browser. The CLI is published with the SDK bundled in, so there is nothing else to install. The only command is `praeko`.

## SDK quick start

Create an API key in the panel (or with `praeko key create`) and keep it in `PRAEKO_KEY`. Never put the key in your source code or in the browser.

**JavaScript (Node)**

```js
import { Praeko } from "@praeko/sdk";
import { uploadFile } from "@praeko/sdk/node"; // Node only: uploads the file from disk in parts

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

const video = await uploadFile(praeko, "./video.mp4", { type: "video", onProgress: (done, total) => {} });
const post = await praeko.posts.create({
  title: "My video",
  media: { video: video.id },
  texts: { youtube: { title: "My video", text: "Video description" } },
  items: [{ network: "youtube", queue: true }],
});
console.log(post.id);
```

Outside Node (Workers, browser), pass a `Uint8Array`, a `Blob` or `{ size, read(start, n) }` to `praeko.media.upload(source, { type, name, mime })`. The upload picks a single request or several parts by size on its own. In the browser, on the same origin as the panel, use `{ cookies: true }` instead of the key.

## Retries and safe repeats

| Call | Retries by itself on network failure, `429` and `5xx`? |
|---|---|
| `GET` and media part uploads | Yes, up to 3 attempts (change it with `retries`). |
| `POST`, `PATCH` and `DELETE` | No, so nothing is duplicated. With the `idempotencyKey` option, yes: the SDK resends with the same key. |

**Create a post without risking a duplicate**

```js
// true: the SDK generates a UUID and reuses it on every attempt of this call
const post = await praeko.posts.create({ title, media: { video: video.id }, texts, items }, { idempotencyKey: true });

// or choose the key yourself, for example one from your own job
await praeko.webhooks.create({ url: "https://example.com/hooks/praeko", idempotencyKey: `hook-${jobId}` });
```

See the header rules in [Retry a request safely](https://praeko.app/docs/en/guides/idempotency). Errors become a `PraekoError`, with `status`, `code` (stable, in English), `message` and `details`:

**Errors**

```js
import { PraekoError } from "@praeko/sdk";
try { await praeko.posts.get("nao-existe"); }
catch (e) { if (e instanceof PraekoError && e.code === "not_found") { /* … */ } else throw e; }
```

The routes and the error codes are also typed in `@praeko/sdk/contract` (`ROUTES`, `ERROR_CODES`).

## CLI commands

Point the CLI at the service with `--server https://praeko.app` (or `PRAEKO_SERVER`) and give the key in `PRAEKO_KEY`. Nothing is sent, hosted or scheduled without `--send`: without it, `post` only simulates. The CLI messages are in English (CLI 0.4.0).

| Command | Does |
|---|---|
| `praeko post <folder> --queue`, `--when …` or `--draft` | Creates a post from a folder with `publication.json`, the video and the cover (needs a `praeko.json` in the current folder or above). Simulates unless you pass `--send`. |
| `praeko posts` | Lists posts by `--state`, `--channel`, `--tag`, `--limit`. |
| `praeko calendar` | Scheduled items and free slots, with `--from` and `--to`. |
| `praeko slots <network> [day time …]` | Shows or replaces the weekly slots. |
| `praeko publish-now <id> [--idempotency-key K]` | Takes the post out of the queue and publishes now. The key prevents publishing twice if you run the command again. |
| `praeko channels` | What is connected. |
| `praeko insights` | Metrics, with `--days`, `--channel`, `--compare`, `--json`. |
| `praeko content` | Everything already published. |
| `praeko youtube videos`, `edit`, `comments`, `reply` | Channel videos, title and description edits, unanswered comments and replies. Edits and replies simulate until `--send`. |
| `praeko key create`, `list`, `revoke` | API keys (needs an admin key). |
| `praeko webhook list`, `create --url … [--idempotency-key K]`, `test`, `deliveries`, `retry` | Outgoing webhooks, admin scope. The secret is shown once. |
| `praeko usage` and `praeko usage log` | API usage and the request log of the last 30 days. |
| `praeko help` | The full list, with every option. |

**Terminal**

```bash
export PRAEKO_KEY="praeko_…"
export PRAEKO_SERVER="https://praeko.app"

praeko --version
praeko channels
praeko post ./my-video --queue          # simulates
praeko post ./my-video --queue --send   # schedules for real
```

Exit codes: `0` success; `1` error (message in English on stderr); `2` invalid command or argument (prints the help). The CLI does not retry on its own: `--idempotency-key` is for whoever runs the command again, for example in a script with retries.

## Key and environment variables

| Variable | What it does |
|---|---|
| `PRAEKO_KEY` | The API key. |
| `PRAEKO_SERVER` | The service address, `https://praeko.app`. Replaces `--server`. |
| `PRAEKO_SECRETS` | A different path for the secrets file (the default is `~/.config/praeko/secrets.json`, mode 600). |
| `PRAEKO_NO_KEYCHAIN` | `1` ignores the macOS Keychain. |

Without `PRAEKO_KEY`, the CLI looks for the key in the macOS Keychain (Mac only) and in the secrets file. On Linux and Windows, the variable and the file apply.

## Versions

[SemVer](https://semver.org/). While the version is `0.x`, a breaking change can ship in a minor version, and each one is listed in the `CHANGELOG.md` of the package. `praeko studio` hands over to [Praeko Studio](https://praeko.app/docs/en/studio) (`@praeko/studio`), installed separately.

> **Old names** The `arauto` command left the package in CLI 0.1.1: use `praeko` (if you used 0.1.0 you can run `npx -p @praeko/cli praeko`). Since CLI 0.4.0 (11/08/2026) the CLI accepts only English commands, options and files (`publication.json`, `PRAEKO_SECRETS`, `PRAEKO_NO_KEYCHAIN`; see the [changelog](https://praeko.app/docs/en/changelog)); the `ARAUTO_CHAVE` variable is still read, and `Arauto` remains an alias in the SDK. The Portuguese names in the SDK (`chave`, `enviarArquivo`…) are deprecated aliases and will be removed in a future version.
