Customers API
If you stream for your own customers (you are a partner), each stream
names its customer with customer_ref, your own identifier. Booking a
stream registers its customer; these endpoints name, list and archive
them, and pull their recordings.
This page is generated from the OpenAPI specification; the same text is inMarkdown for tools and AI assistants.
List customers
GET/v1/customers
Your customers, ordered by customer_ref. Archived customers are left
out unless you ask for them. Page with cursor until next_cursor is
absent.
Query parameters
| Name | Type | Description |
|---|---|---|
| limit | integer | Page size, 1-200. Default 50; more than 200 is treated as 200. |
| cursor | string | The previous page’s |
| include_archived | string |
One of |
Response 200
A page of customers.
Fields
| Name | Type | Description |
|---|---|---|
| customersrequired | array of object | |
| customers[].customer_refrequired | string | Your identifier for a customer. 1-128 letters, digits, |
| customers[].namerequired | string or null | |
| customers[].metadatarequired | object | Your own labels, returned as given. |
| customers[].created_atrequired | string (date-time) | |
| customers[].updated_atrequired | string (date-time) | |
| customers[].archived_atrequired | string (date-time) or null | |
| next_cursor | string | Present when there is another page. Pass it as |
Errors
| Status | Code | Meaning |
|---|---|---|
| 400 | invalid_limit |
|
| 400 | invalid_cursor |
|
| 400 | invalid_include_archived |
|
curl "https://api.cardinalstreaming.com/v1/customers" \ -H "Authorization: Bearer $CARDINAL_API_KEY"import os
import requests
response = requests.get( "https://api.cardinalstreaming.com/v1/customers", 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/customers', { 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/customers', { 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/customers', [ '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/customers")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/customers", 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/customers")) .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/customers");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()}");{ "customers": [ { "customer_ref": "grace-chapel", "name": "Grace Chapel", "metadata": { "crm_id": "C-1042" }, "created_at": "2026-09-01T14:02:11Z", "updated_at": "2026-09-12T09:40:00Z", "archived_at": null } ]}Create a customer
POST/v1/customers
Registers a customer ahead of its first stream, with a name and your own metadata. Booking a stream registers its customer anyway; create one only to name it first.
Request body
| Name | Type | Description |
|---|---|---|
| customer_refrequired | string | Your identifier for a customer. 1-128 letters, digits, |
| name | string | 1-200 characters. |
| metadata | object | Up to 50 keys of 1-40 characters, values up to 500 characters, 4 KB in all. |
Response 201
The customer.
Fields
| Name | Type | Description |
|---|---|---|
| customer_refrequired | string | Your identifier for a customer. 1-128 letters, digits, |
| namerequired | string or null | |
| metadatarequired | object | Your own labels, returned as given. |
| created_atrequired | string (date-time) | |
| updated_atrequired | string (date-time) | |
| archived_atrequired | string (date-time) or null |
Errors
| Status | Code | Meaning |
|---|---|---|
| 400 | invalid_body | The body is not a JSON object of the documented fields. |
| 400 | invalid_customer_ref |
|
| 400 | invalid_name |
|
| 400 | invalid_metadata |
|
| 409 | customer_exists | A customer with this |
curl -X POST "https://api.cardinalstreaming.com/v1/customers" \ -H "Authorization: Bearer $CARDINAL_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "customer_ref": "grace-chapel", "name": "Grace Chapel", "metadata": { "crm_id": "C-1042" }}'import os
import requests
response = requests.post( "https://api.cardinalstreaming.com/v1/customers", headers={ "Authorization": f"Bearer {os.environ['CARDINAL_API_KEY']}", }, json={ "customer_ref": "grace-chapel", "name": "Grace Chapel", "metadata": { "crm_id": "C-1042", }, }, timeout=30,)print(response.status_code, response.text)const response = await fetch('https://api.cardinalstreaming.com/v1/customers', { method: 'POST', headers: { Authorization: `Bearer ${process.env.CARDINAL_API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ "customer_ref": "grace-chapel", "name": "Grace Chapel", "metadata": { "crm_id": "C-1042" } }),});const data = await response.json();console.log(response.status, data);const response: Response = await fetch('https://api.cardinalstreaming.com/v1/customers', { method: 'POST', headers: { Authorization: `Bearer ${process.env.CARDINAL_API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ "customer_ref": "grace-chapel", "name": "Grace Chapel", "metadata": { "crm_id": "C-1042" } }),});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/customers', [ 'headers' => [ 'Authorization' => 'Bearer ' . getenv('CARDINAL_API_KEY'), ], 'json' => [ 'customer_ref' => 'grace-chapel', 'name' => 'Grace Chapel', 'metadata' => [ 'crm_id' => 'C-1042', ], ], 'http_errors' => false,]);echo $response->getStatusCode(), ' ', $response->getBody(), PHP_EOL;require 'json'require 'net/http'
uri = URI("https://api.cardinalstreaming.com/v1/customers")request = Net::HTTP::Post.new(uri)request['Authorization'] = "Bearer #{ENV.fetch('CARDINAL_API_KEY')}"request['Content-Type'] = 'application/json'request.body = JSON.generate({ "customer_ref" => "grace-chapel", "name" => "Grace Chapel", "metadata" => { "crm_id" => "C-1042" }})
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/customers", strings.NewReader(`{ "customer_ref": "grace-chapel", "name": "Grace Chapel", "metadata": { "crm_id": "C-1042" }}`)) 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/customers")) .header("Authorization", "Bearer " + System.getenv("CARDINAL_API_KEY")) .header("Content-Type", "application/json") .method("POST", HttpRequest.BodyPublishers.ofString("{\"customer_ref\":\"grace-chapel\",\"name\":\"Grace Chapel\",\"metadata\":{\"crm_id\":\"C-1042\"}}")) .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/customers");request.Headers.Authorization = new AuthenticationHeaderValue( "Bearer", Environment.GetEnvironmentVariable("CARDINAL_API_KEY"));request.Content = new StringContent("{\"customer_ref\":\"grace-chapel\",\"name\":\"Grace Chapel\",\"metadata\":{\"crm_id\":\"C-1042\"}}", Encoding.UTF8, "application/json");
using var response = await client.SendAsync(request);Console.WriteLine($"{(int)response.StatusCode} {await response.Content.ReadAsStringAsync()}");{ "customer_ref": "grace-chapel", "name": "Grace Chapel", "metadata": { "crm_id": "C-1042" }, "created_at": "2026-09-01T14:02:11Z", "updated_at": "2026-09-12T09:40:00Z", "archived_at": null}Read a customer
GET/v1/customers/{customer_ref}
Path parameters
| Name | Type | Description |
|---|---|---|
| customer_refrequired | string | Your identifier for the customer. |
Response 200
The customer.
Fields
| Name | Type | Description |
|---|---|---|
| customer_refrequired | string | Your identifier for a customer. 1-128 letters, digits, |
| namerequired | string or null | |
| metadatarequired | object | Your own labels, returned as given. |
| created_atrequired | string (date-time) | |
| updated_atrequired | string (date-time) | |
| archived_atrequired | string (date-time) or null |
Errors
| Status | Code | Meaning |
|---|---|---|
| 400 | invalid_customer_ref | The path’s customer reference is not valid. |
| 404 | not_found | No such customer in your organization. |
curl "https://api.cardinalstreaming.com/v1/customers/grace-chapel" \ -H "Authorization: Bearer $CARDINAL_API_KEY"import os
import requests
response = requests.get( "https://api.cardinalstreaming.com/v1/customers/grace-chapel", 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/customers/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/customers/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/customers/grace-chapel', [ '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/customers/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/customers/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/customers/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/customers/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()}");{ "customer_ref": "grace-chapel", "name": "Grace Chapel", "metadata": { "crm_id": "C-1042" }, "created_at": "2026-09-01T14:02:11Z", "updated_at": "2026-09-12T09:40:00Z", "archived_at": null}Update or archive a customer
PATCH/v1/customers/{customer_ref}
Every field is optional: absent leaves it, "name": null clears the
name, metadata replaces the whole set, and "archived": true archives
the customer. An archived customer keeps its history and recordings, but
no stream can be booked for it until it is unarchived.
Path parameters
| Name | Type | Description |
|---|---|---|
| customer_refrequired | string | Your identifier for the customer. |
Request body
| Name | Type | Description |
|---|---|---|
| name | string or null | A new name, or null to clear it. |
| metadata | object | Replaces the whole set. |
| archived | boolean |
Response 200
The customer as it now is.
Fields
| Name | Type | Description |
|---|---|---|
| customer_refrequired | string | Your identifier for a customer. 1-128 letters, digits, |
| namerequired | string or null | |
| metadatarequired | object | Your own labels, returned as given. |
| created_atrequired | string (date-time) | |
| updated_atrequired | string (date-time) | |
| archived_atrequired | string (date-time) or null |
Errors
| Status | Code | Meaning |
|---|---|---|
| 400 | invalid_body | The body is not a JSON object of the documented fields. |
| 400 | invalid_customer_ref | The path’s customer reference is not valid. |
| 400 | invalid_name |
|
| 400 | invalid_metadata |
|
| 404 | not_found | No such customer in your organization. |
curl -X PATCH "https://api.cardinalstreaming.com/v1/customers/grace-chapel" \ -H "Authorization: Bearer $CARDINAL_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Grace Chapel Downtown", "archived": false}'import os
import requests
response = requests.patch( "https://api.cardinalstreaming.com/v1/customers/grace-chapel", headers={ "Authorization": f"Bearer {os.environ['CARDINAL_API_KEY']}", }, json={ "name": "Grace Chapel Downtown", "archived": False, }, timeout=30,)print(response.status_code, response.text)const response = await fetch('https://api.cardinalstreaming.com/v1/customers/grace-chapel', { method: 'PATCH', headers: { Authorization: `Bearer ${process.env.CARDINAL_API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ "name": "Grace Chapel Downtown", "archived": false }),});const data = await response.json();console.log(response.status, data);const response: Response = await fetch('https://api.cardinalstreaming.com/v1/customers/grace-chapel', { method: 'PATCH', headers: { Authorization: `Bearer ${process.env.CARDINAL_API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ "name": "Grace Chapel Downtown", "archived": 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/customers/grace-chapel', [ 'headers' => [ 'Authorization' => 'Bearer ' . getenv('CARDINAL_API_KEY'), ], 'json' => [ 'name' => 'Grace Chapel Downtown', 'archived' => false, ], 'http_errors' => false,]);echo $response->getStatusCode(), ' ', $response->getBody(), PHP_EOL;require 'json'require 'net/http'
uri = URI("https://api.cardinalstreaming.com/v1/customers/grace-chapel")request = Net::HTTP::Patch.new(uri)request['Authorization'] = "Bearer #{ENV.fetch('CARDINAL_API_KEY')}"request['Content-Type'] = 'application/json'request.body = JSON.generate({ "name" => "Grace Chapel Downtown", "archived" => 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/customers/grace-chapel", strings.NewReader(`{ "name": "Grace Chapel Downtown", "archived": 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/customers/grace-chapel")) .header("Authorization", "Bearer " + System.getenv("CARDINAL_API_KEY")) .header("Content-Type", "application/json") .method("PATCH", HttpRequest.BodyPublishers.ofString("{\"name\":\"Grace Chapel Downtown\",\"archived\":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/customers/grace-chapel");request.Headers.Authorization = new AuthenticationHeaderValue( "Bearer", Environment.GetEnvironmentVariable("CARDINAL_API_KEY"));request.Content = new StringContent("{\"name\":\"Grace Chapel Downtown\",\"archived\":false}", Encoding.UTF8, "application/json");
using var response = await client.SendAsync(request);Console.WriteLine($"{(int)response.StatusCode} {await response.Content.ReadAsStringAsync()}");