---
title: "Create a stream (optionally with its first schema version and sources)"
method: POST
path: "/v1/streams"
tags: ["streams"]
---

# Create a stream (optionally with its first schema version and sources)

`POST /v1/streams`

## Request

- Base URL: `https://postbag.dev`
- URL: `https://postbag.dev/v1/streams`
- Auth: HTTP bearer

A Stream collects Submissions from many Forms into one shared shape. Pass `schema` to define that shape up front, or omit it and pass `sources` — the first source's form then provides version 1 (copied from its published schema, its inferred draft, or the fields seen in recent submissions) with an identity mapping, so `{ name, sources: [{ form_id }] }` is a complete request.

## Request body

- object
  - `name` string
  - `slug` string
  - `schema` object
    - `json_schema` object, required: JSON Schema draft 2020-12 describing the submission data. `required` drives drift detection and mapping completeness.
    - `ui` object: Per-field rendering hints keyed by field name (label, placeholder, widget, options, order) — used to render embed snippets.
    - `changelog` string: A short human note on what changed in this version, shown in the version history.
  - `sources` object[]
    - `form_id` string: One Form feeding this Stream. Mutually exclusive with `selector`.
    - `selector` string: A dynamic Form source: non-empty `tag:<tag>` or `project:<project_id>` without leading or trailing whitespace after `:`. Mutually exclusive with `form_id`.
    - `mapping` object: Keyed by the stream schema's field names. Each entry is exactly one of `from` (copy a field from the form's data), `const` (a fixed value) or `expr` (a JSONata expression), plus an optional `default`. Every required field in the stream's schema must be covered or this call fails 422 mapping_incomplete.
  - `if_exists` 'error' | 'return'

## Response `201`

created

- Stream
  - `id` string, required
  - `slug` string, required
  - `name` string, required
  - `current_schema_version` integer, nullable, required
  - `counts` object, required
    - `sources` integer, required
    - `routes` integer, required
    - `submissions_30d` integer, required
  - `created_at` string, required

## Other responses

- `400`: Error
- `401`: Error
- `403`: Error
- `404`: Not found
- `409`: Error
- `422`: Error

---

[API](https://skmtc.dev/postbag/apis/postbag-api.md) · [All operations](https://skmtc.dev/postbag/apis/postbag-api/llms.txt) · [OpenAPI document](https://skmtc.dev/postbag/apis/postbag-api/revisions/3da976524695?raw)
