> For the complete documentation index, see [llms.txt](https://docs.twistly.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.twistly.ai/api/presentations.md).

# Presentations

Submit generation jobs and poll for results.

## Create a presentation from a topic

> You have a topic or idea — the AI writes the content. Queues a generation job and returns \`202 Accepted\` with the job descriptor.<br>

```json
{"openapi":"3.1.0","info":{"title":"Twistly Presentation Generation API","version":"1.0.0"},"tags":[{"name":"Presentations","description":"Submit generation jobs and poll for results."}],"servers":[{"url":"https://api.appsdowonders.com","description":"Production"}],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"ppsk_ API key","description":"Recommended. Pass your API key (starts with `ppsk_`) as `Authorization: Bearer ppsk_…`. One active key per Pro/Team account — to rotate, revoke the old one first.\n"},"apiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"Alternative to bearer auth. Pass your `ppsk_` key in the `x-api-key` header."}},"schemas":{"TopicRequest":{"type":"object","required":["topic"],"properties":{"topic":{"type":"string","maxLength":450,"description":"Subject of the presentation."},"numSlides":{"$ref":"#/components/schemas/NumSlides"},"language":{"type":"string","description":"Output language. Defaults to auto-detect."},"template":{"$ref":"#/components/schemas/Template"},"format":{"$ref":"#/components/schemas/OutputFormat"},"imageSource":{"$ref":"#/components/schemas/ImageSource"},"imageStyle":{"$ref":"#/components/schemas/ImageStyle"},"content":{"$ref":"#/components/schemas/ContentVerbosity","description":"Text verbosity. Defaults to `detailed`."},"presentationType":{"$ref":"#/components/schemas/PresentationType"},"targetAudience":{"type":"string","maxLength":200,"description":"Free-text audience description."},"toneAndStyle":{"type":"string","maxLength":200,"description":"Free-text tone/style description."},"debugMode":{"type":"boolean","default":false,"description":"Internal diagnostics."}},"additionalProperties":false},"NumSlides":{"type":"integer","description":"Slide count: `-1` for auto, or `1`–`50`. `0` is invalid.","oneOf":[{"const":-1,"description":"Automatic slide count."},{"minimum":1,"maximum":50}],"default":-1},"Template":{"type":"string","description":"Design theme id (case-sensitive, no spaces). Custom user-uploaded templates are not supported via the public API.","enum":["Tokyo","NewYork","Seoul","Rome","Berlin","Copenhagen","Oslo","Rotterdam","Cambridge","Houston"],"default":"Tokyo"},"OutputFormat":{"type":"string","description":"Output file format.","enum":["pptx","pdf"],"default":"pptx"},"ImageSource":{"type":"string","description":"Where slide images come from. `unsplash`/`pexels`/`scrapingdog` are stock; `ai`/`flux` are AI-generated.","enum":["unsplash","pexels","scrapingdog","ai","flux"],"default":"unsplash"},"ImageStyle":{"type":"string","description":"Image style. Applies only when `imageSource` is `ai` or `flux`.","enum":["auto","photorealistic","illustration","neon","abstract","black-and-white","3d","linear"]},"ContentVerbosity":{"type":"string","description":"Text verbosity of the generated slides.","enum":["short","detailed","bulletPoints"]},"PresentationType":{"type":"string","enum":["General","Educational Project","Business Pitch","Reports and Insights"]},"JobAccepted":{"type":"object","description":"Job descriptor returned by all POST endpoints.","required":["id","status","createdAt"],"properties":{"id":{"type":"string","format":"uuid"},"status":{"$ref":"#/components/schemas/JobStatus"},"createdAt":{"type":"string","format":"date-time"}}},"JobStatus":{"type":"string","enum":["queued","processing","completed","failed"]},"ErrorResponse":{"type":"object","description":"Uniform error envelope for all 4xx/5xx responses.","required":["error"],"properties":{"error":{"type":"object","required":["code","message","status"],"properties":{"code":{"type":"string","enum":["BAD_REQUEST","UNAUTHORIZED","FORBIDDEN","NOT_FOUND","UNPROCESSABLE_ENTITY","RATE_LIMIT_EXCEEDED","INTERNAL_SERVER_ERROR"]},"message":{"type":"string","description":"Human-readable message. For invalid enum fields, lists the allowed values.\n"},"status":{"type":"integer","description":"HTTP status code mirrored in the body."},"request_id":{"type":"string","description":"Present only on 5xx — include in support tickets."}},"additionalProperties":true}}}},"responses":{"JobAccepted":{"description":"Job queued. Poll `GET /v1/presentations/{id}` for the result.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobAccepted"}}}},"BadRequest":{"description":"Missing or invalid parameters (also unsupported file MIME type).","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"Unauthorized":{"description":"API key missing or wrong.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"Forbidden":{"description":"Feature not available on your plan.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"UnprocessableEntity":{"description":"Validation passed but the request can't be processed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"RateLimitExceeded":{"description":"Too many requests. Buckets: 60 writes/min, 600 reads/min per key. Wait `x-ratelimit-reset` milliseconds and retry.\n","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"InternalServerError":{"description":"Server-side failure — retry, and include `request_id` when reporting.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"paths":{"/v1/presentations/topic":{"post":{"tags":["Presentations"],"operationId":"createPresentationFromTopic","summary":"Create a presentation from a topic","description":"You have a topic or idea — the AI writes the content. Queues a generation job and returns `202 Accepted` with the job descriptor.\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TopicRequest"}}}},"responses":{"202":{"$ref":"#/components/responses/JobAccepted"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/RateLimitExceeded"},"500":{"$ref":"#/components/responses/InternalServerError"}}}}}}
```

## Create a presentation from raw text

> You already have text and want it turned into slides. The output language always matches the source language. If the text exceeds the token limit (390,000 tokens, measured with the \`gpt-3.5-turbo\` tokenizer), the API responds \`400 BAD\_REQUEST\` with \`tokensCount\` and \`tokenLimit\` in the error body.<br>

```json
{"openapi":"3.1.0","info":{"title":"Twistly Presentation Generation API","version":"1.0.0"},"tags":[{"name":"Presentations","description":"Submit generation jobs and poll for results."}],"servers":[{"url":"https://api.appsdowonders.com","description":"Production"}],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"ppsk_ API key","description":"Recommended. Pass your API key (starts with `ppsk_`) as `Authorization: Bearer ppsk_…`. One active key per Pro/Team account — to rotate, revoke the old one first.\n"},"apiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"Alternative to bearer auth. Pass your `ppsk_` key in the `x-api-key` header."}},"schemas":{"TextRequest":{"type":"object","required":["text"],"properties":{"text":{"type":"string","description":"Source text. Maximum 390,000 tokens, measured with the `gpt-3.5-turbo` tokenizer. Exceeding the limit returns `400 BAD_REQUEST` with `tokensCount` and `tokenLimit` in the error body.\n"},"numSlides":{"$ref":"#/components/schemas/NumSlides"},"template":{"$ref":"#/components/schemas/Template"},"format":{"$ref":"#/components/schemas/OutputFormat"},"contentModificator":{"$ref":"#/components/schemas/ContentModificator"},"textDensity":{"$ref":"#/components/schemas/TextDensity"},"verbosity":{"$ref":"#/components/schemas/ContentVerbosity"},"imageSource":{"$ref":"#/components/schemas/ImageSource"},"imageStyle":{"$ref":"#/components/schemas/ImageStyle"},"debugMode":{"type":"boolean","default":false}},"additionalProperties":false},"NumSlides":{"type":"integer","description":"Slide count: `-1` for auto, or `1`–`50`. `0` is invalid.","oneOf":[{"const":-1,"description":"Automatic slide count."},{"minimum":1,"maximum":50}],"default":-1},"Template":{"type":"string","description":"Design theme id (case-sensitive, no spaces). Custom user-uploaded templates are not supported via the public API.","enum":["Tokyo","NewYork","Seoul","Rome","Berlin","Copenhagen","Oslo","Rotterdam","Cambridge","Houston"],"default":"Tokyo"},"OutputFormat":{"type":"string","description":"Output file format.","enum":["pptx","pdf"],"default":"pptx"},"ContentModificator":{"type":"string","description":"How the source content is treated when building slides.","enum":["preserve","expand","condense"],"default":"expand"},"TextDensity":{"type":"string","description":"Density of text on each slide.","enum":["minimal","concise","detailed"],"default":"concise"},"ContentVerbosity":{"type":"string","description":"Text verbosity of the generated slides.","enum":["short","detailed","bulletPoints"]},"ImageSource":{"type":"string","description":"Where slide images come from. `unsplash`/`pexels`/`scrapingdog` are stock; `ai`/`flux` are AI-generated.","enum":["unsplash","pexels","scrapingdog","ai","flux"],"default":"unsplash"},"ImageStyle":{"type":"string","description":"Image style. Applies only when `imageSource` is `ai` or `flux`.","enum":["auto","photorealistic","illustration","neon","abstract","black-and-white","3d","linear"]},"JobAccepted":{"type":"object","description":"Job descriptor returned by all POST endpoints.","required":["id","status","createdAt"],"properties":{"id":{"type":"string","format":"uuid"},"status":{"$ref":"#/components/schemas/JobStatus"},"createdAt":{"type":"string","format":"date-time"}}},"JobStatus":{"type":"string","enum":["queued","processing","completed","failed"]},"TextTokenLimitError":{"allOf":[{"$ref":"#/components/schemas/ErrorResponse"},{"type":"object","properties":{"error":{"type":"object","properties":{"tokensCount":{"type":"integer","description":"Token count of the submitted text."},"tokenLimit":{"type":"integer","description":"Maximum allowed tokens (390,000)."}}}}}]},"ErrorResponse":{"type":"object","description":"Uniform error envelope for all 4xx/5xx responses.","required":["error"],"properties":{"error":{"type":"object","required":["code","message","status"],"properties":{"code":{"type":"string","enum":["BAD_REQUEST","UNAUTHORIZED","FORBIDDEN","NOT_FOUND","UNPROCESSABLE_ENTITY","RATE_LIMIT_EXCEEDED","INTERNAL_SERVER_ERROR"]},"message":{"type":"string","description":"Human-readable message. For invalid enum fields, lists the allowed values.\n"},"status":{"type":"integer","description":"HTTP status code mirrored in the body."},"request_id":{"type":"string","description":"Present only on 5xx — include in support tickets."}},"additionalProperties":true}}}},"responses":{"JobAccepted":{"description":"Job queued. Poll `GET /v1/presentations/{id}` for the result.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobAccepted"}}}},"BadRequestText":{"description":"Missing or invalid parameters, or text exceeds the 390,000-token limit.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TextTokenLimitError"}}}},"Unauthorized":{"description":"API key missing or wrong.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"Forbidden":{"description":"Feature not available on your plan.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"UnprocessableEntity":{"description":"Validation passed but the request can't be processed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"RateLimitExceeded":{"description":"Too many requests. Buckets: 60 writes/min, 600 reads/min per key. Wait `x-ratelimit-reset` milliseconds and retry.\n","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"InternalServerError":{"description":"Server-side failure — retry, and include `request_id` when reporting.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"paths":{"/v1/presentations/text":{"post":{"tags":["Presentations"],"operationId":"createPresentationFromText","summary":"Create a presentation from raw text","description":"You already have text and want it turned into slides. The output language always matches the source language. If the text exceeds the token limit (390,000 tokens, measured with the `gpt-3.5-turbo` tokenizer), the API responds `400 BAD_REQUEST` with `tokensCount` and `tokenLimit` in the error body.\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TextRequest"}}}},"responses":{"202":{"$ref":"#/components/responses/JobAccepted"},"400":{"$ref":"#/components/responses/BadRequestText"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/RateLimitExceeded"},"500":{"$ref":"#/components/responses/InternalServerError"}}}}}}
```

## Create a presentation from a document

> Upload a PDF, PPTX, DOCX, or TXT (max 25 MB) and queue a generation job. File types are validated via magic-byte sniffing — extension spoofing is rejected. The output language always matches the source language. Note: in \`multipart/form-data\` every field arrives as a string; the API coerces \`numSlides\` and \`debugMode\`.<br>

```json
{"openapi":"3.1.0","info":{"title":"Twistly Presentation Generation API","version":"1.0.0"},"tags":[{"name":"Presentations","description":"Submit generation jobs and poll for results."}],"servers":[{"url":"https://api.appsdowonders.com","description":"Production"}],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"ppsk_ API key","description":"Recommended. Pass your API key (starts with `ppsk_`) as `Authorization: Bearer ppsk_…`. One active key per Pro/Team account — to rotate, revoke the old one first.\n"},"apiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"Alternative to bearer auth. Pass your `ppsk_` key in the `x-api-key` header."}},"schemas":{"FileRequest":{"type":"object","required":["file"],"description":"multipart/form-data body. All non-file fields arrive as strings; the API coerces `numSlides` and `debugMode`.\n","properties":{"file":{"type":"string","format":"binary","description":"Source document, max 25 MB. Accepted types (validated via magic-byte sniffing): PDF (`application/pdf`), PowerPoint (`application/vnd.openxmlformats-officedocument.presentationml.presentation`), Word (`application/vnd.openxmlformats-officedocument.wordprocessingml.document`), plain text (`text/plain`).\n"},"numSlides":{"type":"string","description":"Slide count as a string: `-1` for auto, or `1`–`50`."},"template":{"$ref":"#/components/schemas/Template"},"format":{"$ref":"#/components/schemas/OutputFormat"},"contentModificator":{"$ref":"#/components/schemas/ContentModificator"},"textDensity":{"$ref":"#/components/schemas/TextDensity"},"verbosity":{"$ref":"#/components/schemas/ContentVerbosity"},"imageSource":{"$ref":"#/components/schemas/ImageSource"},"imageStyle":{"$ref":"#/components/schemas/ImageStyle"},"debugMode":{"type":"string","enum":["true","false"],"default":"false","description":"Boolean as string in form-data."}}},"Template":{"type":"string","description":"Design theme id (case-sensitive, no spaces). Custom user-uploaded templates are not supported via the public API.","enum":["Tokyo","NewYork","Seoul","Rome","Berlin","Copenhagen","Oslo","Rotterdam","Cambridge","Houston"],"default":"Tokyo"},"OutputFormat":{"type":"string","description":"Output file format.","enum":["pptx","pdf"],"default":"pptx"},"ContentModificator":{"type":"string","description":"How the source content is treated when building slides.","enum":["preserve","expand","condense"],"default":"expand"},"TextDensity":{"type":"string","description":"Density of text on each slide.","enum":["minimal","concise","detailed"],"default":"concise"},"ContentVerbosity":{"type":"string","description":"Text verbosity of the generated slides.","enum":["short","detailed","bulletPoints"]},"ImageSource":{"type":"string","description":"Where slide images come from. `unsplash`/`pexels`/`scrapingdog` are stock; `ai`/`flux` are AI-generated.","enum":["unsplash","pexels","scrapingdog","ai","flux"],"default":"unsplash"},"ImageStyle":{"type":"string","description":"Image style. Applies only when `imageSource` is `ai` or `flux`.","enum":["auto","photorealistic","illustration","neon","abstract","black-and-white","3d","linear"]},"JobAccepted":{"type":"object","description":"Job descriptor returned by all POST endpoints.","required":["id","status","createdAt"],"properties":{"id":{"type":"string","format":"uuid"},"status":{"$ref":"#/components/schemas/JobStatus"},"createdAt":{"type":"string","format":"date-time"}}},"JobStatus":{"type":"string","enum":["queued","processing","completed","failed"]},"ErrorResponse":{"type":"object","description":"Uniform error envelope for all 4xx/5xx responses.","required":["error"],"properties":{"error":{"type":"object","required":["code","message","status"],"properties":{"code":{"type":"string","enum":["BAD_REQUEST","UNAUTHORIZED","FORBIDDEN","NOT_FOUND","UNPROCESSABLE_ENTITY","RATE_LIMIT_EXCEEDED","INTERNAL_SERVER_ERROR"]},"message":{"type":"string","description":"Human-readable message. For invalid enum fields, lists the allowed values.\n"},"status":{"type":"integer","description":"HTTP status code mirrored in the body."},"request_id":{"type":"string","description":"Present only on 5xx — include in support tickets."}},"additionalProperties":true}}}},"responses":{"JobAccepted":{"description":"Job queued. Poll `GET /v1/presentations/{id}` for the result.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobAccepted"}}}},"BadRequest":{"description":"Missing or invalid parameters (also unsupported file MIME type).","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"Unauthorized":{"description":"API key missing or wrong.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"Forbidden":{"description":"Feature not available on your plan.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"UnprocessableEntity":{"description":"Validation passed but the request can't be processed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"RateLimitExceeded":{"description":"Too many requests. Buckets: 60 writes/min, 600 reads/min per key. Wait `x-ratelimit-reset` milliseconds and retry.\n","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"InternalServerError":{"description":"Server-side failure — retry, and include `request_id` when reporting.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"paths":{"/v1/presentations/file":{"post":{"tags":["Presentations"],"operationId":"createPresentationFromFile","summary":"Create a presentation from a document","description":"Upload a PDF, PPTX, DOCX, or TXT (max 25 MB) and queue a generation job. File types are validated via magic-byte sniffing — extension spoofing is rejected. The output language always matches the source language. Note: in `multipart/form-data` every field arrives as a string; the API coerces `numSlides` and `debugMode`.\n","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/FileRequest"},"encoding":{"file":{"contentType":"application/pdf, application/vnd.openxmlformats-officedocument.presentationml.presentation, application/vnd.openxmlformats-officedocument.wordprocessingml.document, text/plain"}}}}},"responses":{"202":{"$ref":"#/components/responses/JobAccepted"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/RateLimitExceeded"},"500":{"$ref":"#/components/responses/InternalServerError"}}}}}}
```

## Get job status and result

> Check the status of a generation job and, once \`status\` is \`completed\`, fetch the permanent download URL from \`result.url\`. Jobs are owner-scoped: a job is only visible to the API key that created it. Recommended polling cadence: every 2–3 seconds (read limit is 600 req/min per key).<br>

```json
{"openapi":"3.1.0","info":{"title":"Twistly Presentation Generation API","version":"1.0.0"},"tags":[{"name":"Presentations","description":"Submit generation jobs and poll for results."}],"servers":[{"url":"https://api.appsdowonders.com","description":"Production"}],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"ppsk_ API key","description":"Recommended. Pass your API key (starts with `ppsk_`) as `Authorization: Bearer ppsk_…`. One active key per Pro/Team account — to rotate, revoke the old one first.\n"},"apiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"Alternative to bearer auth. Pass your `ppsk_` key in the `x-api-key` header."}},"schemas":{"Job":{"type":"object","required":["id","status","createdAt"],"properties":{"id":{"type":"string","format":"uuid"},"status":{"$ref":"#/components/schemas/JobStatus"},"createdAt":{"type":"string","format":"date-time"},"completedAt":{"type":"string","format":"date-time","description":"Present only when `status` is `completed` or `failed`."},"result":{"type":"object","description":"Present only when `status` is `completed`.","required":["url"],"properties":{"url":{"type":"string","format":"uri","description":"Permanent download URL for the generated PPTX/PDF."}}},"error":{"type":"object","description":"Present only when `status` is `failed`.","required":["code","message"],"properties":{"code":{"$ref":"#/components/schemas/JobErrorCode"},"message":{"type":"string","description":"Human-readable failure reason."}}}}},"JobStatus":{"type":"string","enum":["queued","processing","completed","failed"]},"JobErrorCode":{"type":"string","description":"Job-level failure codes:\n- `TIMEOUT` — generation exceeded the soft timeout\n- `WORKER_TIMEOUT` — worker aborted the job (default 5 min)\n- `UPSTREAM_FAILURE` — underlying AI/build pipeline failed; retry\n- `UNSUPPORTED_TEMPLATE` — custom (user-uploaded) templates are not supported via the public API\n- `INPUT_TOO_LARGE` — source content exceeded internal processing limits\n","enum":["TIMEOUT","WORKER_TIMEOUT","UPSTREAM_FAILURE","UNSUPPORTED_TEMPLATE","INPUT_TOO_LARGE"]},"ErrorResponse":{"type":"object","description":"Uniform error envelope for all 4xx/5xx responses.","required":["error"],"properties":{"error":{"type":"object","required":["code","message","status"],"properties":{"code":{"type":"string","enum":["BAD_REQUEST","UNAUTHORIZED","FORBIDDEN","NOT_FOUND","UNPROCESSABLE_ENTITY","RATE_LIMIT_EXCEEDED","INTERNAL_SERVER_ERROR"]},"message":{"type":"string","description":"Human-readable message. For invalid enum fields, lists the allowed values.\n"},"status":{"type":"integer","description":"HTTP status code mirrored in the body."},"request_id":{"type":"string","description":"Present only on 5xx — include in support tickets."}},"additionalProperties":true}}}},"responses":{"Unauthorized":{"description":"API key missing or wrong.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"NotFound":{"description":"Job id not found, or owned by another API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"RateLimitExceeded":{"description":"Too many requests. Buckets: 60 writes/min, 600 reads/min per key. Wait `x-ratelimit-reset` milliseconds and retry.\n","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"InternalServerError":{"description":"Server-side failure — retry, and include `request_id` when reporting.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"paths":{"/v1/presentations/{id}":{"get":{"tags":["Presentations"],"operationId":"getPresentationJob","summary":"Get job status and result","description":"Check the status of a generation job and, once `status` is `completed`, fetch the permanent download URL from `result.url`. Jobs are owner-scoped: a job is only visible to the API key that created it. Recommended polling cadence: every 2–3 seconds (read limit is 600 req/min per key).\n","parameters":[{"name":"id","in":"path","required":true,"description":"Job id returned by a `POST /v1/presentations/*` endpoint.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Job descriptor with current status.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Job"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"},"500":{"$ref":"#/components/responses/InternalServerError"}}}}}}
```
