Create Slide

Generate an AI-powered slide deck from a prompt and receive edit/preview URLs. Designed for autonomous agents.

POST /v1/platform/slides

Creates a slide-deck request. The AI generates a structured TipTap-based deck (with image placeholders that auto-resolve when the editor opens), uploads the content to S3, and returns edit and preview URLs.

The endpoint is fully self-contained: one POST returns everything an agent needs to either hand the deck off to a human (previewUrl) or render a public landing page (publicUrl). No follow-up calls are required for the happy path.

Agent Quick Reference

You want…Call thisResult
A finished deck right nowPOST /slides with mode: "sync"Response in 15–40 s with both URLs
To kick off generation in the backgroundPOST /slides with mode: "async"Returns immediately. Poll GET /slides/:id
Idempotent retry safetyAdd Idempotency-Key headerSame key returns the original response
To edit the deck programmaticallyUse editToken from the responseSee Edit by Token
To export to PowerPointPOST /slides/edit/:editToken/pptxReturns S3 URL of the .pptx file
To regenerate a single imagePOST /slides/edit/:editToken/generate/imageReturns S3 key for the new image

Request Body

FieldTypeRequiredDescription
promptstringYesPrompt describing the deck to generate. Specific prompts produce better decks (include audience, tone, key facts).
titlestringNoOverride the AI-generated title.
descriptionstringNoOverride the AI-generated description.
languagestringNoOutput language (default: en). Use ISO 639-1 codes such as en, ko, ja, zh-CN.
slideCountnumberNoTarget number of slides (1–100, default: 10). The AI may produce slightly fewer if the topic is narrow.
themestringNoVisual theme hint (e.g. modern, minimal, dark). Affects styling tokens applied to the deck.
tierstringNoAccepted for backwards compatibility but has no effect on price (single-tier pricing post-v2).
modestringNosync (default) or async. See Async Mode.
idempotencyKeystringNoPrevents duplicate processing. Can also be sent as Idempotency-Key HTTP header.

Pricing

The Slide API is billed per slide for the base creation flow. AI image generation is an optional sub-event billed independently when invoked via the image-generation endpoint — most slides are text-only, so customers pay only for what they actually generate.

EventEndpointPrice
Base slide generationPOST /slides (per slide)$0.03 / slide
AI image generationPOST /slides/edit/.../generate/image$0.07 / image

Slide content is generated as a single HTML blob, not N rows; the slideCount parameter is the requested target and serves as the billable unit count for the base creation event.

The priceSnapshot on the create response covers only the base creation. Each call to the image-generation endpoint produces its own PlatformUsageRecord row with a slide_image priceSnapshot.

Legacy tier field: still accepted but has no effect on price.

Example Request

curl -X POST https://api.tutorflow.io/v1/platform/slides \
  -H "Authorization: Bearer tf_platform_..." \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "Introduction to the Mediterranean diet for adults: foods, health benefits, and a sample weekly meal plan",
    "language": "en",
    "slideCount": 6
  }'

Response Fields

FieldTypeDescription
idstringSlide request ID. Use this to poll, list, or refresh.
slideIdstring | nullInternal slide content ID. null until generation completes.
statusstringPENDING, PROCESSING, COMPLETED, or FAILED.
isTerminalbooleantrue once status is COMPLETED or FAILED. Stop polling.
titlestring | nullAI-generated or overridden title.
descriptionstring | nullShort summary of the deck.
languagestring | nullOutput language (echoed).
themestring | nullVisual theme (echoed).
slideCountnumber | nullNumber of slides actually produced.
slugstring | nullURL-friendly slug.
tierstringPricing tier used.
modestring | nullsync or async.
priceSnapshotobject | nullPricing details captured at request time.
shareTokenstring | nullPermanent token for the public read-only URL.
editTokenstring | nullHourly-rotating token used by the editor and edit-time mutations.
editTokenExpiresAtstring | nullISO 8601 timestamp the current editToken expires at. Refresh by calling any GET /v1/platform/slides/edit/:editToken route — expiry is extended automatically (sliding window).
previewUrlstring | nullEditor URL — /{locale}/platform/slides/edit/{editToken}. Anyone with the link can edit without logging in.
publicUrlstring | nullPublic read-only viewer — /{locale}/platform/slides/{shareToken}. Permanent.
pollAfterMsnumber | nullSuggested polling interval (async only).
idempotencyKeystring | nullEchoed idempotency key.
idempotentReplayboolean | nulltrue if this is a replay, false for a fresh request, null when no key was supplied.
createdAtstringISO 8601 timestamp.
completedAtstring | nullISO 8601 timestamp generation finished.

Example Response

