---
title: "Build the submission packet."
method: POST
path: "/story-projects/{projectId}/deliverables/{deliverableId}/export"
tags: ["Projects"]
---

# Build the submission packet.

`POST /story-projects/{projectId}/deliverables/{deliverableId}/export`

## Request

- Base URL: `https://docs.sleeperhit.studio/api/v1`
- URL: `https://docs.sleeperhit.studio/api/v1/story-projects/{projectId}/deliverables/{deliverableId}/export`
- Auth: HTTP bearer

Build the submission packet for the deliverable. Both outcomes come back as 200 data: `{ ok: true, packet }` or `{ ok: false, reason }` — a refusal is a plain reason in the body, never an empty packet. Optional listing fields: `demoRecordingUrl`, `countries`, `releaseNotes`, `commerce`, `commerceDescription`, carried into the packet as given (nothing fetches the recording URL). It writes nothing, so it needs only story:read.

## Request body

- VideoDeliverableExportRequest: Optional listing material folded into the packet. Every field is optional; `commerce: false` is recorded as false, not omitted.
  - `demoRecordingUrl` string: The reviewer-accessible walkthrough URL (a share page or a hosted recording) — the packet's `review.demo_recording_url`.
  - `countries` string[]: The publication countries — the packet's `publication.countries`.
  - `releaseNotes` string: The publication release notes — the packet's `publication.release_notes`.
  - `commerce` boolean: Whether the listing sells anything — the packet's `review.commerce`.
  - `commerceDescription` string: What it sells — the packet's `review.commerce_description`.

## Response `200`

The packet, or the plain reason no packet was built.

- union: Both outcomes are 200 data. A refusal is a plain reason in the body, never an empty packet.
  - object
    - `ok` unknown, required
    - `packet` OpenAiPacket, required: The submission packet, in the destination submission field reference's own spelling (snake_case, unchanged).
      - `review` OpenAiReview, required
        - `test_cases` object, required: The script's cases in script order, positive first, each polarity in its own list.
          - `positive` OpenAiTestCase[], required
            - `description` string, required
            - `prompt` string, required
            - `tools_triggered` string: A single comma-and-space joined string of the tools the prompt must trigger.
            - `expected_behavior` string
            - `file_attachment_urls` string[]
            - `expected_output_url` string
          - `negative` OpenAiNegativeTestCase[], required
            - `description` string, required
            - `prompt` string, required
        - `demo_recording_url` string
        - `commerce` boolean
        - `commerce_description` string
      - `publication` object, required
        - `release_notes` string
        - `countries` string[]
  - object
    - `ok` unknown, required
    - `reason` string, required: Why no packet was built, in plain words.

## Other responses

- `400`: Request payload failed validation. The error message names the offending field.
- `401`: Missing, malformed, revoked, or expired API key.
- `403`: API key is valid but lacks the scope, is blocked by IP allowlist, or the account is disabled.
- `404`: The named project or source does not exist or is owned by another account.
- `429`: Rate limit for this API key + IP + route family was exceeded.
- `500`: The API failed unexpectedly. Safe to retry with the same Idempotency-Key.

---

[API](https://skmtc.dev/sleeperhit/apis/sleeper-hit-studio-story-api.md) · [All operations](https://skmtc.dev/sleeperhit/apis/sleeper-hit-studio-story-api/llms.txt) · [OpenAPI document](https://skmtc.dev/sleeperhit/apis/sleeper-hit-studio-story-api/revisions/4534f5d25540?raw)
