Streams API
A stream is one broadcast. Book it (now or for later), point an encoder at its ingest address, start it, and end it. A stream is billed per minute from when it starts to when it ends, with a 15-minute minimum.
This page is generated from the OpenAPI specification; the same text is inMarkdown for tools and AI assistants.
List streams
GET/v1/streams
Your streams, newest booked first. Page with limit and before:
pass the previous page’s next_before as before until it is absent.
The ingest key is never in a list.
Query parameters
| Name | Type | Description |
|---|---|---|
| state | string | Only streams in this state. One of |
| customer_ref | string | Only this customer’s streams. |
| recording_state | string | Only streams whose recording is in this state (as you would see it, so a ready recording past its 30 days is One of |
| limit | integer | Page size, 1-200. Default 50; more than 200 is treated as 200. |
| before | string (date-time) | The previous page’s |
Response 200
A page of streams.
Fields
| Name | Type | Description |
|---|---|---|
| streamsrequired | array of object | |
| streams[].playback_idrequired | string | The stream’s public id. Unguessable. |
| streams[].customer_refrequired | string | Your identifier for a customer. 1-128 letters, digits, |
| streams[].titlerequired | string | |
| streams[].tierrequired | string |
One of |
| streams[].staterequired | string | One of |
| streams[].scheduled_start_at | string (date-time) | When a booking starts itself. |
| streams[].started_at | string (date-time) | |
| streams[].ended_at | string (date-time) | |
| streams[].unit_rate_usd_per_hour | number | The stream-hour rate, fixed when it started. |
| streams[].restream_unit_rate_usd_per_hour | number | The destination-hour rate, fixed when it started. |
| streams[].leg_countrequired | integer | How many independent encodings the stream runs. |
| streams[].legs_readyrequired | integer | How many are encoding now. |
| streams[].legs | array of object | Each encoding’s state, while the stream is not over. |
| streams[].legs[].rankrequired | integer | |
| streams[].legs[].staterequired | string | One of |
| streams[].legs[].ready_since | string (date-time) | |
| streams[].recordingrequired | object | |
| streams[].recording.staterequired | string | One of |
| streams[].recording.bytes | integer (int64) | |
| streams[].recording.duration_seconds | number | |
| streams[].recording.ready_at | string (date-time) | |
| streams[].ingest | object | Where an encoder sends the stream: RTMPS (RTMP inside TLS) on port 443. Ingest is encrypted only; plain RTMP is not accepted. The srt_ fields appear only where SRT is offered, and SRT is encrypted too: one passphrase per stream, shown with the key. |
| streams[].ingest.key | string | The ingest key. Only when it was just created or rotated. |
| streams[].ingest.server_url | string | The RTMPS server, for an encoder’s Server field. |
| streams[].ingest.stream_key | string | The stream key, for the encoder’s Stream Key field. Only with |
| streams[].ingest.srt_url | string | Only where SRT is offered. The whole SRT address for one-field encoders: stream ID, passphrase and AES-256. Only with |
| streams[].ingest.srt_server | string | Only where SRT is offered. The SRT server, srt://host:port. Not a secret. |
| streams[].ingest.srt_stream_id | string | Only where SRT is offered. publish:live/<playback_id>: names the broadcast, carries no key. Not a secret. |
| streams[].ingest.srt_passphrase | string | Only where SRT is offered. The stream’s SRT passphrase: the encoder encrypts with it, and anything unencrypted or on another passphrase is refused. Only with |
| streams[].ingest.endpointsrequired | array of string | Every RTMPS address the stream accepts. |
| streams[].ingest.fanout_requiredrequired | boolean | Whether the encoder must push to every endpoint for full redundancy. |
| streams[].encoder_connectedrequired | boolean | Whether video is arriving from an encoder now. |
| streams[].viewer_accessrequired | object | |
| streams[].viewer_access.visibilityrequired | string | One of |
| streams[].viewer_access.has_access_coderequired | boolean | |
| streams[].viewer_access.interactionsrequired | object | What a stream’s live room offers. |
| streams[].viewer_access.interactions.chatrequired | boolean | |
| streams[].viewer_access.interactions.reactionsrequired | boolean | |
| streams[].viewer_access.interactions.highlightsrequired | boolean | Gift highlights from your giving system. |
| streams[].viewer_access.interactions.reaction_floatsrequired | boolean | Whether reactions float up the player. |
| streams[].viewer_access.interactions.highlight_displayrequired | boolean | Whether highlights are shown in the player. |
| streams[].viewer_access.access_code | string | Present only in the response that set or generated the code. Never readable again. |
| streams[].end_reasonrequired | string or null | Why the stream ended. Null until it has. One of |
| streams[].start_failurerequired | string or null | Why a booking could not start. Null unless it could not. One of |
| streams[].captions | object | |
| streams[].captions.spoken_languagerequired | string |
|
| streams[].captions.translation_languagesrequired | array of string | Reserved for translated captions. Empty. |
| streams[].captions.translation_moderequired | string | One of |
| streams[].captions.profanity_maskingrequired | boolean | |
| streams[].captions.sung_lyricsrequired | string | Whether sung lyrics are captioned or shown as a music symbol. One of |
| streams[].captions.vocabularyrequired | array of string | Up to 100 names and terms the captions should spell right. |
| streams[].captions.retired_source_languages | array of string | |
| next_before | string (date-time) | Present when there may be another page. Pass it as |
Errors
| Status | Code | Meaning |
|---|---|---|
| 400 | invalid_state |
|
| 400 | invalid_customer_ref |
|
| 400 | invalid_recording_state |
|
| 400 | invalid_limit |
|
| 400 | invalid_before |
|
curl "https://api.cardinalstreaming.com/v1/streams?state=live&customer_ref=grace-chapel" \ -H "Authorization: Bearer $CARDINAL_API_KEY"import os
import requests
response = requests.get( "https://api.cardinalstreaming.com/v1/streams", headers={ "Authorization": f"Bearer {os.environ['CARDINAL_API_KEY']}", }, params={ "state": "live", "customer_ref": "grace-chapel", }, timeout=30,)print(response.status_code, response.text)const response = await fetch('https://api.cardinalstreaming.com/v1/streams?state=live&customer_ref=grace-chapel', { method: 'GET', headers: { Authorization: `Bearer ${process.env.CARDINAL_API_KEY}`, },});const data = await response.json();console.log(response.status, data);const response: Response = await fetch('https://api.cardinalstreaming.com/v1/streams?state=live&customer_ref=grace-chapel', { method: 'GET', headers: { Authorization: `Bearer ${process.env.CARDINAL_API_KEY}`, },});const data: unknown = await response.json();console.log(response.status, data);<?phprequire 'vendor/autoload.php'; // composer require guzzlehttp/guzzle
$client = new GuzzleHttp\Client();$response = $client->request('GET', 'https://api.cardinalstreaming.com/v1/streams', [ 'headers' => [ 'Authorization' => 'Bearer ' . getenv('CARDINAL_API_KEY'), ], 'query' => [ 'state' => 'live', 'customer_ref' => 'grace-chapel', ], 'http_errors' => false,]);echo $response->getStatusCode(), ' ', $response->getBody(), PHP_EOL;require 'json'require 'net/http'
uri = URI("https://api.cardinalstreaming.com/v1/streams?state=live&customer_ref=grace-chapel")request = Net::HTTP::Get.new(uri)request['Authorization'] = "Bearer #{ENV.fetch('CARDINAL_API_KEY')}"
response = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(request) }puts response.code, response.bodypackage main
import ( "fmt" "io" "net/http" "os")
func main() { req, err := http.NewRequest("GET", "https://api.cardinalstreaming.com/v1/streams?state=live&customer_ref=grace-chapel", nil) if err != nil { panic(err) } req.Header.Set("Authorization", "Bearer "+os.Getenv("CARDINAL_API_KEY"))
resp, err := http.DefaultClient.Do(req) if err != nil { panic(err) } defer resp.Body.Close() data, _ := io.ReadAll(resp.Body) fmt.Println(resp.StatusCode, string(data))}import java.net.URI;import java.net.http.HttpClient;import java.net.http.HttpRequest;import java.net.http.HttpResponse;
public class Example { public static void main(String[] args) throws Exception { HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://api.cardinalstreaming.com/v1/streams?state=live&customer_ref=grace-chapel")) .header("Authorization", "Bearer " + System.getenv("CARDINAL_API_KEY")) .method("GET", HttpRequest.BodyPublishers.noBody()) .build(); HttpResponse<String> response = HttpClient.newHttpClient() .send(request, HttpResponse.BodyHandlers.ofString()); System.out.println(response.statusCode() + " " + response.body()); }}using System.Net.Http.Headers;using System.Text;
using var client = new HttpClient();using var request = new HttpRequestMessage(new HttpMethod("GET"), "https://api.cardinalstreaming.com/v1/streams?state=live&customer_ref=grace-chapel");request.Headers.Authorization = new AuthenticationHeaderValue( "Bearer", Environment.GetEnvironmentVariable("CARDINAL_API_KEY"));
using var response = await client.SendAsync(request);Console.WriteLine($"{(int)response.StatusCode} {await response.Content.ReadAsStringAsync()}");{ "streams": [ { "playback_id": "1846bdac2d8c0ce0e846d4a3817012c9", "customer_ref": "grace-chapel", "title": "Sunday Service", "tier": "standard_1080p", "state": "live", "started_at": "2026-10-18T15:00:02Z", "unit_rate_usd_per_hour": 5, "leg_count": 3, "legs_ready": 3, "legs": [ { "rank": 0, "state": "ready", "ready_since": "2026-10-18T15:00:09Z" }, { "rank": 1, "state": "ready", "ready_since": "2026-10-18T15:00:11Z" }, { "rank": 2, "state": "ready", "ready_since": "2026-10-18T15:00:10Z" } ], "recording": { "state": "none" }, "encoder_connected": true, "viewer_access": { "visibility": "public", "has_access_code": false, "interactions": { "chat": true, "reactions": true, "highlights": true, "reaction_floats": true, "highlight_display": true } }, "end_reason": null, "start_failure": null } ], "next_before": "2026-09-18T11:52:07.421Z"}Book a stream
POST/v1/streams
Books a broadcast, now or for later, and returns its ingest address. The ingest key is returned once, here, and never again (rotate it to get a new one).
A booking with scheduled_start_at starts itself at that time, and
billing starts then whether or not your encoder is connected. Leave
it out and call start when you are ready. An encoder
can connect up to an hour before a booked start to check the picture;
nothing is billed or shown until the start.
Send an Idempotency-Key so a retried request returns the first
booking instead of making a second.
Headers
| Name | Type | Description |
|---|---|---|
| Idempotency-Key | string | Any unique string you choose per booking, up to 255 printable ASCII characters with no spaces (a UUID is ideal). A retry with the same key and the same body returns the original stream ( |
Request body
| Name | Type | Description |
|---|---|---|
| customer_refrequired | string | Your identifier for a customer. 1-128 letters, digits, |
| titlerequired | string | Up to 200 characters. |
| tierrequired | string |
One of |
| scheduled_start_at | string (date-time) | Book it for later. Left out, start it with the start call. |
| visibility | string | Default One of |
| access_code | string | For a private stream: 6-32 letters, digits or hyphens. Left out, one is generated. |
| interactions | object | Switches to change; any left out stay as they are. |
| interactions.chat | boolean | |
| interactions.reactions | boolean | |
| interactions.highlights | boolean | |
| interactions.reaction_floats | boolean | |
| interactions.highlight_display | boolean |
Response 201
The booked stream, with its ingest address and key.
Fields
| Name | Type | Description |
|---|---|---|
| playback_idrequired | string | The stream’s public id. Unguessable. |
| customer_refrequired | string | Your identifier for a customer. 1-128 letters, digits, |
| titlerequired | string | |
| tierrequired | string |
One of |
| staterequired | string | One of |
| scheduled_start_at | string (date-time) | When a booking starts itself. |
| started_at | string (date-time) | |
| ended_at | string (date-time) | |
| unit_rate_usd_per_hour | number | The stream-hour rate, fixed when it started. |
| restream_unit_rate_usd_per_hour | number | The destination-hour rate, fixed when it started. |
| leg_countrequired | integer | How many independent encodings the stream runs. |
| legs_readyrequired | integer | How many are encoding now. |
| legs | array of object | Each encoding’s state, while the stream is not over. |
| legs[].rankrequired | integer | |
| legs[].staterequired | string | One of |
| legs[].ready_since | string (date-time) | |
| recordingrequired | object | |
| recording.staterequired | string | One of |
| recording.bytes | integer (int64) | |
| recording.duration_seconds | number | |
| recording.ready_at | string (date-time) | |
| ingest | object | Where an encoder sends the stream: RTMPS (RTMP inside TLS) on port 443. Ingest is encrypted only; plain RTMP is not accepted. The srt_ fields appear only where SRT is offered, and SRT is encrypted too: one passphrase per stream, shown with the key. |
| ingest.key | string | The ingest key. Only when it was just created or rotated. |
| ingest.server_url | string | The RTMPS server, for an encoder’s Server field. |
| ingest.stream_key | string | The stream key, for the encoder’s Stream Key field. Only with |
| ingest.srt_url | string | Only where SRT is offered. The whole SRT address for one-field encoders: stream ID, passphrase and AES-256. Only with |
| ingest.srt_server | string | Only where SRT is offered. The SRT server, srt://host:port. Not a secret. |
| ingest.srt_stream_id | string | Only where SRT is offered. publish:live/<playback_id>: names the broadcast, carries no key. Not a secret. |
| ingest.srt_passphrase | string | Only where SRT is offered. The stream’s SRT passphrase: the encoder encrypts with it, and anything unencrypted or on another passphrase is refused. Only with |
| ingest.endpointsrequired | array of string | Every RTMPS address the stream accepts. |
| ingest.fanout_requiredrequired | boolean | Whether the encoder must push to every endpoint for full redundancy. |
| encoder_connectedrequired | boolean | Whether video is arriving from an encoder now. |
| viewer_accessrequired | object | |
| viewer_access.visibilityrequired | string | One of |
| viewer_access.has_access_coderequired | boolean | |
| viewer_access.interactionsrequired | object | What a stream’s live room offers. |
| viewer_access.interactions.chatrequired | boolean | |
| viewer_access.interactions.reactionsrequired | boolean | |
| viewer_access.interactions.highlightsrequired | boolean | Gift highlights from your giving system. |
| viewer_access.interactions.reaction_floatsrequired | boolean | Whether reactions float up the player. |
| viewer_access.interactions.highlight_displayrequired | boolean | Whether highlights are shown in the player. |
| viewer_access.access_code | string | Present only in the response that set or generated the code. Never readable again. |
| end_reasonrequired | string or null | Why the stream ended. Null until it has. One of |
| start_failurerequired | string or null | Why a booking could not start. Null unless it could not. One of |
| captions | object | |
| captions.spoken_languagerequired | string |
|
| captions.translation_languagesrequired | array of string | Reserved for translated captions. Empty. |
| captions.translation_moderequired | string | One of |
| captions.profanity_maskingrequired | boolean | |
| captions.sung_lyricsrequired | string | Whether sung lyrics are captioned or shown as a music symbol. One of |
| captions.vocabularyrequired | array of string | Up to 100 names and terms the captions should spell right. |
| captions.retired_source_languages | array of string |
Errors
| Status | Code | Meaning |
|---|---|---|
| 400 | invalid_body | The body is not a JSON object of the documented fields. |
| 400 | invalid_tier |
|
| 400 | missing_field |
|
| 400 | invalid_customer_ref |
|
| 400 | invalid_title |
|
| 400 | invalid_scheduled_start |
|
| 400 | invalid_interactions |
|
| 400 | invalid_viewer_access |
|
| 400 | invalid_idempotency_key |
|
| 402 | card_required | An organization that signed itself up has no card on file yet. Add one in the console (Billing). |
| 402 | payment_required | Streaming is paused: a bill is unpaid after its seven days. Pay it in the console (Billing); streaming resumes at once. |
| 409 | already_active | This customer already has a stream on air and your organization limits that. |
| 409 | customer_archived | The customer is archived. Unarchive it to book streams for it. |
| 422 | idempotency_key_reused | This |
curl -X POST "https://api.cardinalstreaming.com/v1/streams" \ -H "Authorization: Bearer $CARDINAL_API_KEY" \ -H "Idempotency-Key: 6f1c9a2e-booking-0001" \ -H "Content-Type: application/json" \ -d '{ "customer_ref": "grace-chapel", "title": "Sunday Service", "tier": "standard_1080p", "scheduled_start_at": "2026-10-18T15:00:00Z"}'import os
import requests
response = requests.post( "https://api.cardinalstreaming.com/v1/streams", headers={ "Authorization": f"Bearer {os.environ['CARDINAL_API_KEY']}", "Idempotency-Key": "6f1c9a2e-booking-0001", }, json={ "customer_ref": "grace-chapel", "title": "Sunday Service", "tier": "standard_1080p", "scheduled_start_at": "2026-10-18T15:00:00Z", }, timeout=30,)print(response.status_code, response.text)const response = await fetch('https://api.cardinalstreaming.com/v1/streams', { method: 'POST', headers: { Authorization: `Bearer ${process.env.CARDINAL_API_KEY}`, "Idempotency-Key": "6f1c9a2e-booking-0001", 'Content-Type': 'application/json', }, body: JSON.stringify({ "customer_ref": "grace-chapel", "title": "Sunday Service", "tier": "standard_1080p", "scheduled_start_at": "2026-10-18T15:00:00Z" }),});const data = await response.json();console.log(response.status, data);const response: Response = await fetch('https://api.cardinalstreaming.com/v1/streams', { method: 'POST', headers: { Authorization: `Bearer ${process.env.CARDINAL_API_KEY}`, "Idempotency-Key": "6f1c9a2e-booking-0001", 'Content-Type': 'application/json', }, body: JSON.stringify({ "customer_ref": "grace-chapel", "title": "Sunday Service", "tier": "standard_1080p", "scheduled_start_at": "2026-10-18T15:00:00Z" }),});const data: unknown = await response.json();console.log(response.status, data);<?phprequire 'vendor/autoload.php'; // composer require guzzlehttp/guzzle
$client = new GuzzleHttp\Client();$response = $client->request('POST', 'https://api.cardinalstreaming.com/v1/streams', [ 'headers' => [ 'Authorization' => 'Bearer ' . getenv('CARDINAL_API_KEY'), 'Idempotency-Key' => '6f1c9a2e-booking-0001', ], 'json' => [ 'customer_ref' => 'grace-chapel', 'title' => 'Sunday Service', 'tier' => 'standard_1080p', 'scheduled_start_at' => '2026-10-18T15:00:00Z', ], 'http_errors' => false,]);echo $response->getStatusCode(), ' ', $response->getBody(), PHP_EOL;require 'json'require 'net/http'
uri = URI("https://api.cardinalstreaming.com/v1/streams")request = Net::HTTP::Post.new(uri)request['Authorization'] = "Bearer #{ENV.fetch('CARDINAL_API_KEY')}"request["Idempotency-Key"] = "6f1c9a2e-booking-0001"request['Content-Type'] = 'application/json'request.body = JSON.generate({ "customer_ref" => "grace-chapel", "title" => "Sunday Service", "tier" => "standard_1080p", "scheduled_start_at" => "2026-10-18T15:00:00Z"})
response = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(request) }puts response.code, response.bodypackage main
import ( "fmt" "io" "net/http" "os" "strings")
func main() { req, err := http.NewRequest("POST", "https://api.cardinalstreaming.com/v1/streams", strings.NewReader(`{ "customer_ref": "grace-chapel", "title": "Sunday Service", "tier": "standard_1080p", "scheduled_start_at": "2026-10-18T15:00:00Z"}`)) if err != nil { panic(err) } req.Header.Set("Authorization", "Bearer "+os.Getenv("CARDINAL_API_KEY")) req.Header.Set("Idempotency-Key", "6f1c9a2e-booking-0001") req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req) if err != nil { panic(err) } defer resp.Body.Close() data, _ := io.ReadAll(resp.Body) fmt.Println(resp.StatusCode, string(data))}import java.net.URI;import java.net.http.HttpClient;import java.net.http.HttpRequest;import java.net.http.HttpResponse;
public class Example { public static void main(String[] args) throws Exception { HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://api.cardinalstreaming.com/v1/streams")) .header("Authorization", "Bearer " + System.getenv("CARDINAL_API_KEY")) .header("Idempotency-Key", "6f1c9a2e-booking-0001") .header("Content-Type", "application/json") .method("POST", HttpRequest.BodyPublishers.ofString("{\"customer_ref\":\"grace-chapel\",\"title\":\"Sunday Service\",\"tier\":\"standard_1080p\",\"scheduled_start_at\":\"2026-10-18T15:00:00Z\"}")) .build(); HttpResponse<String> response = HttpClient.newHttpClient() .send(request, HttpResponse.BodyHandlers.ofString()); System.out.println(response.statusCode() + " " + response.body()); }}using System.Net.Http.Headers;using System.Text;
using var client = new HttpClient();using var request = new HttpRequestMessage(new HttpMethod("POST"), "https://api.cardinalstreaming.com/v1/streams");request.Headers.Authorization = new AuthenticationHeaderValue( "Bearer", Environment.GetEnvironmentVariable("CARDINAL_API_KEY"));request.Headers.Add("Idempotency-Key", "6f1c9a2e-booking-0001");request.Content = new StringContent("{\"customer_ref\":\"grace-chapel\",\"title\":\"Sunday Service\",\"tier\":\"standard_1080p\",\"scheduled_start_at\":\"2026-10-18T15:00:00Z\"}", Encoding.UTF8, "application/json");
using var response = await client.SendAsync(request);Console.WriteLine($"{(int)response.StatusCode} {await response.Content.ReadAsStringAsync()}");{ "playback_id": "1846bdac2d8c0ce0e846d4a3817012c9", "customer_ref": "grace-chapel", "title": "Sunday Service", "tier": "standard_1080p", "state": "scheduled", "scheduled_start_at": "2026-10-18T15:00:00Z", "leg_count": 3, "legs_ready": 0, "recording": { "state": "none" }, "ingest": { "key": "strmi_Zk4q0V9yR1sT7uW3xY5zA2bC4dE6fG8hJ2kL5mN8pQr", "server_url": "rtmps://ingest.cardinalstreaming.com:443/live", "stream_key": "1846bdac2d8c0ce0e846d4a3817012c9?key=strmi_Zk4q0V9yR1sT7uW3xY5zA2bC4dE6fG8hJ2kL5mN8pQr", "endpoints": [ "rtmps://ingest.cardinalstreaming.com:443/live/1846bdac2d8c0ce0e846d4a3817012c9" ], "fanout_required": false }, "encoder_connected": false, "viewer_access": { "visibility": "public", "has_access_code": false, "interactions": { "chat": true, "reactions": true, "highlights": true, "reaction_floats": true, "highlight_display": true } }, "end_reason": null, "start_failure": null}Read a stream
GET/v1/streams/{playback_id}
A stream’s state, its legs (the three independent encodings) while it is on air, whether an encoder is connected, and its recording’s state. Poll it every few seconds while live; it contains no credential.
Path parameters
| Name | Type | Description |
|---|---|---|
| playback_idrequired | string | The stream’s |
Response 200
The stream.
Fields
| Name | Type | Description |
|---|---|---|
| playback_idrequired | string | The stream’s public id. Unguessable. |
| customer_refrequired | string | Your identifier for a customer. 1-128 letters, digits, |
| titlerequired | string | |
| tierrequired | string |
One of |
| staterequired | string | One of |
| scheduled_start_at | string (date-time) | When a booking starts itself. |
| started_at | string (date-time) | |
| ended_at | string (date-time) | |
| unit_rate_usd_per_hour | number | The stream-hour rate, fixed when it started. |
| restream_unit_rate_usd_per_hour | number | The destination-hour rate, fixed when it started. |
| leg_countrequired | integer | How many independent encodings the stream runs. |
| legs_readyrequired | integer | How many are encoding now. |
| legs | array of object | Each encoding’s state, while the stream is not over. |
| legs[].rankrequired | integer | |
| legs[].staterequired | string | One of |
| legs[].ready_since | string (date-time) | |
| recordingrequired | object | |
| recording.staterequired | string | One of |
| recording.bytes | integer (int64) | |
| recording.duration_seconds | number | |
| recording.ready_at | string (date-time) | |
| ingest | object | Where an encoder sends the stream: RTMPS (RTMP inside TLS) on port 443. Ingest is encrypted only; plain RTMP is not accepted. The srt_ fields appear only where SRT is offered, and SRT is encrypted too: one passphrase per stream, shown with the key. |
| ingest.key | string | The ingest key. Only when it was just created or rotated. |
| ingest.server_url | string | The RTMPS server, for an encoder’s Server field. |
| ingest.stream_key | string | The stream key, for the encoder’s Stream Key field. Only with |
| ingest.srt_url | string | Only where SRT is offered. The whole SRT address for one-field encoders: stream ID, passphrase and AES-256. Only with |
| ingest.srt_server | string | Only where SRT is offered. The SRT server, srt://host:port. Not a secret. |
| ingest.srt_stream_id | string | Only where SRT is offered. publish:live/<playback_id>: names the broadcast, carries no key. Not a secret. |
| ingest.srt_passphrase | string | Only where SRT is offered. The stream’s SRT passphrase: the encoder encrypts with it, and anything unencrypted or on another passphrase is refused. Only with |
| ingest.endpointsrequired | array of string | Every RTMPS address the stream accepts. |
| ingest.fanout_requiredrequired | boolean | Whether the encoder must push to every endpoint for full redundancy. |
| encoder_connectedrequired | boolean | Whether video is arriving from an encoder now. |
| viewer_accessrequired | object | |
| viewer_access.visibilityrequired | string | One of |
| viewer_access.has_access_coderequired | boolean | |
| viewer_access.interactionsrequired | object | What a stream’s live room offers. |
| viewer_access.interactions.chatrequired | boolean | |
| viewer_access.interactions.reactionsrequired | boolean | |
| viewer_access.interactions.highlightsrequired | boolean | Gift highlights from your giving system. |
| viewer_access.interactions.reaction_floatsrequired | boolean | Whether reactions float up the player. |
| viewer_access.interactions.highlight_displayrequired | boolean | Whether highlights are shown in the player. |
| viewer_access.access_code | string | Present only in the response that set or generated the code. Never readable again. |
| end_reasonrequired | string or null | Why the stream ended. Null until it has. One of |
| start_failurerequired | string or null | Why a booking could not start. Null unless it could not. One of |
| captions | object | |
| captions.spoken_languagerequired | string |
|
| captions.translation_languagesrequired | array of string | Reserved for translated captions. Empty. |
| captions.translation_moderequired | string | One of |
| captions.profanity_maskingrequired | boolean | |
| captions.sung_lyricsrequired | string | Whether sung lyrics are captioned or shown as a music symbol. One of |
| captions.vocabularyrequired | array of string | Up to 100 names and terms the captions should spell right. |
| captions.retired_source_languages | array of string |
Errors
| Status | Code | Meaning |
|---|---|---|
| 404 | not_found | No such stream in your organization. |
curl "https://api.cardinalstreaming.com/v1/streams/1846bdac2d8c0ce0e846d4a3817012c9" \ -H "Authorization: Bearer $CARDINAL_API_KEY"import os
import requests
response = requests.get( "https://api.cardinalstreaming.com/v1/streams/1846bdac2d8c0ce0e846d4a3817012c9", headers={ "Authorization": f"Bearer {os.environ['CARDINAL_API_KEY']}", }, timeout=30,)print(response.status_code, response.text)const response = await fetch('https://api.cardinalstreaming.com/v1/streams/1846bdac2d8c0ce0e846d4a3817012c9', { method: 'GET', headers: { Authorization: `Bearer ${process.env.CARDINAL_API_KEY}`, },});const data = await response.json();console.log(response.status, data);const response: Response = await fetch('https://api.cardinalstreaming.com/v1/streams/1846bdac2d8c0ce0e846d4a3817012c9', { method: 'GET', headers: { Authorization: `Bearer ${process.env.CARDINAL_API_KEY}`, },});const data: unknown = await response.json();console.log(response.status, data);<?phprequire 'vendor/autoload.php'; // composer require guzzlehttp/guzzle
$client = new GuzzleHttp\Client();$response = $client->request('GET', 'https://api.cardinalstreaming.com/v1/streams/1846bdac2d8c0ce0e846d4a3817012c9', [ 'headers' => [ 'Authorization' => 'Bearer ' . getenv('CARDINAL_API_KEY'), ], 'http_errors' => false,]);echo $response->getStatusCode(), ' ', $response->getBody(), PHP_EOL;require 'json'require 'net/http'
uri = URI("https://api.cardinalstreaming.com/v1/streams/1846bdac2d8c0ce0e846d4a3817012c9")request = Net::HTTP::Get.new(uri)request['Authorization'] = "Bearer #{ENV.fetch('CARDINAL_API_KEY')}"
response = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(request) }puts response.code, response.bodypackage main
import ( "fmt" "io" "net/http" "os")
func main() { req, err := http.NewRequest("GET", "https://api.cardinalstreaming.com/v1/streams/1846bdac2d8c0ce0e846d4a3817012c9", nil) if err != nil { panic(err) } req.Header.Set("Authorization", "Bearer "+os.Getenv("CARDINAL_API_KEY"))
resp, err := http.DefaultClient.Do(req) if err != nil { panic(err) } defer resp.Body.Close() data, _ := io.ReadAll(resp.Body) fmt.Println(resp.StatusCode, string(data))}import java.net.URI;import java.net.http.HttpClient;import java.net.http.HttpRequest;import java.net.http.HttpResponse;
public class Example { public static void main(String[] args) throws Exception { HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://api.cardinalstreaming.com/v1/streams/1846bdac2d8c0ce0e846d4a3817012c9")) .header("Authorization", "Bearer " + System.getenv("CARDINAL_API_KEY")) .method("GET", HttpRequest.BodyPublishers.noBody()) .build(); HttpResponse<String> response = HttpClient.newHttpClient() .send(request, HttpResponse.BodyHandlers.ofString()); System.out.println(response.statusCode() + " " + response.body()); }}using System.Net.Http.Headers;using System.Text;
using var client = new HttpClient();using var request = new HttpRequestMessage(new HttpMethod("GET"), "https://api.cardinalstreaming.com/v1/streams/1846bdac2d8c0ce0e846d4a3817012c9");request.Headers.Authorization = new AuthenticationHeaderValue( "Bearer", Environment.GetEnvironmentVariable("CARDINAL_API_KEY"));
using var response = await client.SendAsync(request);Console.WriteLine($"{(int)response.StatusCode} {await response.Content.ReadAsStringAsync()}");{ "playback_id": "1846bdac2d8c0ce0e846d4a3817012c9", "customer_ref": "grace-chapel", "title": "Sunday Service", "tier": "standard_1080p", "state": "live", "started_at": "2026-10-18T15:00:02Z", "unit_rate_usd_per_hour": 5, "leg_count": 3, "legs_ready": 3, "legs": [ { "rank": 0, "state": "ready", "ready_since": "2026-10-18T15:00:09Z" }, { "rank": 1, "state": "ready", "ready_since": "2026-10-18T15:00:11Z" }, { "rank": 2, "state": "ready", "ready_since": "2026-10-18T15:00:10Z" } ], "recording": { "state": "none" }, "encoder_connected": true, "viewer_access": { "visibility": "public", "has_access_code": false, "interactions": { "chat": true, "reactions": true, "highlights": true, "reaction_floats": true, "highlight_display": true } }, "end_reason": null, "start_failure": null}Change who may watch, and the room
PATCH/v1/streams/{playback_id}
Makes a stream public or private, sets or regenerates its access code, switches chat, reactions and highlights, and (when captions are enabled) changes its caption settings. Allowed in any state; a new code applies to new viewers, not to URLs already handed out.
Path parameters
| Name | Type | Description |
|---|---|---|
| playback_idrequired | string | The stream’s |
Request body
| Name | Type | Description |
|---|---|---|
| visibility | string | One of |
| access_code | string | 6-32 letters, digits or hyphens. |
| regenerate_access_code | boolean | Generate a new access code. |
| interactions | object | Switches to change; any left out stay as they are. |
| interactions.chat | boolean | |
| interactions.reactions | boolean | |
| interactions.highlights | boolean | |
| interactions.reaction_floats | boolean | |
| interactions.highlight_display | boolean | |
| captions | object | |
| captions.spoken_language | string | |
| captions.translation_languages | array of string | |
| captions.translation_mode | string | One of |
| captions.profanity_masking | boolean | |
| captions.sung_lyrics | string | One of |
| captions.vocabulary | array of string |
Response 200
The stream as it now is. viewer_access.access_code is present only when this call set or generated one.
Fields
| Name | Type | Description |
|---|---|---|
| playback_idrequired | string | The stream’s public id. Unguessable. |
| customer_refrequired | string | Your identifier for a customer. 1-128 letters, digits, |
| titlerequired | string | |
| tierrequired | string |
One of |
| staterequired | string | One of |
| scheduled_start_at | string (date-time) | When a booking starts itself. |
| started_at | string (date-time) | |
| ended_at | string (date-time) | |
| unit_rate_usd_per_hour | number | The stream-hour rate, fixed when it started. |
| restream_unit_rate_usd_per_hour | number | The destination-hour rate, fixed when it started. |
| leg_countrequired | integer | How many independent encodings the stream runs. |
| legs_readyrequired | integer | How many are encoding now. |
| legs | array of object | Each encoding’s state, while the stream is not over. |
| legs[].rankrequired | integer | |
| legs[].staterequired | string | One of |
| legs[].ready_since | string (date-time) | |
| recordingrequired | object | |
| recording.staterequired | string | One of |
| recording.bytes | integer (int64) | |
| recording.duration_seconds | number | |
| recording.ready_at | string (date-time) | |
| ingest | object | Where an encoder sends the stream: RTMPS (RTMP inside TLS) on port 443. Ingest is encrypted only; plain RTMP is not accepted. The srt_ fields appear only where SRT is offered, and SRT is encrypted too: one passphrase per stream, shown with the key. |
| ingest.key | string | The ingest key. Only when it was just created or rotated. |
| ingest.server_url | string | The RTMPS server, for an encoder’s Server field. |
| ingest.stream_key | string | The stream key, for the encoder’s Stream Key field. Only with |
| ingest.srt_url | string | Only where SRT is offered. The whole SRT address for one-field encoders: stream ID, passphrase and AES-256. Only with |
| ingest.srt_server | string | Only where SRT is offered. The SRT server, srt://host:port. Not a secret. |
| ingest.srt_stream_id | string | Only where SRT is offered. publish:live/<playback_id>: names the broadcast, carries no key. Not a secret. |
| ingest.srt_passphrase | string | Only where SRT is offered. The stream’s SRT passphrase: the encoder encrypts with it, and anything unencrypted or on another passphrase is refused. Only with |
| ingest.endpointsrequired | array of string | Every RTMPS address the stream accepts. |
| ingest.fanout_requiredrequired | boolean | Whether the encoder must push to every endpoint for full redundancy. |
| encoder_connectedrequired | boolean | Whether video is arriving from an encoder now. |
| viewer_accessrequired | object | |
| viewer_access.visibilityrequired | string | One of |
| viewer_access.has_access_coderequired | boolean | |
| viewer_access.interactionsrequired | object | What a stream’s live room offers. |
| viewer_access.interactions.chatrequired | boolean | |
| viewer_access.interactions.reactionsrequired | boolean | |
| viewer_access.interactions.highlightsrequired | boolean | Gift highlights from your giving system. |
| viewer_access.interactions.reaction_floatsrequired | boolean | Whether reactions float up the player. |
| viewer_access.interactions.highlight_displayrequired | boolean | Whether highlights are shown in the player. |
| viewer_access.access_code | string | Present only in the response that set or generated the code. Never readable again. |
| end_reasonrequired | string or null | Why the stream ended. Null until it has. One of |
| start_failurerequired | string or null | Why a booking could not start. Null unless it could not. One of |
| captions | object | |
| captions.spoken_languagerequired | string |
|
| captions.translation_languagesrequired | array of string | Reserved for translated captions. Empty. |
| captions.translation_moderequired | string | One of |
| captions.profanity_maskingrequired | boolean | |
| captions.sung_lyricsrequired | string | Whether sung lyrics are captioned or shown as a music symbol. One of |
| captions.vocabularyrequired | array of string | Up to 100 names and terms the captions should spell right. |
| captions.retired_source_languages | array of string |
Errors
| Status | Code | Meaning |
|---|---|---|
| 400 | invalid_body | The body has a field that is not one of the documented ones. |
| 400 | missing_field | None of the fields was given. |
| 400 | invalid_interactions |
|
| 400 | invalid_viewer_access |
|
| 400 | invalid_captions |
|
| 404 | not_found | No such stream in your organization. |
| 409 | stream_ended | The stream is over; its captions can no longer change. |
curl -X PATCH "https://api.cardinalstreaming.com/v1/streams/1846bdac2d8c0ce0e846d4a3817012c9" \ -H "Authorization: Bearer $CARDINAL_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "visibility": "private", "regenerate_access_code": true, "interactions": { "chat": true, "reactions": true, "highlights": false }}'import os
import requests
response = requests.patch( "https://api.cardinalstreaming.com/v1/streams/1846bdac2d8c0ce0e846d4a3817012c9", headers={ "Authorization": f"Bearer {os.environ['CARDINAL_API_KEY']}", }, json={ "visibility": "private", "regenerate_access_code": True, "interactions": { "chat": True, "reactions": True, "highlights": False, }, }, timeout=30,)print(response.status_code, response.text)const response = await fetch('https://api.cardinalstreaming.com/v1/streams/1846bdac2d8c0ce0e846d4a3817012c9', { method: 'PATCH', headers: { Authorization: `Bearer ${process.env.CARDINAL_API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ "visibility": "private", "regenerate_access_code": true, "interactions": { "chat": true, "reactions": true, "highlights": false } }),});const data = await response.json();console.log(response.status, data);const response: Response = await fetch('https://api.cardinalstreaming.com/v1/streams/1846bdac2d8c0ce0e846d4a3817012c9', { method: 'PATCH', headers: { Authorization: `Bearer ${process.env.CARDINAL_API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ "visibility": "private", "regenerate_access_code": true, "interactions": { "chat": true, "reactions": true, "highlights": false } }),});const data: unknown = await response.json();console.log(response.status, data);<?phprequire 'vendor/autoload.php'; // composer require guzzlehttp/guzzle
$client = new GuzzleHttp\Client();$response = $client->request('PATCH', 'https://api.cardinalstreaming.com/v1/streams/1846bdac2d8c0ce0e846d4a3817012c9', [ 'headers' => [ 'Authorization' => 'Bearer ' . getenv('CARDINAL_API_KEY'), ], 'json' => [ 'visibility' => 'private', 'regenerate_access_code' => true, 'interactions' => [ 'chat' => true, 'reactions' => true, 'highlights' => false, ], ], 'http_errors' => false,]);echo $response->getStatusCode(), ' ', $response->getBody(), PHP_EOL;require 'json'require 'net/http'
uri = URI("https://api.cardinalstreaming.com/v1/streams/1846bdac2d8c0ce0e846d4a3817012c9")request = Net::HTTP::Patch.new(uri)request['Authorization'] = "Bearer #{ENV.fetch('CARDINAL_API_KEY')}"request['Content-Type'] = 'application/json'request.body = JSON.generate({ "visibility" => "private", "regenerate_access_code" => true, "interactions" => { "chat" => true, "reactions" => true, "highlights" => false }})
response = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(request) }puts response.code, response.bodypackage main
import ( "fmt" "io" "net/http" "os" "strings")
func main() { req, err := http.NewRequest("PATCH", "https://api.cardinalstreaming.com/v1/streams/1846bdac2d8c0ce0e846d4a3817012c9", strings.NewReader(`{ "visibility": "private", "regenerate_access_code": true, "interactions": { "chat": true, "reactions": true, "highlights": false }}`)) if err != nil { panic(err) } req.Header.Set("Authorization", "Bearer "+os.Getenv("CARDINAL_API_KEY")) req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req) if err != nil { panic(err) } defer resp.Body.Close() data, _ := io.ReadAll(resp.Body) fmt.Println(resp.StatusCode, string(data))}import java.net.URI;import java.net.http.HttpClient;import java.net.http.HttpRequest;import java.net.http.HttpResponse;
public class Example { public static void main(String[] args) throws Exception { HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://api.cardinalstreaming.com/v1/streams/1846bdac2d8c0ce0e846d4a3817012c9")) .header("Authorization", "Bearer " + System.getenv("CARDINAL_API_KEY")) .header("Content-Type", "application/json") .method("PATCH", HttpRequest.BodyPublishers.ofString("{\"visibility\":\"private\",\"regenerate_access_code\":true,\"interactions\":{\"chat\":true,\"reactions\":true,\"highlights\":false}}")) .build(); HttpResponse<String> response = HttpClient.newHttpClient() .send(request, HttpResponse.BodyHandlers.ofString()); System.out.println(response.statusCode() + " " + response.body()); }}using System.Net.Http.Headers;using System.Text;
using var client = new HttpClient();using var request = new HttpRequestMessage(new HttpMethod("PATCH"), "https://api.cardinalstreaming.com/v1/streams/1846bdac2d8c0ce0e846d4a3817012c9");request.Headers.Authorization = new AuthenticationHeaderValue( "Bearer", Environment.GetEnvironmentVariable("CARDINAL_API_KEY"));request.Content = new StringContent("{\"visibility\":\"private\",\"regenerate_access_code\":true,\"interactions\":{\"chat\":true,\"reactions\":true,\"highlights\":false}}", Encoding.UTF8, "application/json");
using var response = await client.SendAsync(request);Console.WriteLine($"{(int)response.StatusCode} {await response.Content.ReadAsStringAsync()}");Start a stream
POST/v1/streams/{playback_id}/start
Brings a booked stream up now: three legs start encoding and billing begins. It goes live within about a minute of your encoder’s video arriving, while it gets ready. A stream left to start itself at its booked time gets ready in the five minutes before, and goes live within seconds of the start. Calling it again on a stream already starting or live returns it unchanged.
Path parameters
| Name | Type | Description |
|---|---|---|
| playback_idrequired | string | The stream’s |
Response 200
The stream, now starting (or already starting or live).
Fields
| Name | Type | Description |
|---|---|---|
| playback_idrequired | string | The stream’s public id. Unguessable. |
| customer_refrequired | string | Your identifier for a customer. 1-128 letters, digits, |
| titlerequired | string | |
| tierrequired | string |
One of |
| staterequired | string | One of |
| scheduled_start_at | string (date-time) | When a booking starts itself. |
| started_at | string (date-time) | |
| ended_at | string (date-time) | |
| unit_rate_usd_per_hour | number | The stream-hour rate, fixed when it started. |
| restream_unit_rate_usd_per_hour | number | The destination-hour rate, fixed when it started. |
| leg_countrequired | integer | How many independent encodings the stream runs. |
| legs_readyrequired | integer | How many are encoding now. |
| legs | array of object | Each encoding’s state, while the stream is not over. |
| legs[].rankrequired | integer | |
| legs[].staterequired | string | One of |
| legs[].ready_since | string (date-time) | |
| recordingrequired | object | |
| recording.staterequired | string | One of |
| recording.bytes | integer (int64) | |
| recording.duration_seconds | number | |
| recording.ready_at | string (date-time) | |
| ingest | object | Where an encoder sends the stream: RTMPS (RTMP inside TLS) on port 443. Ingest is encrypted only; plain RTMP is not accepted. The srt_ fields appear only where SRT is offered, and SRT is encrypted too: one passphrase per stream, shown with the key. |
| ingest.key | string | The ingest key. Only when it was just created or rotated. |
| ingest.server_url | string | The RTMPS server, for an encoder’s Server field. |
| ingest.stream_key | string | The stream key, for the encoder’s Stream Key field. Only with |
| ingest.srt_url | string | Only where SRT is offered. The whole SRT address for one-field encoders: stream ID, passphrase and AES-256. Only with |
| ingest.srt_server | string | Only where SRT is offered. The SRT server, srt://host:port. Not a secret. |
| ingest.srt_stream_id | string | Only where SRT is offered. publish:live/<playback_id>: names the broadcast, carries no key. Not a secret. |
| ingest.srt_passphrase | string | Only where SRT is offered. The stream’s SRT passphrase: the encoder encrypts with it, and anything unencrypted or on another passphrase is refused. Only with |
| ingest.endpointsrequired | array of string | Every RTMPS address the stream accepts. |
| ingest.fanout_requiredrequired | boolean | Whether the encoder must push to every endpoint for full redundancy. |
| encoder_connectedrequired | boolean | Whether video is arriving from an encoder now. |
| viewer_accessrequired | object | |
| viewer_access.visibilityrequired | string | One of |
| viewer_access.has_access_coderequired | boolean | |
| viewer_access.interactionsrequired | object | What a stream’s live room offers. |
| viewer_access.interactions.chatrequired | boolean | |
| viewer_access.interactions.reactionsrequired | boolean | |
| viewer_access.interactions.highlightsrequired | boolean | Gift highlights from your giving system. |
| viewer_access.interactions.reaction_floatsrequired | boolean | Whether reactions float up the player. |
| viewer_access.interactions.highlight_displayrequired | boolean | Whether highlights are shown in the player. |
| viewer_access.access_code | string | Present only in the response that set or generated the code. Never readable again. |
| end_reasonrequired | string or null | Why the stream ended. Null until it has. One of |
| start_failurerequired | string or null | Why a booking could not start. Null unless it could not. One of |
| captions | object | |
| captions.spoken_languagerequired | string |
|
| captions.translation_languagesrequired | array of string | Reserved for translated captions. Empty. |
| captions.translation_moderequired | string | One of |
| captions.profanity_maskingrequired | boolean | |
| captions.sung_lyricsrequired | string | Whether sung lyrics are captioned or shown as a music symbol. One of |
| captions.vocabularyrequired | array of string | Up to 100 names and terms the captions should spell right. |
| captions.retired_source_languages | array of string |
Errors
| Status | Code | Meaning |
|---|---|---|
| 402 | cap_exceeded | Your organization has reached the monthly stream-hour cap set on its account. |
| 402 | payment_required | Streaming is paused: a bill is unpaid after its seven days. Pay it in the console (Billing); streaming resumes at once. |
| 404 | not_found | No such stream in your organization. |
| 409 | already_active | This customer already has a stream on air and your organization limits that. |
| 409 | stream_ended | The stream is over and cannot be started again. Book a new one. |
| 503 | no_rate | No price is configured for this tier. Contact us. |
curl -X POST "https://api.cardinalstreaming.com/v1/streams/1846bdac2d8c0ce0e846d4a3817012c9/start" \ -H "Authorization: Bearer $CARDINAL_API_KEY"import os
import requests
response = requests.post( "https://api.cardinalstreaming.com/v1/streams/1846bdac2d8c0ce0e846d4a3817012c9/start", headers={ "Authorization": f"Bearer {os.environ['CARDINAL_API_KEY']}", }, timeout=30,)print(response.status_code, response.text)const response = await fetch('https://api.cardinalstreaming.com/v1/streams/1846bdac2d8c0ce0e846d4a3817012c9/start', { method: 'POST', headers: { Authorization: `Bearer ${process.env.CARDINAL_API_KEY}`, },});const data = await response.json();console.log(response.status, data);const response: Response = await fetch('https://api.cardinalstreaming.com/v1/streams/1846bdac2d8c0ce0e846d4a3817012c9/start', { method: 'POST', headers: { Authorization: `Bearer ${process.env.CARDINAL_API_KEY}`, },});const data: unknown = await response.json();console.log(response.status, data);<?phprequire 'vendor/autoload.php'; // composer require guzzlehttp/guzzle
$client = new GuzzleHttp\Client();$response = $client->request('POST', 'https://api.cardinalstreaming.com/v1/streams/1846bdac2d8c0ce0e846d4a3817012c9/start', [ 'headers' => [ 'Authorization' => 'Bearer ' . getenv('CARDINAL_API_KEY'), ], 'http_errors' => false,]);echo $response->getStatusCode(), ' ', $response->getBody(), PHP_EOL;require 'json'require 'net/http'
uri = URI("https://api.cardinalstreaming.com/v1/streams/1846bdac2d8c0ce0e846d4a3817012c9/start")request = Net::HTTP::Post.new(uri)request['Authorization'] = "Bearer #{ENV.fetch('CARDINAL_API_KEY')}"
response = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(request) }puts response.code, response.bodypackage main
import ( "fmt" "io" "net/http" "os")
func main() { req, err := http.NewRequest("POST", "https://api.cardinalstreaming.com/v1/streams/1846bdac2d8c0ce0e846d4a3817012c9/start", nil) if err != nil { panic(err) } req.Header.Set("Authorization", "Bearer "+os.Getenv("CARDINAL_API_KEY"))
resp, err := http.DefaultClient.Do(req) if err != nil { panic(err) } defer resp.Body.Close() data, _ := io.ReadAll(resp.Body) fmt.Println(resp.StatusCode, string(data))}import java.net.URI;import java.net.http.HttpClient;import java.net.http.HttpRequest;import java.net.http.HttpResponse;
public class Example { public static void main(String[] args) throws Exception { HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://api.cardinalstreaming.com/v1/streams/1846bdac2d8c0ce0e846d4a3817012c9/start")) .header("Authorization", "Bearer " + System.getenv("CARDINAL_API_KEY")) .method("POST", HttpRequest.BodyPublishers.noBody()) .build(); HttpResponse<String> response = HttpClient.newHttpClient() .send(request, HttpResponse.BodyHandlers.ofString()); System.out.println(response.statusCode() + " " + response.body()); }}using System.Net.Http.Headers;using System.Text;
using var client = new HttpClient();using var request = new HttpRequestMessage(new HttpMethod("POST"), "https://api.cardinalstreaming.com/v1/streams/1846bdac2d8c0ce0e846d4a3817012c9/start");request.Headers.Authorization = new AuthenticationHeaderValue( "Bearer", Environment.GetEnvironmentVariable("CARDINAL_API_KEY"));
using var response = await client.SendAsync(request);Console.WriteLine($"{(int)response.StatusCode} {await response.Content.ReadAsStringAsync()}");End a stream
POST/v1/streams/{playback_id}/end
Takes a stream down and stops billing. Its recording starts to be made.
Calling it again returns the same answer and bills nothing more. A
booking that never started ends with billed_usd: 0.
Path parameters
| Name | Type | Description |
|---|---|---|
| playback_idrequired | string | The stream’s |
Response 200
The ended stream and what it bills.
Errors
| Status | Code | Meaning |
|---|---|---|
| 404 | not_found | No such stream in your organization. |
curl -X POST "https://api.cardinalstreaming.com/v1/streams/1846bdac2d8c0ce0e846d4a3817012c9/end" \ -H "Authorization: Bearer $CARDINAL_API_KEY"import os
import requests
response = requests.post( "https://api.cardinalstreaming.com/v1/streams/1846bdac2d8c0ce0e846d4a3817012c9/end", headers={ "Authorization": f"Bearer {os.environ['CARDINAL_API_KEY']}", }, timeout=30,)print(response.status_code, response.text)const response = await fetch('https://api.cardinalstreaming.com/v1/streams/1846bdac2d8c0ce0e846d4a3817012c9/end', { method: 'POST', headers: { Authorization: `Bearer ${process.env.CARDINAL_API_KEY}`, },});const data = await response.json();console.log(response.status, data);const response: Response = await fetch('https://api.cardinalstreaming.com/v1/streams/1846bdac2d8c0ce0e846d4a3817012c9/end', { method: 'POST', headers: { Authorization: `Bearer ${process.env.CARDINAL_API_KEY}`, },});const data: unknown = await response.json();console.log(response.status, data);<?phprequire 'vendor/autoload.php'; // composer require guzzlehttp/guzzle
$client = new GuzzleHttp\Client();$response = $client->request('POST', 'https://api.cardinalstreaming.com/v1/streams/1846bdac2d8c0ce0e846d4a3817012c9/end', [ 'headers' => [ 'Authorization' => 'Bearer ' . getenv('CARDINAL_API_KEY'), ], 'http_errors' => false,]);echo $response->getStatusCode(), ' ', $response->getBody(), PHP_EOL;require 'json'require 'net/http'
uri = URI("https://api.cardinalstreaming.com/v1/streams/1846bdac2d8c0ce0e846d4a3817012c9/end")request = Net::HTTP::Post.new(uri)request['Authorization'] = "Bearer #{ENV.fetch('CARDINAL_API_KEY')}"
response = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(request) }puts response.code, response.bodypackage main
import ( "fmt" "io" "net/http" "os")
func main() { req, err := http.NewRequest("POST", "https://api.cardinalstreaming.com/v1/streams/1846bdac2d8c0ce0e846d4a3817012c9/end", nil) if err != nil { panic(err) } req.Header.Set("Authorization", "Bearer "+os.Getenv("CARDINAL_API_KEY"))
resp, err := http.DefaultClient.Do(req) if err != nil { panic(err) } defer resp.Body.Close() data, _ := io.ReadAll(resp.Body) fmt.Println(resp.StatusCode, string(data))}import java.net.URI;import java.net.http.HttpClient;import java.net.http.HttpRequest;import java.net.http.HttpResponse;
public class Example { public static void main(String[] args) throws Exception { HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://api.cardinalstreaming.com/v1/streams/1846bdac2d8c0ce0e846d4a3817012c9/end")) .header("Authorization", "Bearer " + System.getenv("CARDINAL_API_KEY")) .method("POST", HttpRequest.BodyPublishers.noBody()) .build(); HttpResponse<String> response = HttpClient.newHttpClient() .send(request, HttpResponse.BodyHandlers.ofString()); System.out.println(response.statusCode() + " " + response.body()); }}using System.Net.Http.Headers;using System.Text;
using var client = new HttpClient();using var request = new HttpRequestMessage(new HttpMethod("POST"), "https://api.cardinalstreaming.com/v1/streams/1846bdac2d8c0ce0e846d4a3817012c9/end");request.Headers.Authorization = new AuthenticationHeaderValue( "Bearer", Environment.GetEnvironmentVariable("CARDINAL_API_KEY"));
using var response = await client.SendAsync(request);Console.WriteLine($"{(int)response.StatusCode} {await response.Content.ReadAsStringAsync()}");Rotate the ingest key
POST/v1/streams/{playback_id}/ingest-key
Replaces a stream’s ingest key and returns the new address. The old key stops working immediately. Use it if a key leaks, or to get a key for a stream booked by a retried request.
Path parameters
| Name | Type | Description |
|---|---|---|
| playback_idrequired | string | The stream’s |
Response 200
The new ingest address and key.
Fields
| Name | Type | Description |
|---|---|---|
| key | string | The ingest key. Only when it was just created or rotated. |
| server_url | string | The RTMPS server, for an encoder’s Server field. |
| stream_key | string | The stream key, for the encoder’s Stream Key field. Only with |
| srt_url | string | Only where SRT is offered. The whole SRT address for one-field encoders: stream ID, passphrase and AES-256. Only with |
| srt_server | string | Only where SRT is offered. The SRT server, srt://host:port. Not a secret. |
| srt_stream_id | string | Only where SRT is offered. publish:live/<playback_id>: names the broadcast, carries no key. Not a secret. |
| srt_passphrase | string | Only where SRT is offered. The stream’s SRT passphrase: the encoder encrypts with it, and anything unencrypted or on another passphrase is refused. Only with |
| endpointsrequired | array of string | Every RTMPS address the stream accepts. |
| fanout_requiredrequired | boolean | Whether the encoder must push to every endpoint for full redundancy. |
Errors
| Status | Code | Meaning |
|---|---|---|
| 404 | not_found | No such stream in your organization, or it is over. |
curl -X POST "https://api.cardinalstreaming.com/v1/streams/1846bdac2d8c0ce0e846d4a3817012c9/ingest-key" \ -H "Authorization: Bearer $CARDINAL_API_KEY"import os
import requests
response = requests.post( "https://api.cardinalstreaming.com/v1/streams/1846bdac2d8c0ce0e846d4a3817012c9/ingest-key", headers={ "Authorization": f"Bearer {os.environ['CARDINAL_API_KEY']}", }, timeout=30,)print(response.status_code, response.text)const response = await fetch('https://api.cardinalstreaming.com/v1/streams/1846bdac2d8c0ce0e846d4a3817012c9/ingest-key', { method: 'POST', headers: { Authorization: `Bearer ${process.env.CARDINAL_API_KEY}`, },});const data = await response.json();console.log(response.status, data);const response: Response = await fetch('https://api.cardinalstreaming.com/v1/streams/1846bdac2d8c0ce0e846d4a3817012c9/ingest-key', { method: 'POST', headers: { Authorization: `Bearer ${process.env.CARDINAL_API_KEY}`, },});const data: unknown = await response.json();console.log(response.status, data);<?phprequire 'vendor/autoload.php'; // composer require guzzlehttp/guzzle
$client = new GuzzleHttp\Client();$response = $client->request('POST', 'https://api.cardinalstreaming.com/v1/streams/1846bdac2d8c0ce0e846d4a3817012c9/ingest-key', [ 'headers' => [ 'Authorization' => 'Bearer ' . getenv('CARDINAL_API_KEY'), ], 'http_errors' => false,]);echo $response->getStatusCode(), ' ', $response->getBody(), PHP_EOL;require 'json'require 'net/http'
uri = URI("https://api.cardinalstreaming.com/v1/streams/1846bdac2d8c0ce0e846d4a3817012c9/ingest-key")request = Net::HTTP::Post.new(uri)request['Authorization'] = "Bearer #{ENV.fetch('CARDINAL_API_KEY')}"
response = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(request) }puts response.code, response.bodypackage main
import ( "fmt" "io" "net/http" "os")
func main() { req, err := http.NewRequest("POST", "https://api.cardinalstreaming.com/v1/streams/1846bdac2d8c0ce0e846d4a3817012c9/ingest-key", nil) if err != nil { panic(err) } req.Header.Set("Authorization", "Bearer "+os.Getenv("CARDINAL_API_KEY"))
resp, err := http.DefaultClient.Do(req) if err != nil { panic(err) } defer resp.Body.Close() data, _ := io.ReadAll(resp.Body) fmt.Println(resp.StatusCode, string(data))}import java.net.URI;import java.net.http.HttpClient;import java.net.http.HttpRequest;import java.net.http.HttpResponse;
public class Example { public static void main(String[] args) throws Exception { HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://api.cardinalstreaming.com/v1/streams/1846bdac2d8c0ce0e846d4a3817012c9/ingest-key")) .header("Authorization", "Bearer " + System.getenv("CARDINAL_API_KEY")) .method("POST", HttpRequest.BodyPublishers.noBody()) .build(); HttpResponse<String> response = HttpClient.newHttpClient() .send(request, HttpResponse.BodyHandlers.ofString()); System.out.println(response.statusCode() + " " + response.body()); }}using System.Net.Http.Headers;using System.Text;
using var client = new HttpClient();using var request = new HttpRequestMessage(new HttpMethod("POST"), "https://api.cardinalstreaming.com/v1/streams/1846bdac2d8c0ce0e846d4a3817012c9/ingest-key");request.Headers.Authorization = new AuthenticationHeaderValue( "Bearer", Environment.GetEnvironmentVariable("CARDINAL_API_KEY"));
using var response = await client.SendAsync(request);Console.WriteLine($"{(int)response.StatusCode} {await response.Content.ReadAsStringAsync()}");