Story0.API

Guides

Composed workflows

Practical recipes for clip intake, editorial review, story delivery and live alerts, with explicit costs and human decisions.

Build the workflow your product needs from a few stable objects. Upload once, request specific operations, collect immutable results through jobs, and preserve the human decision separately. No workspace provisioning or customer-specific preset is required.

Choose the smallest useful workflow

Need Compose Your application owns
Route a large incoming library Upload → screening → selected assessment Category policy and which clips merit more spend
Explain whether a clip fits an editorial brief Upload → assessment → producer review Versioned criteria and final editorial decision
Produce a captioned news package Ready assets + article → story revision → preview → approval → delivery Source rights, article accuracy and the producer approving the preview
Detect candidate moments in a live feed HLS/pushed windows → analysis jobs → signed events → review queue Alert policy, handling gaps and deciding whether repeated observations describe the same event
Reprocess an existing archive Ready asset → analysis or segmentation → your search/index Storage after retention and how results are queried

Each arrow into a paid operation is an explicit request with its own cap. Reading results, listing windows or receiving a retried webhook does not start more inference.

Intake and editorial triage

Keep your own external record ID in metadata. Use screening for inexpensive routing, then call assessment only when the screening warrants it. A missing match means “this operation found no match,” not “this clip is cleared.”

ts
import Story0 from "@story0/sdk";

const story0 = new Story0();
const assetId = process.env.STORY0_ASSET_ID!; // ready asset from your ingest
const screening = await story0.screenings.createAndWait({
  input: { asset_id: assetId },
  categories: [
    { key: "clear_action", description: "A visible action with a clear subject and outcome." },
  ],
  billing: { max_charge: { currency: "USD", amount: "0.10" } },
});

if (screening.matched.includes("clear_action")) {
  const assessment = await story0.assessments.createAndWait({
    input: { asset_id: assetId },
    playback_policy: "sound_off",
    criteria: [
      { key: "clear_action", description: "The central action is understandable without audio.", severity: "major", remediable: false },
      { key: "concise_opening", description: "The clip opens with useful action rather than extended empty footage.", severity: "minor", remediable: true },
    ],
    metadata: { policy_version: "editorial-v1" },
    billing: { max_charge: { currency: "USD", amount: "0.75" } },
  });
  console.log(assessment.disposition, assessment.review, assessment.criteria);
  // Store these in your producer's review queue; publication is a separate decision.
}

The caps are examples, not price quotes for every duration. Ask POST /v1/estimates for the operation and media length before committing a larger batch. A low cap prevents paid execution instead of silently increasing your spend.

Analyze once, apply several criteria sets

Call analyses.createAndWait with an asset, instruction, playback policy, sampling and range. Then assess the same asset with those same analysis settings and your criteria. A compatible, unexpired analysis in the same account can be reused while the assessment judgment remains a new operation. The receipt is authoritative for what was charged.

Keep instructions stable when you intend reuse. Changing the editorial question, sound policy, sampling or source range changes the analysis configuration. Reuse is content- and configuration-based, not a promise that every operation shares the same internal log.

Story preparation needs additional per-source speech and framing information for edits and crops. A generic analysis followed by a story can therefore require an additional pass. A story's source logs are reused across its variants where valid. Do not budget story preparation as a free conversion of an analysis result.

Prepare a story, then review what will be delivered

Send your ready source assets and an article to POST /v1/stories. The article grounds factual captions; the footage supplies visual evidence and source cuts. Configure a neutral style, language/aspect variants and an explicit soundtrack policy.

  1. Wait for the preparation job and fetch its immutable revision.
  2. Inspect facts, caption references, source cuts and checks. Apply structured edits for exact changes, or a charge-capped instruction for a broader revision.
  3. Request a preview render for the revision and variant you intend to deliver.
  4. Have the producer inspect the actual preview artifact and record approval bound to that revision, variant and preview.
  5. Request final delivery using that approval. Retrieve the package and save it in your own media repository before expiry.

An approval for an older revision does not approve later edits. Final delivery never publishes to a social account or newsroom system automatically. See Stories for the exact requests and artifacts.

Live editorial alerts

Create a stream with a bounded source duration and mandatory session cap. Receive job.succeeded, branch on data.job.operation === "stream_window", and use data.job.stream to locate its source window. Fetch the analysis and add candidate events to your review queue.

Store the webhook event ID before acknowledging delivery. Keep session ID, window ID, sequence, epoch and evidence offsets with each candidate. Use GET /v1/streams/{id}/windows to reconcile missed or reordered events. For pushed windows, only advance your checkpoint over contiguous sequence numbers.

Use stream.gap to mark coverage your product cannot claim. A failed window or unknown-duration gap should remain visible alongside successful observations. Neither silence nor stream.ended proves that the stream contained no event of interest.

For RTMP, SRT, RTSP or WebRTC, retain your existing ingest gateway and push complete ready chunks. Direct DASH and partial LL-HLS are not accepted by this release. See the supported matrix and gateway example.

Start safely in test mode

Run the same orchestration with a test key. Results are visibly labelled fixtures, stream sessions produce a bounded sequence, and webhook delivery still exercises signatures and retries. Switch to a short authorized live source when you are ready to inspect actual evidence, quality and latency. Test and live objects and subscriptions are isolated.

Persist the job ID immediately after admission. Reuse an idempotency key only for the same intended action. If your service restarts, resume the existing job instead of creating another operation. See Jobs and results, Idempotency and Webhooks.