{
  "id": "61f1b111-0df3-4de3-a83f-d4b10304949d",
  "slideId": "669b977b-0007-40b9-8339-2b4e1d8e7c8e",
  "status": "COMPLETED",
  "isTerminal": true,
  "title": "The Mediterranean Diet, Explained",
  "description": "A 6-slide overview of the Mediterranean diet's foods, health benefits, and a one-week meal plan.",
  "language": "en",
  "theme": null,
  "slideCount": 6,
  "slug": "the-mediterranean-diet-explained-1602dc2c",
  "tier": "default",
  "mode": "sync",
  "priceSnapshot": {
    "category": "slide",
    "catalogKey": "slide.default",
    "tier": "default",
    "unit": "slide",
    "unitPrice": 0.03,
    "units": 6,
    "amountUsd": 0.18,
    "currency": "USD",
    "source": "platform_pricing_catalog_v2"
  },
  "shareToken": "fda025e5ea364bf30ea46671582d6859",
  "editToken": "187d1d98e7cfe5190da4e2cc24bbf65d",
  "editTokenExpiresAt": "2026-04-25T14:14:40.890Z",
  "previewUrl": "https://tutorflow.io/en/platform/slides/edit/187d1d98e7cfe5190da4e2cc24bbf65d",
  "publicUrl": "https://tutorflow.io/en/platform/slides/fda025e5ea364bf30ea46671582d6859",
  "idempotencyKey": null,
  "idempotentReplay": null,
  "createdAt": "2026-04-25T04:14:15.756Z",
  "completedAt": "2026-04-25T04:14:40.940Z",
  "pollAfterMs": null
}

Preview URL vs Public URL

URLPurposeAuthExpiry
previewUrlEditor — change title, content, outline, regenerate images, export PPTXNone (token-gated)editToken extends on each access; effectively never expires while you keep using it
publicUrlPublic read-only viewerNonePermanent

The previewUrl is the link you hand to a human reviewer or paste into a chat reply. Opening it loads a full TipTap editor with image placeholders that auto-fill when first viewed.

Image Generation in the Editor

AI-generated decks contain <img data-prompt="..." data-auto-image-id="..."> placeholders. When a human (or your own headless browser) opens the editor for the first time, each placeholder triggers a call to:

POST /v1/platform/slides/edit/:editToken/generate/image

The image generator calls Gemini, uploads the result to a workspace-scoped S3 path, and patches the <img> node in place. The editor handles this for you — you do not need to call the endpoint manually unless you want to regenerate a specific image.

To regenerate manually:

curl -X POST https://api.tutorflow.io/v1/platform/slides/edit/{editToken}/generate/image \
  -H "Content-Type: application/json" \
  -d '{
    "content": "Olive oil, fresh vegetables, and whole grains arranged on a wooden board",
    "aspectRatio": "3:4",
    "imageStyle": "photorealistic"
  }'
FieldTypeRequiredDescription
contentstringYes (or prompt)Slide text content used to derive an image prompt automatically.
promptstringNoExplicit prompt. Overrides content-based derivation.
aspectRatiostringNo21:9, 3:4, 1:1, etc. Defaults based on layout.
isInfographicbooleanNoGenerates an infographic-style image when true.
themeNamestringNoTheme hint passed to the image prompt builder.
imageStylestringNodefault, photorealistic, minimalist, isometric.

Response:

{ "data": [{ "key": "platform/{workspaceId}/slides/{slideId}/images/...png" }] }

Use the returned key with the STORAGE URL prefix (see Authentication) to display the image.

PPTX Export

Convert any deck to a downloadable .pptx file:

curl -X POST https://api.tutorflow.io/v1/platform/slides/edit/{editToken}/pptx \
  -H "Content-Type: application/json" \
  -d '{
    "html": "<slide>...</slide><slide>...</slide>",
    "theme": { "backgroundColor": "#ffffff", "textColor": "#0f172a", "...": "..." }
  }'

The endpoint reuses the same PPTX builder as the classroom slide editor. The html field is the rendered slide HTML — typically captured from the editor DOM. Captured base64 images can also be supplied via capturedImages, capturedMathImages, and capturedContentImages fields for high-fidelity export of charts and math.

Response:

{
  "url": "https://{bucket}.s3.{region}.amazonaws.com/platform/{workspaceId}/slides/{slideId}/pptx/1714060000.pptx",
  "key": "platform/{workspaceId}/slides/{slideId}/pptx/1714060000.pptx"
}

The URL is publicly readable. Stream it to the user or store the key for later retrieval.

Edit Token API

The edit URL provides access to these public endpoints (no API key needed):

MethodPathDescription
GET/v1/platform/slides/edit/:editTokenGet slide content (TipTap JSON), title, outline, metadata.
PATCH/v1/platform/slides/edit/:editTokenUpdate title, description, outline, theme, content, thumbnail, visibility, metadata.
POST/v1/platform/slides/edit/:editToken/generate/imageGenerate a single AI image.
POST/v1/platform/slides/edit/:editToken/pptxExport the deck to PowerPoint.

Update Slide

curl -X PATCH https://api.tutorflow.io/v1/platform/slides/edit/{editToken} \
  -H "Content-Type: application/json" \
  -d '{
    "title": "The Mediterranean Diet — Updated",
    "outline": "1. Foundations\n2. Daily Habits\n3. Weekly Plan"
  }'
FieldTypeDescription
titlestringUpdated deck title.
descriptionstring | nullUpdated description.
outlinestring | nullPlain-text outline (markdown supported).
themestringVisual theme.
contentstringFull TipTap content (JSON string). Server uploads to S3 and bumps contentVersion.
thumbnailstring | nullThumbnail HTML snippet (rendered first slide).
visibilitystringPUBLIC or PRIVATE.
metadataobjectFree-form metadata.

Response is the full SlideEditResDto — see Get Slide for the shape.

Async Mode

Set mode: "async" to queue generation as a background job. The response returns immediately with status: "PENDING" and a pollAfterMs value. Poll GET /v1/platform/slides/:id until isTerminal is true.

Idempotency

Pass an idempotencyKey in the request body or Idempotency-Key header to prevent duplicate slide generation. Reusing the same key returns the original response with idempotentReplay: true.