Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 14 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ Commands you run in a terminal check for a newer version at most once a day, whi
Workspace commands need an Excalidraw+ API key. The [authentication docs](https://plus.excalidraw.com/docs/api/authentication) explain how to create one.

```bash
export EXCALIDRAW_API_KEY="your_api_key"
# Paste your API key once; later commands use it
excalidraw login

# Check which workspace the key belongs to
excalidraw whoami
Expand Down Expand Up @@ -87,7 +88,9 @@ Rendering uses a browser that's already installed: Chrome, Edge or Chromium, or

| Command | What it does |
| --- | --- |
| `whoami` | Show the workspace, key type and API origin in use |
| `login` | Check an API key and save it for later commands |
| `logout` | Remove the saved API key |
| `whoami` | Show the workspace, key type, credential source and API origin in use |
| `scenes` | List, create, rename, move, pin and trash scenes |
| `scenes content` | Read, replace or patch a scene's drawing |
| `scenes render` | Render a workspace scene to PNG |
Expand Down Expand Up @@ -119,7 +122,8 @@ echo '{"appState":{"viewBackgroundColor":"#f8f9fa"}}' | excalidraw scenes conten

## Scripting and agents

- Commands print JSON. `-o table` prints list commands, `whoami` and `update` as a table.
- Commands print JSON, except `login` and `logout`, which print a confirmation. `-o table` prints list commands, `whoami` and `update` as a table.
- Set `EXCALIDRAW_API_KEY` rather than running `login`, which asks for the key in a terminal. `excalidraw login --api-key <key>` saves a key without asking.
- Lists return 5 items by default (50 for logs), up to 100 with `--limit`. `--all` fetches every page.
- `--raw` prints the API's response text as received, and shows API errors in full.
- `-` as a file path reads from stdin for inputs (`render -`, `--file -`) and writes to stdout for `--out`.
Expand All @@ -133,7 +137,7 @@ These flags can also be set with environment variables.

| Flag | Environment variable | Default |
| --- | --- | --- |
| `--api-key` | `EXCALIDRAW_API_KEY` | |
| `--api-key` | `EXCALIDRAW_API_KEY` | key saved by `login` |
| `--api-url` | `EXCALIDRAW_API_URL` | `https://api.excalidraw.com` |
| `-o, --output` | `EXCALIDRAW_OUTPUT` | `json` |
| `--retries` | `EXCALIDRAW_RETRIES` | `3` |
Expand All @@ -143,8 +147,14 @@ These flags can also be set with environment variables.

For a self-hosted or staging instance, set `--api-url` to the origin, without `/api/v1`.

### API keys

There are two kinds of API key. Workspace keys act for the whole workspace. They can't see private scenes, so `scenes create` needs a real collection ID. Personal keys start with `uk-` and act as one user, with that user's role. They can pass `private` as the collection ID to use the owner's private collection. Run `excalidraw whoami` to see which kind you're using.

`excalidraw login` asks how to sign in (an API key for now; OAuth is coming), checks the key against the API and saves it. A key the API rejects isn't saved. Commands use the saved key when neither `--api-key` nor `EXCALIDRAW_API_KEY` is set; `whoami` reports which one is in use as `credentialSource` (`flag`, `env` or `login`).

Keys are saved per API origin, so a staging key is only sent to staging: `excalidraw login --api-url https://staging.example.com` saves one next to your production key. They live in `~/.config/excalidraw-cli/credentials.json` (`$XDG_CONFIG_HOME` if set, `%APPDATA%` on Windows), readable only by you. `excalidraw logout` removes the key for the origin; to revoke the key itself, delete it in Excalidraw+.

The full API reference lives at [plus.excalidraw.com/docs/api](https://plus.excalidraw.com/docs/api).

## Contributing
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"playwright-core": "1.63.0"
},
"devDependencies": {
"@clack/prompts": "1.8.1",
"@excalidraw/utils": "0.1.5",
"@types/node": "^22.19.3",
"@types/pngjs": "^6.0.5",
Expand Down
47 changes: 47 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 11 additions & 4 deletions src/cli.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Command, Option } from "commander";
import { registerCollectionsCommands } from "./commands/collections.js";
import { registerLoginCommands } from "./commands/login.js";
import { registerLogsCommands } from "./commands/logs.js";
import { registerScenesCommands } from "./commands/scenes.js";
import { registerWhoamiCommand } from "./commands/whoami.js";
Expand All @@ -24,7 +25,11 @@ export function createProgram() {
"EXCALIDRAW_API_URL",
),
)
.addOption(new Option("--api-key <key>", "API key").env("EXCALIDRAW_API_KEY"))
.addOption(
new Option("--api-key <key>", 'API key; overrides the key "excalidraw login" saved').env(
"EXCALIDRAW_API_KEY",
),
)
.addOption(
new Option(
"-o, --output <format>",
Expand Down Expand Up @@ -54,6 +59,7 @@ export function createProgram() {
"after",
`
EXAMPLES
$ excalidraw login
$ excalidraw whoami
$ excalidraw scenes list --limit 25
$ excalidraw scenes list --all --output table
Expand All @@ -64,10 +70,10 @@ EXAMPLES
$ excalidraw logs list --operation update --limit 10

SETUP
Set EXCALIDRAW_API_KEY for non-interactive use, or pass --api-key per command.
Run "excalidraw login" once to save an API key. In scripts and CI, set EXCALIDRAW_API_KEY or pass --api-key instead; both take precedence over the saved key.
Local "render" commands do not require an API key.
Use --api-url for development, staging, or self-hosted API origins. Pass the origin only; /api/v1 is added automatically.
Run "excalidraw whoami" to confirm which workspace and key type the CLI is using.
Use --api-url for development, staging, or self-hosted API origins. Pass the origin only; /api/v1 is added automatically. Saved keys are per origin.
Run "excalidraw whoami" to confirm which workspace, key type and credential source the CLI is using.

OUTPUT
Commands print formatted JSON by default. Use --output table for readable lists, or --raw for the raw API response text.
Expand Down Expand Up @@ -98,6 +104,7 @@ LEARN MORE
styleArgumentTerm: helpTheme.argument,
});

registerLoginCommands(program);
registerWhoamiCommand(program);
registerScenesCommands(program);
registerRenderCommand(program);
Expand Down
6 changes: 5 additions & 1 deletion src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { z } from "zod/v4";
import { DEFAULT_REQUEST_TIMEOUT_MS, DEFAULT_RETRIES, resolveConfig } from "./config.js";

import type { Command } from "commander";
import type { GlobalOptions } from "./config.js";

const ErrorResponseSchema = z
.object({
Expand Down Expand Up @@ -208,7 +209,10 @@ function encodePathId(id: string) {
}

export function getClient(command: Command) {
const config = resolveConfig(command.optsWithGlobals());
return createClient(resolveConfig(command));
}

export function createClient(config: GlobalOptions & { apiKey: string }) {
return new PublicApiClient(config.apiUrl, config.apiKey, {
retries: config.retries,
timeout: config.requestTimeout,
Expand Down
Loading