# Quickstart

> Create a stream, send a test picture with ffmpeg or OBS, and watch it in the hosted player. About five minutes.

You need an API key and a terminal. For step 3 you need either [ffmpeg](https://ffmpeg.org/download.html) or [OBS Studio](https://obsproject.com).

## 1. Set your API key

Create a key in the dashboard under **API keys** ([app.justonair.com](https://app.justonair.com)). It starts with `joa_live_` and is shown once.

```bash
export JOA_API_KEY="joa_live_..."
```

## 2. Create a stream

```bash
curl https://api.justonair.com/v1/streams \
  -H "Authorization: Bearer $JOA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"name": "My first stream"}'
```

The answer (shortened; the secrets are replaced here):

```json
{
  "id": "str_e1bzk3dxw9z9allei6n7",
  "object": "stream",
  "name": "My first stream",
  "status": "pending",
  "rtmp_url": "rtmp://ingest-1.justonair.com:1935/abr-basic",
  "stream_key": "str_e1bzk3dxw9z9allei6n7?key=...",
  "whip_url": "https://ingest-1.justonair.com:3334/abr-basic/str_e1bzk3dxw9z9allei6n7?direction=whip&key=...",
  "embed_url": "https://play.joacdn.com/str_e1bzk3dxw9z9allei6n7",
  "playback_url": "https://live.joacdn.com/bcdn_token=.../str_e1bzk3dxw9z9allei6n7/master.m3u8",
  "renditions": ["source", "480p"],
  "reservation_expires_in_seconds": 1800
}
```

> **Important:** `stream_key` and `whip_url` are returned only by this call. Keep them. If you lose them while the stream is still pending, [replace the key](/api-reference#replace-a-lost-stream-key).

The stream now waits up to 30 minutes for video. If nothing connects in that time it expires, and you create a new one.

## 3. Send video

### With ffmpeg (no camera needed)

This sends a moving test picture with a tone, at 720p, with the settings JustOnAir wants: H.264, a keyframe every 2 seconds, under 6 Mbps.

```bash
RTMP_URL="rtmp://ingest-1.justonair.com:1935/abr-basic"   # rtmp_url from step 2
STREAM_KEY="str_e1bzk3dxw9z9allei6n7?key=..."            # stream_key from step 2

ffmpeg -re \
  -f lavfi -i "testsrc2=size=1280x720:rate=30" \
  -f lavfi -i "sine=frequency=440:sample_rate=48000" \
  -c:v libx264 -preset veryfast -tune zerolatency -b:v 2500k \
  -g 60 -keyint_min 60 -sc_threshold 0 -pix_fmt yuv420p \
  -c:a aac -b:a 128k -ar 48000 \
  -f flv "$RTMP_URL/$STREAM_KEY"
```

Keep the quotes: the stream key contains a `?`.

### With OBS

In **Settings → Stream**, choose **Custom**, then:

| OBS field | Value |
|---|---|
| Server | `rtmp_url` |
| Stream Key | `stream_key` |

In **Settings → Output** (Advanced mode): Encoder x264 or your hardware H.264 encoder, Bitrate up to 6000 Kbps, **Keyframe Interval 2 s**. OBS's default of "0 (auto)" sends a keyframe only every 8 seconds or so, which makes quality switching stutter. Then press **Start Streaming**.

## 4. Watch it

Open `embed_url` in a browser. Before the video arrives it shows a waiting screen; it switches to the picture by itself, usually 10–20 seconds after you start sending. To put the player on a page:

```html
<iframe src="https://play.joacdn.com/str_e1bzk3dxw9z9allei6n7"
  allow="autoplay; fullscreen; picture-in-picture" allowfullscreen
  style="aspect-ratio:16/9;width:100%;border:0"></iframe>
```

## 5. Follow it and end it

```bash
curl https://api.justonair.com/v1/streams/str_e1bzk3dxw9z9allei6n7 \
  -H "Authorization: Bearer $JOA_API_KEY"
```

`status` becomes `live` as soon as the publisher is accepted. `ingest` shows what is arriving (size, bitrate, keyframe interval) and `cost` what the stream has cost so far.

To end it:

```bash
curl -X DELETE https://api.justonair.com/v1/streams/str_e1bzk3dxw9z9allei6n7 \
  -H "Authorization: Bearer $JOA_API_KEY"
```

The publisher is disconnected within seconds, viewers see the end screen, and a few minutes later `recording.status` is `ready`: [download the MP4](/recordings).

## Next

- [Sending video](/publishing): OBS, ffmpeg, hardware encoders and browsers.
- [The hosted player](/player): options, the stream name, sizing.
- [Your own player](/own-player): hls.js and short-lived links per viewer.
- [For AI agents](/agents): the same flow as tools an agent can call.
