# For agents (/docs/agents) This site is built to be consumed by AI agents as well as humans. ## Machine-readable resources [#machine-readable-resources] * [`/openapi.json`](/openapi.json) — the full OpenAPI 3.1 spec for the REST API. * [`/llms.txt`](/llms.txt) — an index of every docs page with title and URL. * [`/llms-full.txt`](/llms-full.txt) — the entire docs content as one markdown document. * Every guide page is also available as raw markdown at `/llms.mdx/docs//content.md` (use the copy-markdown button on any page). ## MCP server [#mcp-server] The backend exposes an [MCP](https://modelcontextprotocol.io) server at `/mcp` on the API origin, secured by OAuth. It offers deck creation, task polling, exports, and sharing as tools — the fastest way to integrate an agent without writing REST calls by hand. ## REST access [#rest-access] For direct REST calls, authenticate with a workspace API key as a Bearer token (see the [overview](/docs)) and follow the [API reference](/docs/api). The create → poll task → fetch export flow is the core loop. # Overview (/docs) The presentations.ai REST API lets you create, manage, and export presentation decks programmatically. Everything the API can do is described in the [API reference](/docs/api), generated from our [OpenAPI spec](/openapi.json). ## Base URL [#base-url] All endpoints live under `/api/v1` on your workspace's API origin. ## Authentication [#authentication] Requests are authenticated with a workspace API key passed as a Bearer token: ```bash curl "$PRESENTATIONSAI_BASE_URL/me" \ -H "Authorization: Bearer $PRES_API_KEY" ``` API keys are created and managed from your workspace settings, or via the [api-keys endpoints](/docs/api/api-keys). ## How generation works [#how-generation-works] Deck generation is asynchronous: create a deck with a caller request ID, then poll `/requests/{request_id}` for its status and current generation stage. The response always carries the request ID and deck ID; there is no separate task identifier in this REST workflow. Generation consumes workspace [credits](/docs/api/credits). ## Python CLI quickstart [#python-cli-quickstart] Install the isolated CLI, create a key in [workspace API-key settings](https://console.presentations.ai/api-keys), and save it in your OS credential store. Profiles never contain the token itself. ```bash uv tool install deckmaker deckmaker auth login deckmaker auth status ``` Generate an outline, edit its plain JSON, and create a deck from the reviewed outline. Outline and prompt workflows target 10 slides unless `--slides` is set. ```bash deckmaker create outline \ "Turn the source into a concise board update" \ --file ./quarterly-review.pdf \ --slides 8 \ --output ./reviewed-outline.json ${EDITOR:-vi} ./reviewed-outline.json deckmaker create deck \ --title "Quarterly customer review" \ --outline ./reviewed-outline.json \ --request-id quarterly-review-v1 \ --format pptx \ --output ./quarterly-review.pptx ``` The request ID is optional. When omitted, the CLI derives a stable ID so an identical retry is safe; pass `--new` when you intentionally want another copy. ```bash deckmaker create deck "Explain our launch plan" --slides 10 --format pdf deckmaker get status quarterly-review-v1 deckmaker list decks deckmaker get deck DECK_ID deckmaker get deck DECK_ID pptx --output ./deck.pptx deckmaker delete deck DECK_ID --yes ``` `get deck` prints the viewer link by default. Global flags work after leaf commands, for example `deckmaker create deck "Brief" --json`. Use `deckmaker --version`, `deckmaker update --check`, and `deckmaker update` to inspect and update the installed CLI. # CLI support (/docs/support) Run the following command to print the official support route and a safe diagnostic summary: ```bash deckmaker report-issue ``` Email [support@presentations.ai](mailto:support@presentations.ai) with: * the CLI and Python versions; * the command shape, with secrets and private source paths removed; * the error code and trace ID, when present; and * the operating system and whether the credential came from an environment variable or OS credential store. Never send an API key, authorization header, confidential source file, or full profile/state directory. API keys can be rotated from [workspace API-key settings](https://console.presentations.ai/api-keys). Use `deckmaker auth status` to validate the selected credential. Use `deckmaker auth logout --revoke` only when you intend to permanently revoke that key. # API reference (/docs/api) All endpoints live under `/api/v1` and authenticate with a workspace API key as a Bearer token (see the [overview](/docs)). The machine-readable spec is at [`/openapi.json`](/openapi.json). Browse by resource using the sidebar: start with [decks](/docs/api/decks) for creation and export, [requests](/docs/api/requests) for polling generation, and [credits](/docs/api/credits) for usage. ## Review an outline before rendering [#review-an-outline-before-rendering] Outline generation is stateless. Generate a typed outline, edit its JSON locally, then send the reviewed outline to the deck endpoint. The second request skips outline generation and runs the edited structure through slide rendering and export. ```bash curl -fsS "$PRESENTATIONSAI_BASE_URL/outlines" \ -H "Authorization: Bearer $PRES_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "prompt": "Turn the Q3 results into a concise board update", "slide_count": "8", "level_of_detail": "standard" }' \ | jq '.outline' > reviewed-outline.json ``` Edit `reviewed-outline.json`: reorder, add, remove, or rewrite slides while preserving the [`PresentationOutline`](/docs/api/decks) shape. Then wrap it in a deck request and submit it with a caller-owned request ID. ```bash jq '{ name: "Q3 customer review", outline: ., export_format: "PPTX" }' reviewed-outline.json > deck-request.json curl -i "$PRESENTATIONSAI_BASE_URL/decks" \ -H "Authorization: Bearer $PRES_API_KEY" \ -H "Content-Type: application/json" \ -H "Request-Id: q3-customer-review-v1" \ --data-binary @deck-request.json ``` The default response is `202 Accepted`. Poll its `status_url`; a successful terminal response has `status: "COMPLETED"` and a non-null `export.download_url`. Reusing the same `Request-Id` and body is safe. If the body changes, use a new versioned ID such as `q3-customer-review-v2`. ## Errors and asynchronous failures [#errors-and-asynchronous-failures] Every HTTP error uses the same envelope: ```json { "error": { "code": "NOT_FOUND", "message": "Deck not found.", "trace_id": "4bf92f3577b34da6a3ce929d0e0e4736" } } ``` Branch client behavior on `error.code`, not the human-readable message. The most important codes are: | Code | Meaning | Caller action | | ----------------------------------- | ----------------------------------------------------------- | ------------------------------------------------------------------- | | `VALIDATION_FAILED` | A path, query, header, or body field was rejected. | Read `error.details.errors` and fix the named fields. | | `UNAUTHENTICATED` / `INVALID_TOKEN` | The Bearer API key is absent or invalid. | Supply or rotate the key; do not retry unchanged credentials. | | `FORBIDDEN` / `FEATURE_NOT_IN_PLAN` | The key scope, role, project, or plan disallows the action. | Change authorization or plan; a retry alone will not help. | | `NOT_FOUND` | The resource is absent or outside the key's scope. | Check the ID and workspace/project scope. | | `SOURCES_NOT_READY` | Uploaded files are still being extracted. | Retry after extraction completes. | | `REQUEST_ID_CONFLICT` | The request ID was reused with different content. | Reuse the original body or increment the ID version. | | `INSUFFICIENT_CREDITS` | The workspace cannot fund generation. | Add credits before retrying. | | `RATE_LIMITED` | The current rate window is exhausted. | Wait until `Retry-After`; inspect the `X-RateLimit-*` headers. | | `UPSTREAM_ERROR` / `INTERNAL_ERROR` | A dependency or the service failed. | Retry only idempotent operations and retain `trace_id` for support. | A `202` response means the request was durably accepted, not that rendering succeeded. Generation failures are reported by the polled request resource as `status: "FAILED"`, `stage: "FAILED"`, and a sanitized `error` string. They are not later HTTP 5xx responses.