<!-- Generated from openapi/v2.json (md/launch-clips.md) — do not edit. Run: npm run generate -->

[Interactive reference](https://api-docs.syllaby.io/) · [OpenAPI 3.1 spec](https://api-docs.syllaby.io/openapi/v2.json) · [Docs index (llms.txt)](https://api-docs.syllaby.io/llms.txt)

# Launch Clips

Create a 20-second launch video from an idea: supply a product name, domain, and idea — the API writes the creative brief, renders a 1080×1920 MP4, and you poll it to completion. Flat 5 credits per clip, refunded on failure.

## GET /launch-clips/estimate

**Estimate launch clip credits** (operationId: `estimateLaunchClipCredits`)

**Step 1 of 3 · Check the price (optional).**

Reports the flat charge for a launch clip against your balance. **Every clip costs exactly 5 credits** — the price does not vary with the idea, the brief, or the rendered length, so `data.total` always equals what `POST /launch-clips` will charge. Nothing is charged by this call.

→ **Next:** Step 2 — create the clip with `POST /launch-clips`.

### Response `200`

```json
{
  "message": "Success.",
  "status": 200,
  "data": {
    "total": 5
  },
  "meta": {
    "credits": {
      "cost": 5,
      "remaining": 95
    }
  }
}
```

### Errors

- `401` — Unauthenticated
- `403` — No active **paid** subscription. The v2 public API is paid-only — every faceless and preset endpoint (reads included) requires an active paid subscription, and trials are not eligible. Two codes distinguish the cause on this `403`: `PAID-SUBSCRIPTION-REQUIRED` (subscribed but on a trial — access unlocks automatically once the subscription becomes paid) and `SUBSCRIPTION-REQUIRED` (never subscribed, expired, or canceled). Rejected before any ownership, credit, or validation check. Only `GET /me`, `GET /credits/costs`, and `GET /credits/history` are reachable without a paid subscription.
- `405` — The URL exists but not for this HTTP method — e.g. `GET /presets/faceless/{preset}`, which is only defined for `PATCH` and `DELETE`. Check the verb against the endpoint reference; the `Allow` header lists the methods this path accepts.
- `409` — Email address not verified. The token is valid and the account exists, but the user has not confirmed their email address. This gate fronts every v2 endpoint. Have the user complete verification, then retry.
- `429` — Rate limit exceeded — requests are limited per API token (30 per minute by default). The response carries `Retry-After` (seconds to wait) and `X-RateLimit-Reset` (Unix timestamp when the window resets); back off until then and retry. Successful responses include `X-RateLimit-Limit` and `X-RateLimit-Remaining` so you can pace requests proactively.

Error shapes and examples are shared across endpoints — see the **Error responses** section in [getting-started](getting-started.md).

## GET /launch-clips

**List launch clips** (operationId: `listLaunchClips`)

Lists your launch clips, newest first — the list is owner-scoped, so you only ever see your own. Paginated. Poll individual in-flight clips with `GET /launch-clips/{id}` rather than re-fetching the list.

### Parameters

- `page` (query, integer) — Page number to fetch. Example: `1`
- `per_page` (query, integer) — Items per page (default 12, max 50). Example: `12`

### Response `200`

```json
{
  "message": "Success.",
  "status": 200,
  "data": [
    {
      "id": 42,
      "status": "rendering",
      "product_name": "Launchly",
      "domain": "getlaunchly.io",
      "idea": "A tool that turns a one-line product idea into a ready-to-post 20-second launch video.",
      "accent_color": "#7C3AED",
      "video": null,
      "credits": 5,
      "error": null,
      "created_at": "2026-08-18T12:00:00Z",
      "updated_at": "2026-08-18T12:00:00Z"
    },
    {
      "id": 41,
      "status": "completed",
      "product_name": "Launchly",
      "domain": "getlaunchly.io",
      "idea": "A tool that turns a one-line product idea into a ready-to-post 20-second launch video.",
      "accent_color": "#7C3AED",
      "video": {
        "id": 6,
        "title": "Launchly — launch clip",
        "url": "https://cdn.syllaby.dev/launch-clips/41/launch-clip.mp4"
      },
      "credits": 5,
      "error": null,
      "created_at": "2026-08-18T12:00:00Z",
      "updated_at": "2026-08-18T12:00:00Z"
    }
  ],
  "meta": {
    "current_page": 1,
    "last_page": 1,
    "per_page": 12,
    "total": 2
  }
}
```

### Errors

- `401` — Unauthenticated
- `403` — No active **paid** subscription. The v2 public API is paid-only — every faceless and preset endpoint (reads included) requires an active paid subscription, and trials are not eligible. Two codes distinguish the cause on this `403`: `PAID-SUBSCRIPTION-REQUIRED` (subscribed but on a trial — access unlocks automatically once the subscription becomes paid) and `SUBSCRIPTION-REQUIRED` (never subscribed, expired, or canceled). Rejected before any ownership, credit, or validation check. Only `GET /me`, `GET /credits/costs`, and `GET /credits/history` are reachable without a paid subscription.
- `405` — The URL exists but not for this HTTP method — e.g. `GET /presets/faceless/{preset}`, which is only defined for `PATCH` and `DELETE`. Check the verb against the endpoint reference; the `Allow` header lists the methods this path accepts.
- `409` — Email address not verified. The token is valid and the account exists, but the user has not confirmed their email address. This gate fronts every v2 endpoint. Have the user complete verification, then retry.
- `429` — Rate limit exceeded — requests are limited per API token (30 per minute by default). The response carries `Retry-After` (seconds to wait) and `X-RateLimit-Reset` (Unix timestamp when the window resets); back off until then and retry. Successful responses include `X-RateLimit-Limit` and `X-RateLimit-Remaining` so you can pace requests proactively.

Error shapes and examples are shared across endpoints — see the **Error responses** section in [getting-started](getting-started.md).

## POST /launch-clips

**Create a launch clip** (operationId: `createLaunchClip`)

**Step 2 of 3 · Create.**

💳 **Charges a flat 5 credits.** The response `meta.credits` reports the charge and your remaining balance.

Creates a 20-second, 1080×1920 launch video from three inputs: the `product_name`, the `domain` to show as the call-to-action, and the `idea` in your own words. The API writes the creative brief (hook, benefits, CTA) from the idea and renders the MP4 — no script, voice, or media required. An optional `accent_color` pins the brand color.

Returns `201` immediately with the clip in a **`planning`** state; briefing and rendering run asynchronously.

**To track progress:** poll `GET /launch-clips/{id}` with the **`id` from this response**, every 5–10 seconds. If briefing or rendering fails, the 5-credit charge is refunded automatically.

Insufficient balance is rejected with `402` before anything is queued; a plan that does not include launch clips is a `403` with code `FEATURE-NOT-ALLOWED`.

→ **Next:** Step 3 — track progress by polling `GET /launch-clips/{id}` with the `id` from this response.

### Request body

Required. The product name, domain, and idea for the clip, plus an optional accent color.

- `product_name` (string, required) — Name of the product the clip announces — up to 40 characters, rendered verbatim in the clip.
- `domain` (string, required) — Domain rendered as the clip's call-to-action (e.g. "getlaunchly.io") — up to 60 characters. It is rendered as text, never fetched or validated for reachability.
- `idea` (string, required) — What the product does, in your own words — 10 to 500 characters. The API writes the clip's creative brief (hook, benefits, call-to-action) from this.
- `accent_color` (string) — Optional brand accent color as a `#RRGGBB` hex value (e.g. "#7C3AED"). Omit to let the renderer pick a palette from the brief.

Example request:

```json
{
  "product_name": "Launchly",
  "domain": "getlaunchly.io",
  "idea": "A tool that turns a one-line product idea into a ready-to-post 20-second launch video.",
  "accent_color": "#7C3AED"
}
```

### Response `201`

```json
{
  "message": "Success.",
  "status": 201,
  "data": {
    "id": 42,
    "status": "planning",
    "product_name": "Launchly",
    "domain": "getlaunchly.io",
    "idea": "A tool that turns a one-line product idea into a ready-to-post 20-second launch video.",
    "accent_color": "#7C3AED",
    "video": null,
    "credits": 5,
    "error": null,
    "created_at": "2026-08-18T12:00:00Z",
    "updated_at": "2026-08-18T12:00:00Z"
  },
  "meta": {
    "credits": {
      "cost": 5,
      "remaining": 95
    }
  }
}
```

### Errors

- `401` — Unauthenticated
- `402` — Insufficient credits — `error.required` and `error.available` carry the figures. The cost is a flat 5 credits per clip.
- `403` — Forbidden — two distinct causes share this status: 1. **No active subscription** (code `SUBSCRIPTION-REQUIRED`, message "An active subscription is required.") — checked first by the active-subscription gate, before any other logic. The v2 public API has no free tier. 2. **Feature not on the plan** (code `FEATURE-NOT-ALLOWED`) — the subscription is active but launch clips are not included in the current plan.
- `405` — The URL exists but not for this HTTP method — e.g. `GET /presets/faceless/{preset}`, which is only defined for `PATCH` and `DELETE`. Check the verb against the endpoint reference; the `Allow` header lists the methods this path accepts.
- `409` — Email address not verified. The token is valid and the account exists, but the user has not confirmed their email address. This gate fronts every v2 endpoint. Have the user complete verification, then retry.
- `422` — Validation error
- `429` — Rate limit exceeded — requests are limited per API token (30 per minute by default). The response carries `Retry-After` (seconds to wait) and `X-RateLimit-Reset` (Unix timestamp when the window resets); back off until then and retry. Successful responses include `X-RateLimit-Limit` and `X-RateLimit-Remaining` so you can pace requests proactively.

Error shapes and examples are shared across endpoints — see the **Error responses** section in [getting-started](getting-started.md).

## GET /launch-clips/{id}

**Get a launch clip** (operationId: `getLaunchClip`)

**Step 3 of 3 · Track progress.**

Returns a single launch clip you own — this is the polling endpoint. Use the **`id` from the create response**; polling every 5–10 seconds is plenty.

`status` is the field to branch on — match these **exact strings**: `planning` (the creative brief is being written) → `briefed` (brief ready, render queued) → `rendering` (the MP4 is being composed) → terminal `completed` (then, and only then, `video` is non-null and the MP4 is at `video.url`) or `failed` (`error` carries the reason and the charge has been refunded automatically).

Responds with a uniform `404` when the id does not exist, belongs to another account, is not a launch clip, or is not numeric.

→ **Done** when `data.status` is `completed` — the MP4 is at `data.video.url`. On `failed`, the 5-credit charge is auto-refunded; adjust the idea and create again.

### Parameters

- `id` (path, integer, required) — Identifier of the launch clip — the `id` field from the create response. Example: `42`

### Response `200`

```json
{
  "message": "Success.",
  "status": 200,
  "data": {
    "id": 42,
    "status": "completed",
    "product_name": "Launchly",
    "domain": "getlaunchly.io",
    "idea": "A tool that turns a one-line product idea into a ready-to-post 20-second launch video.",
    "accent_color": "#7C3AED",
    "video": {
      "id": 7,
      "title": "Launchly — launch clip",
      "url": "https://cdn.syllaby.dev/launch-clips/42/launch-clip.mp4"
    },
    "credits": 5,
    "error": null,
    "created_at": "2026-08-18T12:00:00Z",
    "updated_at": "2026-08-18T12:00:00Z"
  }
}
```

### Errors

- `401` — Unauthenticated
- `403` — No active **paid** subscription. The v2 public API is paid-only — every faceless and preset endpoint (reads included) requires an active paid subscription, and trials are not eligible. Two codes distinguish the cause on this `403`: `PAID-SUBSCRIPTION-REQUIRED` (subscribed but on a trial — access unlocks automatically once the subscription becomes paid) and `SUBSCRIPTION-REQUIRED` (never subscribed, expired, or canceled). Rejected before any ownership, credit, or validation check. Only `GET /me`, `GET /credits/costs`, and `GET /credits/history` are reachable without a paid subscription.
- `404` — Not found — returned uniformly when the id does not exist, belongs to another account, is not a launch clip, or is not numeric. The response never distinguishes those cases.
- `405` — The URL exists but not for this HTTP method — e.g. `GET /presets/faceless/{preset}`, which is only defined for `PATCH` and `DELETE`. Check the verb against the endpoint reference; the `Allow` header lists the methods this path accepts.
- `409` — Email address not verified. The token is valid and the account exists, but the user has not confirmed their email address. This gate fronts every v2 endpoint. Have the user complete verification, then retry.
- `429` — Rate limit exceeded — requests are limited per API token (30 per minute by default). The response carries `Retry-After` (seconds to wait) and `X-RateLimit-Reset` (Unix timestamp when the window resets); back off until then and retry. Successful responses include `X-RateLimit-Limit` and `X-RateLimit-Remaining` so you can pace requests proactively.

Error shapes and examples are shared across endpoints — see the **Error responses** section in [getting-started](getting-started.md).
