---
title: "Turns a slideshow's storyboard into a story — one Dialogue node per slide, the slide as its background, the chosen presenter on the start node."
method: POST
path: "/api/script-assistant/sessions/{sessionId}/create-slideshow-story"
tags: ["ScriptAssistant"]
---

# Turns a slideshow's storyboard into a story — one Dialogue node per slide, the slide as its background, the chosen presenter on the start node.

`POST /api/script-assistant/sessions/{sessionId}/create-slideshow-story`

## Request

- Base URL: `https://api.wearelearning.io` (the document declares no server; this is the origin it was published from)
- URL: `https://api.wearelearning.io/api/script-assistant/sessions/{sessionId}/create-slideshow-story`
- Auth: OAuth 2
  - Implicit: `https://login.wearelearning.io/authorize?audience=https://api.wearelearning.io`

ITS OWN ROUTE, not a branch inside `create-story` above. The two answer different
questions with different shapes: that one builds synchronously from an outline and returns
the story, this one starts a build on the bus and returns a STATUS, because a deck can carry
a hundred slides at two Cosmos commands each — see `CreateSlideshowStory` for the
transport reasoning. Folding them together would also mean softening
`SlideshowStoryCreationRefusal`, which is the guard keeping a slideshow out of the
outline path in the first place.
            
200 FOR EVERY OUTCOME THAT IS NOT A REFUSAL, including the two that did not build anything:
a story that already exists (the double click, answered with its id) and one already being
built (the second tab). Both are the mechanism working, and both leave the caller with the
same next move the storyboard's poll would give it.
            
422 carries text meant for the user, which is why there is no failure-reason enum beside it.
Every refusal on this route — no presenter, a presenter who has left their slot, a deck still
rendering, slides whose images were deleted — is something the person pressing the button can
act on, and the message names the action. See `SlideshowStoryReadiness`, which holds the
same four clauses the client's own gate holds so the two cannot disagree.
            
GATED ON `DeckToSlideshow` AT THE ENDPOINT as well as in the handler, for the reason the
presenter route below gives: an action filter short-circuits before MediatR is entered, so
with the flag off this endpoint must not exist rather than 422 from a validator that has
already run its lookups.

## Path parameters

- `sessionId` string, required

## Response `200`

OK

- CreateSlideshowStoryResponseDto: What a slideshow's Create Story press answers with: where the session stands, and the story when one exists.
  - `storyCreationStatus` 'NotStarted' | 'InProgress' | 'Created', required
  - `simulationId` string, nullable: Set only for WeAreLearning.R2D2.Core.ScriptAssistant.Entities.SlideshowStoryCreationStatus.Created — a build that has just started has no simulation yet. Null is what tells the client to keep polling rather than navigate.
  - `storyCreationCompleted` boolean, required: Whether the story is FINISHED rather than merely created. The client opens the story only when this is true, and otherwise waits for the storyboard to report it — the same field, under the same name, as `StoryboardDto.StoryCreationCompleted`.
  - `storyCreationMissingSlideCount` integer, required: Slides a finished story is missing or has without a picture (WE-2694) - the same field, under the same name, as `StoryboardDto.StoryCreationMissingSlideCount`. Zero unless finished.
  - `message` string, required

## Other responses

- `401`: Unauthorized
- `403`: Forbidden
- `404`: Not Found
- `422`: Unprocessable Content

---

[API](https://skmtc.dev/wearelearning/apis/we-are-learning-api.md) - [All operations](https://skmtc.dev/wearelearning/apis/we-are-learning-api/llms.txt) - [OpenAPI document](https://skmtc.dev/wearelearning/apis/we-are-learning-api/revisions/e2ca5265db77?raw)
