Video service#
The video service manages videos and video metadata.
OpenAPI file: VideoService.json
Endpoints#
Get#
GET /video/v1/videos/{videoRid}
Deprecated: Legacy Video-entity API. Videos are now channels on datasets; list a channel’s files with listVideoChannelDatasetFiles and read dataset metadata from CatalogService.
Returns video metadata associated with a video rid.
Path parameters
videoRidstring (RID) required
Response
ridstring (RID)
titlestring
descriptionstring
labelsarray of string
propertiesmap ofPropertyNameto string
createdBystring (RID)
createdAtstring (date-time)
isArchivedboolean
originMetadataVideoOriginMetadatadeprecatedDeprecated: deprecated in favor of per-file VideoFileOriginMetadata. Will be removed after April 15th.
Fields of
VideoOriginMetadatavideoSourcesarray ofHandledeprecatedDeprecated: deprecated in favor of per-file VideoFileOriginMetadata. Will be removed after April 15th.
Set
typeto"s3".s3string
timestampManifestVideoTimestampManifestdeprecatedDeprecated: deprecated in favor of per-file VideoFileOriginMetadata. Will be removed after April 15th.
Set
typeto"mcap".mcapMcapTimestampManifest
Fields of
McapTimestampManifestmcapChannelLocatorMcapChannelLocator
Set
typeto"topic".topicstring
Set
typeto"id".idinteger
Set
typeto"s3paths".s3pathsarray of string
Set
typeto"noManifest".noManifestNoTimestampManifest
Fields of
NoTimestampManifeststartingTimestampTimestampSpecifies the original starting timestamp of the video.
Fields of
Timestampsecondsinteger (int64)
nanosinteger (int64)
scaleParameterScaleParameterA field that specifies that the frame rate of the video does not match the frame rate of the camera | i.e. a slowed down or sped up video. Can specify either the camera frame rate or the absolute end time.
Set
typeto"trueFrameRate".trueFrameRatenumber
Set
typeto"endingTimestamp".endingTimestampTimestamp
Set
typeto"scaleFactor".scaleFactornumberthe scale factor can be used to calculate whether media duration differs from a video’s | real duration, and if so, the true frame rate of the camera. The video time will thus be scaled | by the ratio of the real duration to media duration, or media frame rate to true frame rate.
allSegmentsMetadataVideoAllSegmentsMetadata
Fields of
VideoAllSegmentsMetadataridstring (RID)
numFramesinteger
numSegmentsinteger
scaleFactornumberdeprecated, in favor of per-file VideoFileSegmentsMetadata scaleFactor. Will be removed after April 15th.
minAbsoluteTimestampTimestamp
maxAbsoluteTimestampTimestampthe timestamp corresponding to absolute starting timestamp plus absolute duration of the video.
mediaDurationSecondsnumber
mediaFrameRatenumberThe average media frame rate (FPS) of the video calculated as total frames / duration in seconds.
minTimestampTimestampdeprecated. Will be removed after April 15th.
maxTimestampTimestampdeprecated. Will be removed after April 15th.
durationSecondsnumberdeprecated. Will be removed after April 15th.
frameRatenumberdeprecated. Will be removed after April 15th.
Request
curl "https://api.gov.nominal.io/api/video/v1/videos/<video rid>" \
-H "Authorization: Bearer <api key>"
import requests
response = requests.get(
"https://api.gov.nominal.io/api/video/v1/videos/<video rid>",
headers={"Authorization": "Bearer <api key>"},
)
response.raise_for_status()
print(response.json())
import httpx
response = httpx.get(
"https://api.gov.nominal.io/api/video/v1/videos/<video rid>",
headers={"Authorization": "Bearer <api key>"},
)
response.raise_for_status()
print(response.json())
import asyncio
import aiohttp
async def main() -> None:
async with aiohttp.ClientSession() as session:
async with session.get(
"https://api.gov.nominal.io/api/video/v1/videos/<video rid>",
headers={"Authorization": "Bearer <api key>"},
) as response:
response.raise_for_status()
print(await response.json())
asyncio.run(main())
Response: 200
{
"rid": "<video rid>",
"title": "<title>",
"description": "<description>",
"labels": [
"<label>"
],
"properties": {
"<key>": "<property value>"
},
"createdBy": "<created by>",
"createdAt": "2026-01-01T00:00:00Z",
"isArchived": true,
"originMetadata": {
"videoSources": [
{
"type": "s3",
"s3": "<s3 path>"
}
],
"timestampManifest": {
"type": "mcap",
"mcap": {
"mcapChannelLocator": {
"type": "topic",
"topic": "<mcap channel topic>"
}
}
}
},
"allSegmentsMetadata": {
"rid": "<video rid>",
"numFrames": 1,
"numSegments": 1,
"scaleFactor": 1,
"minAbsoluteTimestamp": {
"seconds": 1,
"nanos": 1
},
"maxAbsoluteTimestamp": {
"seconds": 1,
"nanos": 1
},
"mediaDurationSeconds": 1,
"mediaFrameRate": 1,
"minTimestamp": {
"seconds": 1,
"nanos": 1
},
"maxTimestamp": {
"seconds": 1,
"nanos": 1
},
"durationSeconds": 1,
"frameRate": 1
}
}
Update metadata#
PUT /video/v1/videos/{videoRid}
Deprecated: Legacy Video-entity API. Videos are now channels on datasets; update dataset metadata with CatalogService#updateDatasetMetadata and per-file titles with batchUpdateVideoChannelDatasetFiles.
Updates the metadata for a video associated with the given video rid.
Path parameters
videoRidstring (RID) required
Body
titlestring
descriptionstring
labelsarray of string
propertiesmap ofPropertyNameto string
startingTimestampTimestamp
Fields of
Timestampsecondsinteger (int64) required
nanosinteger (int64) required
scaleParameterScaleParameterdeprecatedDeprecated: deprecated in favor of updating scaleParameter per-file. Will fail if set on a video with multiple files. Will be removed after April 15th.
Set
typeto"trueFrameRate".trueFrameRatenumber
Set
typeto"endingTimestamp".endingTimestampTimestamp
Set
typeto"scaleFactor".scaleFactornumberthe scale factor can be used to calculate whether media duration differs from a video’s | real duration, and if so, the true frame rate of the camera. The video time will thus be scaled | by the ratio of the real duration to media duration, or media frame rate to true frame rate.
Response
ridstring (RID)
titlestring
descriptionstring
labelsarray of string
propertiesmap ofPropertyNameto string
createdBystring (RID)
createdAtstring (date-time)
isArchivedboolean
originMetadataVideoOriginMetadatadeprecatedDeprecated: deprecated in favor of per-file VideoFileOriginMetadata. Will be removed after April 15th.
Fields of
VideoOriginMetadatavideoSourcesarray ofHandledeprecatedDeprecated: deprecated in favor of per-file VideoFileOriginMetadata. Will be removed after April 15th.
Set
typeto"s3".s3string
timestampManifestVideoTimestampManifestdeprecatedDeprecated: deprecated in favor of per-file VideoFileOriginMetadata. Will be removed after April 15th.
Set
typeto"mcap".mcapMcapTimestampManifest
Fields of
McapTimestampManifestmcapChannelLocatorMcapChannelLocator
Set
typeto"topic".topicstring
Set
typeto"id".idinteger
Set
typeto"s3paths".s3pathsarray of string
Set
typeto"noManifest".noManifestNoTimestampManifest
Fields of
NoTimestampManifeststartingTimestampTimestampSpecifies the original starting timestamp of the video.
Fields of
Timestampsecondsinteger (int64)
nanosinteger (int64)
scaleParameterScaleParameterA field that specifies that the frame rate of the video does not match the frame rate of the camera | i.e. a slowed down or sped up video. Can specify either the camera frame rate or the absolute end time.
Set
typeto"trueFrameRate".trueFrameRatenumber
Set
typeto"endingTimestamp".endingTimestampTimestamp
Set
typeto"scaleFactor".scaleFactornumberthe scale factor can be used to calculate whether media duration differs from a video’s | real duration, and if so, the true frame rate of the camera. The video time will thus be scaled | by the ratio of the real duration to media duration, or media frame rate to true frame rate.
allSegmentsMetadataVideoAllSegmentsMetadata
Fields of
VideoAllSegmentsMetadataridstring (RID)
numFramesinteger
numSegmentsinteger
scaleFactornumberdeprecated, in favor of per-file VideoFileSegmentsMetadata scaleFactor. Will be removed after April 15th.
minAbsoluteTimestampTimestamp
maxAbsoluteTimestampTimestampthe timestamp corresponding to absolute starting timestamp plus absolute duration of the video.
mediaDurationSecondsnumber
mediaFrameRatenumberThe average media frame rate (FPS) of the video calculated as total frames / duration in seconds.
minTimestampTimestampdeprecated. Will be removed after April 15th.
maxTimestampTimestampdeprecated. Will be removed after April 15th.
durationSecondsnumberdeprecated. Will be removed after April 15th.
frameRatenumberdeprecated. Will be removed after April 15th.
Request
curl -X PUT "https://api.gov.nominal.io/api/video/v1/videos/<video rid>" \
-H "Authorization: Bearer <api key>" \
-H "Content-Type: application/json" \
--data '{
"title": "<title>",
"description": "<description>",
"labels": [
"<label>"
],
"properties": {
"<key>": "<property value>"
},
"startingTimestamp": {
"seconds": 1,
"nanos": 1
},
"scaleParameter": {
"type": "trueFrameRate",
"trueFrameRate": 1
}
}'
import requests
response = requests.put(
"https://api.gov.nominal.io/api/video/v1/videos/<video rid>",
headers={"Authorization": "Bearer <api key>"},
json={
"title": "<title>",
"description": "<description>",
"labels": ["<label>"],
"properties": {"<key>": "<property value>"},
"startingTimestamp": {"seconds": 1, "nanos": 1},
"scaleParameter": {"type": "trueFrameRate", "trueFrameRate": 1},
},
)
response.raise_for_status()
print(response.json())
import httpx
response = httpx.put(
"https://api.gov.nominal.io/api/video/v1/videos/<video rid>",
headers={"Authorization": "Bearer <api key>"},
json={
"title": "<title>",
"description": "<description>",
"labels": ["<label>"],
"properties": {"<key>": "<property value>"},
"startingTimestamp": {"seconds": 1, "nanos": 1},
"scaleParameter": {"type": "trueFrameRate", "trueFrameRate": 1},
},
)
response.raise_for_status()
print(response.json())
import asyncio
import aiohttp
async def main() -> None:
async with aiohttp.ClientSession() as session:
async with session.put(
"https://api.gov.nominal.io/api/video/v1/videos/<video rid>",
headers={"Authorization": "Bearer <api key>"},
json={
"title": "<title>",
"description": "<description>",
"labels": ["<label>"],
"properties": {"<key>": "<property value>"},
"startingTimestamp": {"seconds": 1, "nanos": 1},
"scaleParameter": {"type": "trueFrameRate", "trueFrameRate": 1},
},
) as response:
response.raise_for_status()
print(await response.json())
asyncio.run(main())
Response: 200
{
"rid": "<video rid>",
"title": "<title>",
"description": "<description>",
"labels": [
"<label>"
],
"properties": {
"<key>": "<property value>"
},
"createdBy": "<created by>",
"createdAt": "2026-01-01T00:00:00Z",
"isArchived": true,
"originMetadata": {
"videoSources": [
{
"type": "s3",
"s3": "<s3 path>"
}
],
"timestampManifest": {
"type": "mcap",
"mcap": {
"mcapChannelLocator": {
"type": "topic",
"topic": "<mcap channel topic>"
}
}
}
},
"allSegmentsMetadata": {
"rid": "<video rid>",
"numFrames": 1,
"numSegments": 1,
"scaleFactor": 1,
"minAbsoluteTimestamp": {
"seconds": 1,
"nanos": 1
},
"maxAbsoluteTimestamp": {
"seconds": 1,
"nanos": 1
},
"mediaDurationSeconds": 1,
"mediaFrameRate": 1,
"minTimestamp": {
"seconds": 1,
"nanos": 1
},
"maxTimestamp": {
"seconds": 1,
"nanos": 1
},
"durationSeconds": 1,
"frameRate": 1
}
}
Batch get#
POST /video/v1/videos/batchGet
Deprecated: Legacy Video-entity API. Videos are now channels on datasets; list a channel’s files with listVideoChannelDatasetFiles and read dataset metadata from CatalogService.
Returns video metadata about each video given a set of video rids.
Body
videoRidsarray of string (RID)
Response
responsesarray ofVideo
Fields of
Videoridstring (RID)
titlestring
descriptionstring
labelsarray of string
propertiesmap ofPropertyNameto string
createdBystring (RID)
createdAtstring (date-time)
isArchivedboolean
originMetadataVideoOriginMetadatadeprecatedDeprecated: deprecated in favor of per-file VideoFileOriginMetadata. Will be removed after April 15th.
Fields of
VideoOriginMetadatavideoSourcesarray ofHandledeprecatedDeprecated: deprecated in favor of per-file VideoFileOriginMetadata. Will be removed after April 15th.
Set
typeto"s3".s3string
timestampManifestVideoTimestampManifestdeprecatedDeprecated: deprecated in favor of per-file VideoFileOriginMetadata. Will be removed after April 15th.
Set
typeto"mcap".mcapMcapTimestampManifest
Fields of
McapTimestampManifestmcapChannelLocatorMcapChannelLocator
Set
typeto"topic".topicstring
Set
typeto"id".idinteger
Set
typeto"s3paths".s3pathsarray of string
Set
typeto"noManifest".noManifestNoTimestampManifest
Fields of
NoTimestampManifeststartingTimestampTimestampSpecifies the original starting timestamp of the video.
Fields of
Timestampsecondsinteger (int64)
nanosinteger (int64)
scaleParameterScaleParameterA field that specifies that the frame rate of the video does not match the frame rate of the camera | i.e. a slowed down or sped up video. Can specify either the camera frame rate or the absolute end time.
Set
typeto"trueFrameRate".trueFrameRatenumber
Set
typeto"endingTimestamp".endingTimestampTimestamp
Set
typeto"scaleFactor".scaleFactornumberthe scale factor can be used to calculate whether media duration differs from a video’s | real duration, and if so, the true frame rate of the camera. The video time will thus be scaled | by the ratio of the real duration to media duration, or media frame rate to true frame rate.
allSegmentsMetadataVideoAllSegmentsMetadata
Fields of
VideoAllSegmentsMetadataridstring (RID)
numFramesinteger
numSegmentsinteger
scaleFactornumberdeprecated, in favor of per-file VideoFileSegmentsMetadata scaleFactor. Will be removed after April 15th.
minAbsoluteTimestampTimestamp
maxAbsoluteTimestampTimestampthe timestamp corresponding to absolute starting timestamp plus absolute duration of the video.
mediaDurationSecondsnumber
mediaFrameRatenumberThe average media frame rate (FPS) of the video calculated as total frames / duration in seconds.
minTimestampTimestampdeprecated. Will be removed after April 15th.
maxTimestampTimestampdeprecated. Will be removed after April 15th.
durationSecondsnumberdeprecated. Will be removed after April 15th.
frameRatenumberdeprecated. Will be removed after April 15th.
Request
curl -X POST "https://api.gov.nominal.io/api/video/v1/videos/batchGet" \
-H "Authorization: Bearer <api key>" \
-H "Content-Type: application/json" \
--data '{
"videoRids": [
"<video rid>"
]
}'
import requests
response = requests.post(
"https://api.gov.nominal.io/api/video/v1/videos/batchGet",
headers={"Authorization": "Bearer <api key>"},
json={"videoRids": ["<video rid>"]},
)
response.raise_for_status()
print(response.json())
import httpx
response = httpx.post(
"https://api.gov.nominal.io/api/video/v1/videos/batchGet",
headers={"Authorization": "Bearer <api key>"},
json={"videoRids": ["<video rid>"]},
)
response.raise_for_status()
print(response.json())
import asyncio
import aiohttp
async def main() -> None:
async with aiohttp.ClientSession() as session:
async with session.post(
"https://api.gov.nominal.io/api/video/v1/videos/batchGet",
headers={"Authorization": "Bearer <api key>"},
json={"videoRids": ["<video rid>"]},
) as response:
response.raise_for_status()
print(await response.json())
asyncio.run(main())
Response: 200
{
"responses": [
{
"rid": "<video rid>",
"title": "<title>",
"description": "<description>",
"labels": [
"<label>"
],
"properties": {
"<key>": "<property value>"
},
"createdBy": "<created by>",
"createdAt": "2026-01-01T00:00:00Z",
"isArchived": true,
"originMetadata": {
"videoSources": [
{
"type": "s3",
"s3": "<s3 path>"
}
],
"timestampManifest": {
"type": "mcap",
"mcap": {
"mcapChannelLocator": {
"type": "topic",
"topic": "<mcap channel topic>"
}
}
}
},
"allSegmentsMetadata": {
"rid": "<video rid>",
"numFrames": 1,
"numSegments": 1,
"scaleFactor": 1,
"minAbsoluteTimestamp": {
"seconds": 1,
"nanos": 1
},
"maxAbsoluteTimestamp": {
"seconds": 1,
"nanos": 1
},
"mediaDurationSeconds": 1,
"mediaFrameRate": 1,
"minTimestamp": {
"seconds": 1,
"nanos": 1
},
"maxTimestamp": {
"seconds": 1,
"nanos": 1
},
"durationSeconds": 1,
"frameRate": 1
}
}
]
}
Search#
POST /video/v1/videos/search
Deprecated: Legacy Video-entity API. Videos are now channels on datasets; search datasets with CatalogService#searchDatasets.
Returns metadata about videos that match a given query.
Body
querySearchVideosQueryrequired
Set
typeto"searchText".searchTextstring
Set
typeto"label".labelstring
Set
typeto"property".propertyProperty
Fields of
Propertynamestring required
valuestring required
Set
typeto"and".andarray ofSearchVideosQuery
Set
typeto"or".orarray ofSearchVideosQuery
Set
typeto"ingestStatus".ingestStatusIngestStatus
Values of
IngestStatusSUCCEEDED
FAILED
IN_PROGRESS
Set
typeto"workspace".workspacestring (RID)
pageSizeintegerDefaults to 100. Will throw if larger than 1_000.
tokenstring
sortOptionsSortOptionsrequired
Fields of
SortOptionsisDescendingboolean required
fieldSortFieldrequired
Values of
SortFieldCREATED_AT
archivedStatusesarray ofArchivedStatusDefault search status is NOT_ARCHIVED if none are provided. Allows for including archived videos in search.
Values of
ArchivedStatusNOT_ARCHIVED
ARCHIVED
Response
resultsarray ofVideo
Fields of
Videoridstring (RID)
titlestring
descriptionstring
labelsarray of string
propertiesmap ofPropertyNameto string
createdBystring (RID)
createdAtstring (date-time)
isArchivedboolean
originMetadataVideoOriginMetadatadeprecatedDeprecated: deprecated in favor of per-file VideoFileOriginMetadata. Will be removed after April 15th.
Fields of
VideoOriginMetadatavideoSourcesarray ofHandledeprecatedDeprecated: deprecated in favor of per-file VideoFileOriginMetadata. Will be removed after April 15th.
Set
typeto"s3".s3string
timestampManifestVideoTimestampManifestdeprecatedDeprecated: deprecated in favor of per-file VideoFileOriginMetadata. Will be removed after April 15th.
Set
typeto"mcap".mcapMcapTimestampManifest
Fields of
McapTimestampManifestmcapChannelLocatorMcapChannelLocator
Set
typeto"topic".topicstring
Set
typeto"id".idinteger
Set
typeto"s3paths".s3pathsarray of string
Set
typeto"noManifest".noManifestNoTimestampManifest
Fields of
NoTimestampManifeststartingTimestampTimestampSpecifies the original starting timestamp of the video.
Fields of
Timestampsecondsinteger (int64)
nanosinteger (int64)
scaleParameterScaleParameterA field that specifies that the frame rate of the video does not match the frame rate of the camera | i.e. a slowed down or sped up video. Can specify either the camera frame rate or the absolute end time.
Set
typeto"trueFrameRate".trueFrameRatenumber
Set
typeto"endingTimestamp".endingTimestampTimestamp
Set
typeto"scaleFactor".scaleFactornumberthe scale factor can be used to calculate whether media duration differs from a video’s | real duration, and if so, the true frame rate of the camera. The video time will thus be scaled | by the ratio of the real duration to media duration, or media frame rate to true frame rate.
allSegmentsMetadataVideoAllSegmentsMetadata
Fields of
VideoAllSegmentsMetadataridstring (RID)
numFramesinteger
numSegmentsinteger
scaleFactornumberdeprecated, in favor of per-file VideoFileSegmentsMetadata scaleFactor. Will be removed after April 15th.
minAbsoluteTimestampTimestamp
maxAbsoluteTimestampTimestampthe timestamp corresponding to absolute starting timestamp plus absolute duration of the video.
mediaDurationSecondsnumber
mediaFrameRatenumberThe average media frame rate (FPS) of the video calculated as total frames / duration in seconds.
minTimestampTimestampdeprecated. Will be removed after April 15th.
maxTimestampTimestampdeprecated. Will be removed after April 15th.
durationSecondsnumberdeprecated. Will be removed after April 15th.
frameRatenumberdeprecated. Will be removed after April 15th.
nextPageTokenstring
Request
curl -X POST "https://api.gov.nominal.io/api/video/v1/videos/search" \
-H "Authorization: Bearer <api key>" \
-H "Content-Type: application/json" \
--data '{
"query": {
"type": "searchText",
"searchText": "<search text>"
},
"sortOptions": {
"isDescending": true,
"field": "CREATED_AT"
}
}'
import requests
response = requests.post(
"https://api.gov.nominal.io/api/video/v1/videos/search",
headers={"Authorization": "Bearer <api key>"},
json={
"query": {"type": "searchText", "searchText": "<search text>"},
"sortOptions": {"isDescending": True, "field": "CREATED_AT"},
},
)
response.raise_for_status()
print(response.json())
import httpx
response = httpx.post(
"https://api.gov.nominal.io/api/video/v1/videos/search",
headers={"Authorization": "Bearer <api key>"},
json={
"query": {"type": "searchText", "searchText": "<search text>"},
"sortOptions": {"isDescending": True, "field": "CREATED_AT"},
},
)
response.raise_for_status()
print(response.json())
import asyncio
import aiohttp
async def main() -> None:
async with aiohttp.ClientSession() as session:
async with session.post(
"https://api.gov.nominal.io/api/video/v1/videos/search",
headers={"Authorization": "Bearer <api key>"},
json={
"query": {"type": "searchText", "searchText": "<search text>"},
"sortOptions": {"isDescending": True, "field": "CREATED_AT"},
},
) as response:
response.raise_for_status()
print(await response.json())
asyncio.run(main())
Response: 200
{
"results": [
{
"rid": "<video rid>",
"title": "<title>",
"description": "<description>",
"labels": [
"<label>"
],
"properties": {
"<key>": "<property value>"
},
"createdBy": "<created by>",
"createdAt": "2026-01-01T00:00:00Z",
"isArchived": true,
"originMetadata": {
"videoSources": [
{
"type": "s3",
"s3": "<s3 path>"
}
],
"timestampManifest": {
"type": "mcap",
"mcap": {
"mcapChannelLocator": {
"type": "topic",
"topic": "<mcap channel topic>"
}
}
}
},
"allSegmentsMetadata": {
"rid": "<video rid>",
"numFrames": 1,
"numSegments": 1,
"scaleFactor": 1,
"minAbsoluteTimestamp": {
"seconds": 1,
"nanos": 1
},
"maxAbsoluteTimestamp": {
"seconds": 1,
"nanos": 1
},
"mediaDurationSeconds": 1,
"mediaFrameRate": 1,
"minTimestamp": {
"seconds": 1,
"nanos": 1
},
"maxTimestamp": {
"seconds": 1,
"nanos": 1
},
"durationSeconds": 1,
"frameRate": 1
}
}
],
"nextPageToken": "<token>"
}
Create#
POST /video/v1/videos
Deprecated: Legacy Video-entity API. Videos are now channels on datasets; ingest with videoV2 options targeting a dataset channel instead of creating a Video.
Creates and persists a video entity with the given metadata.
Body
titlestring required
descriptionstring
labelsarray of string
propertiesmap ofPropertyNameto string
originMetadataVideoOriginMetadatadeprecatedDeprecated: deprecated in favor of per-file VideoFileOriginMetadata. Will be removed after April 15th.
Fields of
VideoOriginMetadatavideoSourcesarray ofHandledeprecatedDeprecated: deprecated in favor of per-file VideoFileOriginMetadata. Will be removed after April 15th.
Set
typeto"s3".s3string
timestampManifestVideoTimestampManifestrequired deprecatedDeprecated: deprecated in favor of per-file VideoFileOriginMetadata. Will be removed after April 15th.
Set
typeto"mcap".mcapMcapTimestampManifest
Fields of
McapTimestampManifestmcapChannelLocatorMcapChannelLocatorrequired
Set
typeto"topic".topicstring
Set
typeto"id".idinteger
Set
typeto"s3paths".s3pathsarray of string
Set
typeto"noManifest".noManifestNoTimestampManifest
Fields of
NoTimestampManifeststartingTimestampTimestamprequiredSpecifies the original starting timestamp of the video.
Fields of
Timestampsecondsinteger (int64) required
nanosinteger (int64) required
scaleParameterScaleParameterA field that specifies that the frame rate of the video does not match the frame rate of the camera | i.e. a slowed down or sped up video. Can specify either the camera frame rate or the absolute end time.
Set
typeto"trueFrameRate".trueFrameRatenumber
Set
typeto"endingTimestamp".endingTimestampTimestamp
Set
typeto"scaleFactor".scaleFactornumberthe scale factor can be used to calculate whether media duration differs from a video’s | real duration, and if so, the true frame rate of the camera. The video time will thus be scaled | by the ratio of the real duration to media duration, or media frame rate to true frame rate.
workspacestring (RID)The workspace in which to create the video. If not provided, the video will be created in the default workspace for the user’s organization, if the default workspace for the organization is configured.
markingRidsarray of string (RID)The markings to apply to the created video. If not provided, the video will be visible to all users in the same workspace.
Response
ridstring (RID)
titlestring
descriptionstring
labelsarray of string
propertiesmap ofPropertyNameto string
createdBystring (RID)
createdAtstring (date-time)
isArchivedboolean
originMetadataVideoOriginMetadatadeprecatedDeprecated: deprecated in favor of per-file VideoFileOriginMetadata. Will be removed after April 15th.
Fields of
VideoOriginMetadatavideoSourcesarray ofHandledeprecatedDeprecated: deprecated in favor of per-file VideoFileOriginMetadata. Will be removed after April 15th.
Set
typeto"s3".s3string
timestampManifestVideoTimestampManifestdeprecatedDeprecated: deprecated in favor of per-file VideoFileOriginMetadata. Will be removed after April 15th.
Set
typeto"mcap".mcapMcapTimestampManifest
Fields of
McapTimestampManifestmcapChannelLocatorMcapChannelLocator
Set
typeto"topic".topicstring
Set
typeto"id".idinteger
Set
typeto"s3paths".s3pathsarray of string
Set
typeto"noManifest".noManifestNoTimestampManifest
Fields of
NoTimestampManifeststartingTimestampTimestampSpecifies the original starting timestamp of the video.
Fields of
Timestampsecondsinteger (int64)
nanosinteger (int64)
scaleParameterScaleParameterA field that specifies that the frame rate of the video does not match the frame rate of the camera | i.e. a slowed down or sped up video. Can specify either the camera frame rate or the absolute end time.
Set
typeto"trueFrameRate".trueFrameRatenumber
Set
typeto"endingTimestamp".endingTimestampTimestamp
Set
typeto"scaleFactor".scaleFactornumberthe scale factor can be used to calculate whether media duration differs from a video’s | real duration, and if so, the true frame rate of the camera. The video time will thus be scaled | by the ratio of the real duration to media duration, or media frame rate to true frame rate.
allSegmentsMetadataVideoAllSegmentsMetadata
Fields of
VideoAllSegmentsMetadataridstring (RID)
numFramesinteger
numSegmentsinteger
scaleFactornumberdeprecated, in favor of per-file VideoFileSegmentsMetadata scaleFactor. Will be removed after April 15th.
minAbsoluteTimestampTimestamp
maxAbsoluteTimestampTimestampthe timestamp corresponding to absolute starting timestamp plus absolute duration of the video.
mediaDurationSecondsnumber
mediaFrameRatenumberThe average media frame rate (FPS) of the video calculated as total frames / duration in seconds.
minTimestampTimestampdeprecated. Will be removed after April 15th.
maxTimestampTimestampdeprecated. Will be removed after April 15th.
durationSecondsnumberdeprecated. Will be removed after April 15th.
frameRatenumberdeprecated. Will be removed after April 15th.
Request
curl -X POST "https://api.gov.nominal.io/api/video/v1/videos" \
-H "Authorization: Bearer <api key>" \
-H "Content-Type: application/json" \
--data '{
"title": "<title>"
}'
import requests
response = requests.post(
"https://api.gov.nominal.io/api/video/v1/videos",
headers={"Authorization": "Bearer <api key>"},
json={"title": "<title>"},
)
response.raise_for_status()
print(response.json())
import httpx
response = httpx.post(
"https://api.gov.nominal.io/api/video/v1/videos",
headers={"Authorization": "Bearer <api key>"},
json={"title": "<title>"},
)
response.raise_for_status()
print(response.json())
import asyncio
import aiohttp
async def main() -> None:
async with aiohttp.ClientSession() as session:
async with session.post(
"https://api.gov.nominal.io/api/video/v1/videos",
headers={"Authorization": "Bearer <api key>"},
json={"title": "<title>"},
) as response:
response.raise_for_status()
print(await response.json())
asyncio.run(main())
Response: 200
{
"rid": "<video rid>",
"title": "<title>",
"description": "<description>",
"labels": [
"<label>"
],
"properties": {
"<key>": "<property value>"
},
"createdBy": "<created by>",
"createdAt": "2026-01-01T00:00:00Z",
"isArchived": true,
"originMetadata": {
"videoSources": [
{
"type": "s3",
"s3": "<s3 path>"
}
],
"timestampManifest": {
"type": "mcap",
"mcap": {
"mcapChannelLocator": {
"type": "topic",
"topic": "<mcap channel topic>"
}
}
}
},
"allSegmentsMetadata": {
"rid": "<video rid>",
"numFrames": 1,
"numSegments": 1,
"scaleFactor": 1,
"minAbsoluteTimestamp": {
"seconds": 1,
"nanos": 1
},
"maxAbsoluteTimestamp": {
"seconds": 1,
"nanos": 1
},
"mediaDurationSeconds": 1,
"mediaFrameRate": 1,
"minTimestamp": {
"seconds": 1,
"nanos": 1
},
"maxTimestamp": {
"seconds": 1,
"nanos": 1
},
"durationSeconds": 1,
"frameRate": 1
}
}
Get ingest status#
GET /video/v1/videos/{videoRid}/ingest-status
Deprecated: Legacy Video-entity API. Videos are now channels on datasets; ingest status is tracked per file on the Catalog dataset file (CatalogService#getDatasetFile).
Path parameters
videoRidstring (RID) required
Response
A DetailedIngestStatus union.
Set type to "success".
successSuccessIngestStatus
Set type to "error".
errorErrorIngestStatus
Fields of
ErrorIngestStatuserrorsarray ofIngestError
Fields of
IngestErrorerrorTypestring
messagestring
errorInstanceIdstring
Set type to "inProgress".
inProgressnumberA number between 0 and 1 representing percentage progress.
Request
curl "https://api.gov.nominal.io/api/video/v1/videos/<video rid>/ingest-status" \
-H "Authorization: Bearer <api key>"
import requests
response = requests.get(
"https://api.gov.nominal.io/api/video/v1/videos/<video rid>/ingest-status",
headers={"Authorization": "Bearer <api key>"},
)
response.raise_for_status()
print(response.json())
import httpx
response = httpx.get(
"https://api.gov.nominal.io/api/video/v1/videos/<video rid>/ingest-status",
headers={"Authorization": "Bearer <api key>"},
)
response.raise_for_status()
print(response.json())
import asyncio
import aiohttp
async def main() -> None:
async with aiohttp.ClientSession() as session:
async with session.get(
"https://api.gov.nominal.io/api/video/v1/videos/<video rid>/ingest-status",
headers={"Authorization": "Bearer <api key>"},
) as response:
response.raise_for_status()
print(await response.json())
asyncio.run(main())
Response: 200
{
"type": "success",
"success": {}
}
Batch get ingest status#
POST /video/v1/videos/batch-get-ingest-status
Deprecated: Legacy Video-entity API. Videos are now channels on datasets; ingest status is tracked per file on the Catalog dataset file (CatalogService#batchGetDatasetFiles).
Body
The body is an array of string (RID).
Response
The body is a map of VideoRid to DetailedIngestStatus.
Set type to "success".
successSuccessIngestStatus
Set type to "error".
errorErrorIngestStatus
Fields of
ErrorIngestStatuserrorsarray ofIngestError
Fields of
IngestErrorerrorTypestring
messagestring
errorInstanceIdstring
Set type to "inProgress".
inProgressnumberA number between 0 and 1 representing percentage progress.
Request
curl -X POST "https://api.gov.nominal.io/api/video/v1/videos/batch-get-ingest-status" \
-H "Authorization: Bearer <api key>" \
-H "Content-Type: application/json" \
--data '[
"<video rid>"
]'
import requests
response = requests.post(
"https://api.gov.nominal.io/api/video/v1/videos/batch-get-ingest-status",
headers={"Authorization": "Bearer <api key>"},
json=["<video rid>"],
)
response.raise_for_status()
print(response.json())
import httpx
response = httpx.post(
"https://api.gov.nominal.io/api/video/v1/videos/batch-get-ingest-status",
headers={"Authorization": "Bearer <api key>"},
json=["<video rid>"],
)
response.raise_for_status()
print(response.json())
import asyncio
import aiohttp
async def main() -> None:
async with aiohttp.ClientSession() as session:
async with session.post(
"https://api.gov.nominal.io/api/video/v1/videos/batch-get-ingest-status",
headers={"Authorization": "Bearer <api key>"},
json=["<video rid>"],
) as response:
response.raise_for_status()
print(await response.json())
asyncio.run(main())
Response: 200
{
"<key>": {
"type": "success",
"success": {}
}
}
Get enriched ingest status#
POST /video/v1/videos/enriched-ingest-status
Deprecated: Legacy Video-entity API. Videos are now channels on datasets; ingest status is tracked per file on the Catalog dataset file (CatalogService#getDatasetFile).
Body
videoRidstring (RID) required
tokenstring
Response
statusVideoIngestStatus
fileIngestStatusmap ofVideoFileRidtoVideoFileIngestStatus
Set
typeto"success".successSuccessIngestStatus
Set
typeto"error".errorIngestError
Fields of
IngestErrorerrorTypestring
messagestring
errorInstanceIdstring
Set
typeto"inProgress".inProgressEmpty
nextPageTokenstring
When there is nothing to return, the response is HTTP 204 with no body.
Request
curl -X POST "https://api.gov.nominal.io/api/video/v1/videos/enriched-ingest-status" \
-H "Authorization: Bearer <api key>" \
-H "Content-Type: application/json" \
--data '{
"videoRid": "<video rid>"
}'
import requests
response = requests.post(
"https://api.gov.nominal.io/api/video/v1/videos/enriched-ingest-status",
headers={"Authorization": "Bearer <api key>"},
json={"videoRid": "<video rid>"},
)
response.raise_for_status()
print(response.json())
import httpx
response = httpx.post(
"https://api.gov.nominal.io/api/video/v1/videos/enriched-ingest-status",
headers={"Authorization": "Bearer <api key>"},
json={"videoRid": "<video rid>"},
)
response.raise_for_status()
print(response.json())
import asyncio
import aiohttp
async def main() -> None:
async with aiohttp.ClientSession() as session:
async with session.post(
"https://api.gov.nominal.io/api/video/v1/videos/enriched-ingest-status",
headers={"Authorization": "Bearer <api key>"},
json={"videoRid": "<video rid>"},
) as response:
response.raise_for_status()
print(await response.json())
asyncio.run(main())
Response: 200
{
"status": {
"type": "ready",
"ready": {}
},
"fileIngestStatus": {
"<key>": {
"type": "success",
"success": {}
}
},
"nextPageToken": "<token>"
}
Archive#
PUT /video/v1/videos/{videoRid}/archive
Deprecated: Legacy Video-entity API. Videos are now channels on datasets; archive the backing dataset with CatalogService#archiveDataset, or delete individual files with IngestService#deleteFile.
Archives a video, which excludes it from search and hides it from being publicly visible, but does not permanently delete it. Archived videos can be unarchived.
Path parameters
videoRidstring (RID) required
Response
No content (HTTP 204).
Request
curl -X PUT "https://api.gov.nominal.io/api/video/v1/videos/<video rid>/archive" \
-H "Authorization: Bearer <api key>"
import requests
response = requests.put(
"https://api.gov.nominal.io/api/video/v1/videos/<video rid>/archive",
headers={"Authorization": "Bearer <api key>"},
)
response.raise_for_status()
import httpx
response = httpx.put(
"https://api.gov.nominal.io/api/video/v1/videos/<video rid>/archive",
headers={"Authorization": "Bearer <api key>"},
)
response.raise_for_status()
import asyncio
import aiohttp
async def main() -> None:
async with aiohttp.ClientSession() as session:
async with session.put(
"https://api.gov.nominal.io/api/video/v1/videos/<video rid>/archive",
headers={"Authorization": "Bearer <api key>"},
) as response:
response.raise_for_status()
asyncio.run(main())
Response: 204
No content.
Unarchive#
PUT /video/v1/videos/{videoRid}/unarchive
Deprecated: Legacy Video-entity API. Videos are now channels on datasets; unarchive the backing dataset with CatalogService#unarchiveDataset.
Unarchives a previously archived video.
Path parameters
videoRidstring (RID) required
Response
No content (HTTP 204).
Request
curl -X PUT "https://api.gov.nominal.io/api/video/v1/videos/<video rid>/unarchive" \
-H "Authorization: Bearer <api key>"
import requests
response = requests.put(
"https://api.gov.nominal.io/api/video/v1/videos/<video rid>/unarchive",
headers={"Authorization": "Bearer <api key>"},
)
response.raise_for_status()
import httpx
response = httpx.put(
"https://api.gov.nominal.io/api/video/v1/videos/<video rid>/unarchive",
headers={"Authorization": "Bearer <api key>"},
)
response.raise_for_status()
import asyncio
import aiohttp
async def main() -> None:
async with aiohttp.ClientSession() as session:
async with session.put(
"https://api.gov.nominal.io/api/video/v1/videos/<video rid>/unarchive",
headers={"Authorization": "Bearer <api key>"},
) as response:
response.raise_for_status()
asyncio.run(main())
Response: 204
No content.
Get playlist#
GET /video/v1/videos/{videoRid}/playlist
Deprecated: Replaced by getPlaylistV2, which addresses the video channel series (channel + tags) instead of a Video rid.
Generates an HLS playlist for a video within optional time bounds. Uses GET with query parameters for HLS.js compatibility. The HLS playlist will contain links to all of the segments in the video that overlap with the given bounds, or all segments if no bounds are provided.
Note: The start and end parameters must either both be provided or both be omitted. Providing only one will result in a MissingTimestampBoundPair error.
Path parameters
videoRidstring (RID) required
Query parameters
startstringStart bound as ISO-8601 timestamp (e.g., “2024-01-01T00:00:00Z”). Must be provided together with end, or neither.
endstringEnd bound as ISO-8601 timestamp (e.g., “2024-01-01T01:00:00Z”). Must be provided together with start, or neither.
Response: application/octet-stream
The body is the raw bytes.
A successful response.
Request
curl "https://api.gov.nominal.io/api/video/v1/videos/<video rid>/playlist" \
-H "Authorization: Bearer <api key>" \
--output "<file>"
from pathlib import Path
import requests
response = requests.get(
"https://api.gov.nominal.io/api/video/v1/videos/<video rid>/playlist",
headers={"Authorization": "Bearer <api key>"},
)
response.raise_for_status()
Path("<file>").write_bytes(response.content)
from pathlib import Path
import httpx
response = httpx.get(
"https://api.gov.nominal.io/api/video/v1/videos/<video rid>/playlist",
headers={"Authorization": "Bearer <api key>"},
)
response.raise_for_status()
Path("<file>").write_bytes(response.content)
import asyncio
from pathlib import Path
import aiohttp
async def main() -> None:
async with aiohttp.ClientSession() as session:
async with session.get(
"https://api.gov.nominal.io/api/video/v1/videos/<video rid>/playlist",
headers={"Authorization": "Bearer <api key>"},
) as response:
response.raise_for_status()
Path("<file>").write_bytes(await response.read())
asyncio.run(main())
Response: 200
The raw bytes.
Get segment summaries#
GET /video/v1/videos/{videoRid}/segment-summaries
Deprecated: Replaced by getSegmentSummariesInBounds. Will be removed after April 15th.
Returns the min and max absolute and media timestamps for each segment in a video. To be used during frame-timestamp mapping.
Path parameters
videoRidstring (RID) required
Response
The body is an array of SegmentSummary.
Request
curl "https://api.gov.nominal.io/api/video/v1/videos/<video rid>/segment-summaries" \
-H "Authorization: Bearer <api key>"
import requests
response = requests.get(
"https://api.gov.nominal.io/api/video/v1/videos/<video rid>/segment-summaries",
headers={"Authorization": "Bearer <api key>"},
)
response.raise_for_status()
print(response.json())
import httpx
response = httpx.get(
"https://api.gov.nominal.io/api/video/v1/videos/<video rid>/segment-summaries",
headers={"Authorization": "Bearer <api key>"},
)
response.raise_for_status()
print(response.json())
import asyncio
import aiohttp
async def main() -> None:
async with aiohttp.ClientSession() as session:
async with session.get(
"https://api.gov.nominal.io/api/video/v1/videos/<video rid>/segment-summaries",
headers={"Authorization": "Bearer <api key>"},
) as response:
response.raise_for_status()
print(await response.json())
asyncio.run(main())
Response: 200
[
{
"minAbsoluteTimestamp": {
"seconds": 1,
"nanos": 1
},
"maxAbsoluteTimestamp": {
"seconds": 1,
"nanos": 1
},
"minMediaTimestamp": 1,
"maxMediaTimestamp": 1
}
]
Get playlist in bounds#
POST /video/v1/videos/{videoRid}/playlist-in-bounds
Deprecated: Use getPlaylist (GET) for HLS.js compatibility.
Generates an HLS playlist for a video with the given video rid to enable playback within an optional set of bounds. The HLS playlist will contain links to all of the segments in the video that overlap with the given bounds. playlist will be limited to the given bounds.
Path parameters
videoRidstring (RID) required
Body
boundsBounds
Response: application/octet-stream
The body is the raw bytes.
A successful response.
Request
curl -X POST "https://api.gov.nominal.io/api/video/v1/videos/<video rid>/playlist-in-bounds" \
-H "Authorization: Bearer <api key>" \
-H "Content-Type: application/json" \
--data '{
"bounds": {
"start": {
"seconds": 1,
"nanos": 1
},
"end": {
"seconds": 1,
"nanos": 1
}
}
}' \
--output "<file>"
from pathlib import Path
import requests
response = requests.post(
"https://api.gov.nominal.io/api/video/v1/videos/<video rid>/playlist-in-bounds",
headers={"Authorization": "Bearer <api key>"},
json={
"bounds": {
"start": {"seconds": 1, "nanos": 1},
"end": {"seconds": 1, "nanos": 1},
},
},
)
response.raise_for_status()
Path("<file>").write_bytes(response.content)
from pathlib import Path
import httpx
response = httpx.post(
"https://api.gov.nominal.io/api/video/v1/videos/<video rid>/playlist-in-bounds",
headers={"Authorization": "Bearer <api key>"},
json={
"bounds": {
"start": {"seconds": 1, "nanos": 1},
"end": {"seconds": 1, "nanos": 1},
},
},
)
response.raise_for_status()
Path("<file>").write_bytes(response.content)
import asyncio
from pathlib import Path
import aiohttp
async def main() -> None:
async with aiohttp.ClientSession() as session:
async with session.post(
"https://api.gov.nominal.io/api/video/v1/videos/<video rid>/playlist-in-bounds",
headers={"Authorization": "Bearer <api key>"},
json={
"bounds": {
"start": {"seconds": 1, "nanos": 1},
"end": {"seconds": 1, "nanos": 1},
},
},
) as response:
response.raise_for_status()
Path("<file>").write_bytes(await response.read())
asyncio.run(main())
Response: 200
The raw bytes.
Get playlist in bounds v2#
POST /video/v2/videos/playlist-in-bounds
Deprecated: Use getPlaylistV2 (GET) for HLS.js compatibility.
Generates an HLS playlist for a video series (identified by channel + tags) within bounds.
Body
channelSeriesVideoChannelSeriesrequired
Set
typeto"dataSource".dataSourceVideoDataSourceChannel
Fields of
VideoDataSourceChanneldataSourceRidstring required
channelstring required
tagsmap ofTagNameto string
Set
typeto"asset".assetVideoAssetChannel
Fields of
VideoAssetChannelassetRidstring required
dataScopeNamestring required
channelstring required
tagsmap ofTagNameto string
boundsBoundsrequired
Response: application/octet-stream
The body is the raw bytes.
A successful response.
Request
curl -X POST "https://api.gov.nominal.io/api/video/v2/videos/playlist-in-bounds" \
-H "Authorization: Bearer <api key>" \
-H "Content-Type: application/json" \
--data '{
"channelSeries": {
"type": "dataSource",
"dataSource": {
"dataSourceRid": "<data source rid>",
"channel": "<channel>"
}
},
"bounds": {
"start": {
"seconds": 1,
"nanos": 1
},
"end": {
"seconds": 1,
"nanos": 1
}
}
}' \
--output "<file>"
from pathlib import Path
import requests
response = requests.post(
"https://api.gov.nominal.io/api/video/v2/videos/playlist-in-bounds",
headers={"Authorization": "Bearer <api key>"},
json={
"channelSeries": {
"type": "dataSource",
"dataSource": {"dataSourceRid": "<data source rid>", "channel": "<channel>"},
},
"bounds": {
"start": {"seconds": 1, "nanos": 1},
"end": {"seconds": 1, "nanos": 1},
},
},
)
response.raise_for_status()
Path("<file>").write_bytes(response.content)
from pathlib import Path
import httpx
response = httpx.post(
"https://api.gov.nominal.io/api/video/v2/videos/playlist-in-bounds",
headers={"Authorization": "Bearer <api key>"},
json={
"channelSeries": {
"type": "dataSource",
"dataSource": {"dataSourceRid": "<data source rid>", "channel": "<channel>"},
},
"bounds": {
"start": {"seconds": 1, "nanos": 1},
"end": {"seconds": 1, "nanos": 1},
},
},
)
response.raise_for_status()
Path("<file>").write_bytes(response.content)
import asyncio
from pathlib import Path
import aiohttp
async def main() -> None:
async with aiohttp.ClientSession() as session:
async with session.post(
"https://api.gov.nominal.io/api/video/v2/videos/playlist-in-bounds",
headers={"Authorization": "Bearer <api key>"},
json={
"channelSeries": {
"type": "dataSource",
"dataSource": {
"dataSourceRid": "<data source rid>",
"channel": "<channel>",
},
},
"bounds": {
"start": {"seconds": 1, "nanos": 1},
"end": {"seconds": 1, "nanos": 1},
},
},
) as response:
response.raise_for_status()
Path("<file>").write_bytes(await response.read())
asyncio.run(main())
Response: 200
The raw bytes.
Get playlist v2#
GET /video/v2/videos/playlist
Generates an HLS playlist for a video series within time bounds. Specify either dataSourceRid OR (assetRid + dataScopeName) to identify the series source.
Note: Both start and end parameters are required and must be provided together.
Query parameters
dataSourceRidstring (RID)Data source RID (mutually exclusive with assetRid)
assetRidstring (RID)Asset RID (mutually exclusive with dataSourceRid, requires dataScopeName)
dataScopeNamestringData scope name (required when using assetRid)
channelstring requiredChannel name
tagsstringTags as JSON-encoded map (e.g., {“vehicle”:”car1”})
startstring requiredRequired start bound as ISO-8601 timestamp (e.g., “2024-01-01T00:00:00Z”). Must be provided with end.
endstring requiredRequired end bound as ISO-8601 timestamp (e.g., “2024-01-01T01:00:00Z”). Must be provided with start.
Response: application/octet-stream
The body is the raw bytes.
A successful response.
Request
curl "https://api.gov.nominal.io/api/video/v2/videos/playlist?channel=<channel>&start=<start>&end=<end>" \
-H "Authorization: Bearer <api key>" \
--output "<file>"
from pathlib import Path
import requests
response = requests.get(
"https://api.gov.nominal.io/api/video/v2/videos/playlist?channel=<channel>&start=<start>&end=<end>",
headers={"Authorization": "Bearer <api key>"},
)
response.raise_for_status()
Path("<file>").write_bytes(response.content)
from pathlib import Path
import httpx
response = httpx.get(
"https://api.gov.nominal.io/api/video/v2/videos/playlist?channel=<channel>&start=<start>&end=<end>",
headers={"Authorization": "Bearer <api key>"},
)
response.raise_for_status()
Path("<file>").write_bytes(response.content)
import asyncio
from pathlib import Path
import aiohttp
async def main() -> None:
async with aiohttp.ClientSession() as session:
async with session.get(
"https://api.gov.nominal.io/api/video/v2/videos/playlist?channel=<channel>&start=<start>&end=<end>",
headers={"Authorization": "Bearer <api key>"},
) as response:
response.raise_for_status()
Path("<file>").write_bytes(await response.read())
asyncio.run(main())
Response: 200
The raw bytes.
Get segment summaries in bounds#
POST /video/v1/videos/{videoRid}/segment-summaries-in-bounds
Deprecated: Replaced by getSegmentSummariesInBoundsV2, which addresses the video channel series (channel + tags) instead of a Video rid.
Returns the min and max absolute and media timestamps for each segment in a video that overlap with an optional set of bounds.
Path parameters
videoRidstring (RID) required
Body
boundsBounds
Response
The body is an array of SegmentSummary.
Request
curl -X POST "https://api.gov.nominal.io/api/video/v1/videos/<video rid>/segment-summaries-in-bounds" \
-H "Authorization: Bearer <api key>" \
-H "Content-Type: application/json" \
--data '{
"bounds": {
"start": {
"seconds": 1,
"nanos": 1
},
"end": {
"seconds": 1,
"nanos": 1
}
}
}'
import requests
response = requests.post(
"https://api.gov.nominal.io/api/video/v1/videos/<video rid>/segment-summaries-in-bounds",
headers={"Authorization": "Bearer <api key>"},
json={
"bounds": {
"start": {"seconds": 1, "nanos": 1},
"end": {"seconds": 1, "nanos": 1},
},
},
)
response.raise_for_status()
print(response.json())
import httpx
response = httpx.post(
"https://api.gov.nominal.io/api/video/v1/videos/<video rid>/segment-summaries-in-bounds",
headers={"Authorization": "Bearer <api key>"},
json={
"bounds": {
"start": {"seconds": 1, "nanos": 1},
"end": {"seconds": 1, "nanos": 1},
},
},
)
response.raise_for_status()
print(response.json())
import asyncio
import aiohttp
async def main() -> None:
async with aiohttp.ClientSession() as session:
async with session.post(
"https://api.gov.nominal.io/api/video/v1/videos/<video rid>/segment-summaries-in-bounds",
headers={"Authorization": "Bearer <api key>"},
json={
"bounds": {
"start": {"seconds": 1, "nanos": 1},
"end": {"seconds": 1, "nanos": 1},
},
},
) as response:
response.raise_for_status()
print(await response.json())
asyncio.run(main())
Response: 200
[
{
"minAbsoluteTimestamp": {
"seconds": 1,
"nanos": 1
},
"maxAbsoluteTimestamp": {
"seconds": 1,
"nanos": 1
},
"minMediaTimestamp": 1,
"maxMediaTimestamp": 1
}
]
Get segment summaries in bounds v2#
POST /video/v2/videos/segment-summaries-in-bounds
Returns the min and max absolute and media timestamps for each segment matching a video series (identified by channel + tags) within the specified bounds.
Body
channelSeriesVideoChannelSeriesrequired
Set
typeto"dataSource".dataSourceVideoDataSourceChannel
Fields of
VideoDataSourceChanneldataSourceRidstring required
channelstring required
tagsmap ofTagNameto string
Set
typeto"asset".assetVideoAssetChannel
Fields of
VideoAssetChannelassetRidstring required
dataScopeNamestring required
channelstring required
tagsmap ofTagNameto string
boundsBoundsrequired
Response
The body is an array of SegmentSummaryV2.
Request
curl -X POST "https://api.gov.nominal.io/api/video/v2/videos/segment-summaries-in-bounds" \
-H "Authorization: Bearer <api key>" \
-H "Content-Type: application/json" \
--data '{
"channelSeries": {
"type": "dataSource",
"dataSource": {
"dataSourceRid": "<data source rid>",
"channel": "<channel>"
}
},
"bounds": {
"start": {
"seconds": 1,
"nanos": 1
},
"end": {
"seconds": 1,
"nanos": 1
}
}
}'
import requests
response = requests.post(
"https://api.gov.nominal.io/api/video/v2/videos/segment-summaries-in-bounds",
headers={"Authorization": "Bearer <api key>"},
json={
"channelSeries": {
"type": "dataSource",
"dataSource": {"dataSourceRid": "<data source rid>", "channel": "<channel>"},
},
"bounds": {
"start": {"seconds": 1, "nanos": 1},
"end": {"seconds": 1, "nanos": 1},
},
},
)
response.raise_for_status()
print(response.json())
import httpx
response = httpx.post(
"https://api.gov.nominal.io/api/video/v2/videos/segment-summaries-in-bounds",
headers={"Authorization": "Bearer <api key>"},
json={
"channelSeries": {
"type": "dataSource",
"dataSource": {"dataSourceRid": "<data source rid>", "channel": "<channel>"},
},
"bounds": {
"start": {"seconds": 1, "nanos": 1},
"end": {"seconds": 1, "nanos": 1},
},
},
)
response.raise_for_status()
print(response.json())
import asyncio
import aiohttp
async def main() -> None:
async with aiohttp.ClientSession() as session:
async with session.post(
"https://api.gov.nominal.io/api/video/v2/videos/segment-summaries-in-bounds",
headers={"Authorization": "Bearer <api key>"},
json={
"channelSeries": {
"type": "dataSource",
"dataSource": {
"dataSourceRid": "<data source rid>",
"channel": "<channel>",
},
},
"bounds": {
"start": {"seconds": 1, "nanos": 1},
"end": {"seconds": 1, "nanos": 1},
},
},
) as response:
response.raise_for_status()
print(await response.json())
asyncio.run(main())
Response: 200
[
{
"datasetFileId": "<dataset file id>",
"minAbsoluteTimestamp": {
"seconds": 1,
"nanos": 1
},
"maxAbsoluteTimestamp": {
"seconds": 1,
"nanos": 1
},
"minMediaTimestamp": 1,
"maxMediaTimestamp": 1
}
]
Get segment metadata v2#
POST /video/v2/videos/segment-metadata
Returns aggregated segment metadata for a video channel series, including total frames, segment count, min/max timestamps, and average frame rate. Optionally filter by time bounds.
Body
channelSeriesVideoChannelSeriesrequired
Set
typeto"dataSource".dataSourceVideoDataSourceChannel
Fields of
VideoDataSourceChanneldataSourceRidstring required
channelstring required
tagsmap ofTagNameto string
Set
typeto"asset".assetVideoAssetChannel
Fields of
VideoAssetChannelassetRidstring required
dataScopeNamestring required
channelstring required
tagsmap ofTagNameto string
boundsBounds
Response
numFramesinteger
numSegmentsinteger
minAbsoluteTimestampTimestamp
Fields of
Timestampsecondsinteger (int64)
nanosinteger (int64)
maxAbsoluteTimestampTimestamp
mediaDurationSecondsnumber
mediaFrameRatenumberThe average media frame rate (FPS) calculated as total frames / duration in seconds.
When there is nothing to return, the response is HTTP 204 with no body.
Request
curl -X POST "https://api.gov.nominal.io/api/video/v2/videos/segment-metadata" \
-H "Authorization: Bearer <api key>" \
-H "Content-Type: application/json" \
--data '{
"channelSeries": {
"type": "dataSource",
"dataSource": {
"dataSourceRid": "<data source rid>",
"channel": "<channel>"
}
}
}'
import requests
response = requests.post(
"https://api.gov.nominal.io/api/video/v2/videos/segment-metadata",
headers={"Authorization": "Bearer <api key>"},
json={
"channelSeries": {
"type": "dataSource",
"dataSource": {"dataSourceRid": "<data source rid>", "channel": "<channel>"},
},
},
)
response.raise_for_status()
print(response.json())
import httpx
response = httpx.post(
"https://api.gov.nominal.io/api/video/v2/videos/segment-metadata",
headers={"Authorization": "Bearer <api key>"},
json={
"channelSeries": {
"type": "dataSource",
"dataSource": {"dataSourceRid": "<data source rid>", "channel": "<channel>"},
},
},
)
response.raise_for_status()
print(response.json())
import asyncio
import aiohttp
async def main() -> None:
async with aiohttp.ClientSession() as session:
async with session.post(
"https://api.gov.nominal.io/api/video/v2/videos/segment-metadata",
headers={"Authorization": "Bearer <api key>"},
json={
"channelSeries": {
"type": "dataSource",
"dataSource": {
"dataSourceRid": "<data source rid>",
"channel": "<channel>",
},
},
},
) as response:
response.raise_for_status()
print(await response.json())
asyncio.run(main())
Response: 200
{
"numFrames": 1,
"numSegments": 1,
"minAbsoluteTimestamp": {
"seconds": 1,
"nanos": 1
},
"maxAbsoluteTimestamp": {
"seconds": 1,
"nanos": 1
},
"mediaDurationSeconds": 1,
"mediaFrameRate": 1
}
Get segment by timestamp v2#
POST /video/v2/videos/get-segment-by-timestamp
Returns metadata for the segment within a video series containing the requested absolute timestamp.
Body
channelSeriesVideoChannelSeriesrequired
Set
typeto"dataSource".dataSourceVideoDataSourceChannel
Fields of
VideoDataSourceChanneldataSourceRidstring required
channelstring required
tagsmap ofTagNameto string
Set
typeto"asset".assetVideoAssetChannel
Fields of
VideoAssetChannelassetRidstring required
dataScopeNamestring required
channelstring required
tagsmap ofTagNameto string
timestampTimestamprequired
Fields of
Timestampsecondsinteger (int64) required
nanosinteger (int64) required
viewRangeStartTimestampThe start of the view range used to dynamically calculate media timestamps. The first segment with an overlap with the time bounds will have its minimum media timestamp set to 0, with every subsequent segment building media time cumulatively from that offset.
Response
ridstring (RID)
datasetFileIdstring (UUID)The dataset file ID that this segment belongs to.
dataHandleHandle
Set
typeto"s3".s3string
frameRatenumberThe average frame rate (FPS) of the segment calculated as total frames / duration in seconds.
durationSecondsnumberThe duration of a segment in media time.
timestampsSegmentTimestampsfor videos with frame-level timestamps, we provide mappings, otherwise we just include a single list of timestamps.
Set
typeto"timestampMappings".timestampMappingsTimestampMappings
Fields of
TimestampMappingsmediaTimestampsarray of number
absoluteTimestampsarray ofTimestamp
Fields of
Timestampsecondsinteger (int64)
nanosinteger (int64)
When there is nothing to return, the response is HTTP 204 with no body.
Request
curl -X POST "https://api.gov.nominal.io/api/video/v2/videos/get-segment-by-timestamp" \
-H "Authorization: Bearer <api key>" \
-H "Content-Type: application/json" \
--data '{
"channelSeries": {
"type": "dataSource",
"dataSource": {
"dataSourceRid": "<data source rid>",
"channel": "<channel>"
}
},
"timestamp": {
"seconds": 1,
"nanos": 1
}
}'
import requests
response = requests.post(
"https://api.gov.nominal.io/api/video/v2/videos/get-segment-by-timestamp",
headers={"Authorization": "Bearer <api key>"},
json={
"channelSeries": {
"type": "dataSource",
"dataSource": {"dataSourceRid": "<data source rid>", "channel": "<channel>"},
},
"timestamp": {"seconds": 1, "nanos": 1},
},
)
response.raise_for_status()
print(response.json())
import httpx
response = httpx.post(
"https://api.gov.nominal.io/api/video/v2/videos/get-segment-by-timestamp",
headers={"Authorization": "Bearer <api key>"},
json={
"channelSeries": {
"type": "dataSource",
"dataSource": {"dataSourceRid": "<data source rid>", "channel": "<channel>"},
},
"timestamp": {"seconds": 1, "nanos": 1},
},
)
response.raise_for_status()
print(response.json())
import asyncio
import aiohttp
async def main() -> None:
async with aiohttp.ClientSession() as session:
async with session.post(
"https://api.gov.nominal.io/api/video/v2/videos/get-segment-by-timestamp",
headers={"Authorization": "Bearer <api key>"},
json={
"channelSeries": {
"type": "dataSource",
"dataSource": {
"dataSourceRid": "<data source rid>",
"channel": "<channel>",
},
},
"timestamp": {"seconds": 1, "nanos": 1},
},
) as response:
response.raise_for_status()
print(await response.json())
asyncio.run(main())
Response: 200
{
"rid": "<segment rid>",
"datasetFileId": "<dataset file id>",
"dataHandle": {
"type": "s3",
"s3": "<s3 path>"
},
"frameRate": 1,
"durationSeconds": 1,
"timestamps": {
"type": "timestampMappings",
"timestampMappings": {
"mediaTimestamps": [
1
],
"absoluteTimestamps": [
{
"seconds": 1,
"nanos": 1
}
]
}
}
}
Get segment at or after timestamp#
POST /video/v1/videos/{videoRid}/get-segment-at-or-after-timestamp
Deprecated: Replaced by getSegmentAtOrAfterTimestampV2, which addresses the video channel series (channel + tags) instead of a Video rid.
Returns metadata for the segment containing the requested absolute timestamp. If no segment contains the timestamp, returns the closest segment starting after the timestamp. Returns empty if no segment is found at or after the timestamp.
Path parameters
videoRidstring (RID) required
Body
timestampTimestamprequired
Fields of
Timestampsecondsinteger (int64) required
nanosinteger (int64) required
Response
ridstring (RID)
videoRidstring (RID)
dataHandleHandle
Set
typeto"s3".s3string
frameRatenumberThe average frame rate (FPS) of the segment calculated as total frames / duration in seconds.
durationSecondsnumberThe duration of a segment in media time.
timestampsSegmentTimestampsfor videos with frame-level timestamps, we provide mappings, otherwise we just include a single list of timestamps.
Set
typeto"timestampMappings".timestampMappingsTimestampMappings
Fields of
TimestampMappingsmediaTimestampsarray of number
absoluteTimestampsarray ofTimestamp
Fields of
Timestampsecondsinteger (int64)
nanosinteger (int64)
When there is nothing to return, the response is HTTP 204 with no body.
Request
curl -X POST "https://api.gov.nominal.io/api/video/v1/videos/<video rid>/get-segment-at-or-after-timestamp" \
-H "Authorization: Bearer <api key>" \
-H "Content-Type: application/json" \
--data '{
"timestamp": {
"seconds": 1,
"nanos": 1
}
}'
import requests
response = requests.post(
"https://api.gov.nominal.io/api/video/v1/videos/<video rid>/get-segment-at-or-after-timestamp",
headers={"Authorization": "Bearer <api key>"},
json={"timestamp": {"seconds": 1, "nanos": 1}},
)
response.raise_for_status()
print(response.json())
import httpx
response = httpx.post(
"https://api.gov.nominal.io/api/video/v1/videos/<video rid>/get-segment-at-or-after-timestamp",
headers={"Authorization": "Bearer <api key>"},
json={"timestamp": {"seconds": 1, "nanos": 1}},
)
response.raise_for_status()
print(response.json())
import asyncio
import aiohttp
async def main() -> None:
async with aiohttp.ClientSession() as session:
async with session.post(
"https://api.gov.nominal.io/api/video/v1/videos/<video rid>/get-segment-at-or-after-timestamp",
headers={"Authorization": "Bearer <api key>"},
json={"timestamp": {"seconds": 1, "nanos": 1}},
) as response:
response.raise_for_status()
print(await response.json())
asyncio.run(main())
Response: 200
{
"rid": "<segment rid>",
"videoRid": "<video rid>",
"dataHandle": {
"type": "s3",
"s3": "<s3 path>"
},
"frameRate": 1,
"durationSeconds": 1,
"timestamps": {
"type": "timestampMappings",
"timestampMappings": {
"mediaTimestamps": [
1
],
"absoluteTimestamps": [
{
"seconds": 1,
"nanos": 1
}
]
}
}
}
Get segment at or after timestamp v2#
POST /video/v2/videos/get-segment-at-or-after-timestamp
Returns metadata for the segment containing the requested absolute timestamp for a video series (identified by channel + tags). If no segment contains the timestamp, returns the closest segment starting after the timestamp. Returns empty if no segment is found at or after the timestamp.
Body
channelSeriesVideoChannelSeriesrequired
Set
typeto"dataSource".dataSourceVideoDataSourceChannel
Fields of
VideoDataSourceChanneldataSourceRidstring required
channelstring required
tagsmap ofTagNameto string
Set
typeto"asset".assetVideoAssetChannel
Fields of
VideoAssetChannelassetRidstring required
dataScopeNamestring required
channelstring required
tagsmap ofTagNameto string
timestampTimestamprequired
Fields of
Timestampsecondsinteger (int64) required
nanosinteger (int64) required
Response
ridstring (RID)
datasetFileIdstring (UUID)The dataset file ID that this segment belongs to.
dataHandleHandle
Set
typeto"s3".s3string
frameRatenumberThe average frame rate (FPS) of the segment calculated as total frames / duration in seconds.
durationSecondsnumberThe duration of a segment in media time.
timestampsSegmentTimestampsfor videos with frame-level timestamps, we provide mappings, otherwise we just include a single list of timestamps.
Set
typeto"timestampMappings".timestampMappingsTimestampMappings
Fields of
TimestampMappingsmediaTimestampsarray of number
absoluteTimestampsarray ofTimestamp
Fields of
Timestampsecondsinteger (int64)
nanosinteger (int64)
When there is nothing to return, the response is HTTP 204 with no body.
Request
curl -X POST "https://api.gov.nominal.io/api/video/v2/videos/get-segment-at-or-after-timestamp" \
-H "Authorization: Bearer <api key>" \
-H "Content-Type: application/json" \
--data '{
"channelSeries": {
"type": "dataSource",
"dataSource": {
"dataSourceRid": "<data source rid>",
"channel": "<channel>"
}
},
"timestamp": {
"seconds": 1,
"nanos": 1
}
}'
import requests
response = requests.post(
"https://api.gov.nominal.io/api/video/v2/videos/get-segment-at-or-after-timestamp",
headers={"Authorization": "Bearer <api key>"},
json={
"channelSeries": {
"type": "dataSource",
"dataSource": {"dataSourceRid": "<data source rid>", "channel": "<channel>"},
},
"timestamp": {"seconds": 1, "nanos": 1},
},
)
response.raise_for_status()
print(response.json())
import httpx
response = httpx.post(
"https://api.gov.nominal.io/api/video/v2/videos/get-segment-at-or-after-timestamp",
headers={"Authorization": "Bearer <api key>"},
json={
"channelSeries": {
"type": "dataSource",
"dataSource": {"dataSourceRid": "<data source rid>", "channel": "<channel>"},
},
"timestamp": {"seconds": 1, "nanos": 1},
},
)
response.raise_for_status()
print(response.json())
import asyncio
import aiohttp
async def main() -> None:
async with aiohttp.ClientSession() as session:
async with session.post(
"https://api.gov.nominal.io/api/video/v2/videos/get-segment-at-or-after-timestamp",
headers={"Authorization": "Bearer <api key>"},
json={
"channelSeries": {
"type": "dataSource",
"dataSource": {
"dataSourceRid": "<data source rid>",
"channel": "<channel>",
},
},
"timestamp": {"seconds": 1, "nanos": 1},
},
) as response:
response.raise_for_status()
print(await response.json())
asyncio.run(main())
Response: 200
{
"rid": "<segment rid>",
"datasetFileId": "<dataset file id>",
"dataHandle": {
"type": "s3",
"s3": "<s3 path>"
},
"frameRate": 1,
"durationSeconds": 1,
"timestamps": {
"type": "timestampMappings",
"timestampMappings": {
"mediaTimestamps": [
1
],
"absoluteTimestamps": [
{
"seconds": 1,
"nanos": 1
}
]
}
}
}
Get file summaries#
POST /video/v1/videos/{videoRid}/get-ranges-with-existing-segment-data
Deprecated: Replaced by listVideoChannelDatasetFiles, which returns the dataset files backing a video channel together with the bounds each file contributes.
Returns the min and max absolute timestamps from non-archived video files associated with a given video that overlap with an optional set of bounds. The files on the edges of the bounds will be truncated to segments that are inside or overlap with the bounds.
Path parameters
videoRidstring (RID) required
Body
boundsBounds
Response
fileSummariesarray ofFileSummary
Request
curl -X POST "https://api.gov.nominal.io/api/video/v1/videos/<video rid>/get-ranges-with-existing-segment-data" \
-H "Authorization: Bearer <api key>" \
-H "Content-Type: application/json" \
--data '{
"bounds": {
"start": {
"seconds": 1,
"nanos": 1
},
"end": {
"seconds": 1,
"nanos": 1
}
}
}'
import requests
response = requests.post(
"https://api.gov.nominal.io/api/video/v1/videos/<video rid>/get-ranges-with-existing-segment-data",
headers={"Authorization": "Bearer <api key>"},
json={
"bounds": {
"start": {"seconds": 1, "nanos": 1},
"end": {"seconds": 1, "nanos": 1},
},
},
)
response.raise_for_status()
print(response.json())
import httpx
response = httpx.post(
"https://api.gov.nominal.io/api/video/v1/videos/<video rid>/get-ranges-with-existing-segment-data",
headers={"Authorization": "Bearer <api key>"},
json={
"bounds": {
"start": {"seconds": 1, "nanos": 1},
"end": {"seconds": 1, "nanos": 1},
},
},
)
response.raise_for_status()
print(response.json())
import asyncio
import aiohttp
async def main() -> None:
async with aiohttp.ClientSession() as session:
async with session.post(
"https://api.gov.nominal.io/api/video/v1/videos/<video rid>/get-ranges-with-existing-segment-data",
headers={"Authorization": "Bearer <api key>"},
json={
"bounds": {
"start": {"seconds": 1, "nanos": 1},
"end": {"seconds": 1, "nanos": 1},
},
},
) as response:
response.raise_for_status()
print(await response.json())
asyncio.run(main())
Response: 200
{
"fileSummaries": [
{
"fileRid": "<video file rid>",
"bounds": {
"start": {
"seconds": 1,
"nanos": 1
},
"end": {
"seconds": 1,
"nanos": 1
}
}
}
]
}
Generate WHIP stream#
POST /video/v1/videos/{videoRid}/streaming/whip
Deprecated: Replaced by generateWhipStreamV2, which addresses a channel-backed live video series instead of a Video rid.
Generates a stream ID scoped to a video and returns a WHIP URL with a MediaMTX JWT and ICE servers. Enforces write permission on the video.
Path parameters
videoRidstring (RID) required
Response
streamIdstring
whipUrlstring
iceServersarray ofIceServer
Fields of
IceServerurlsarray of string
usernamestring
credentialstring
Request
curl -X POST "https://api.gov.nominal.io/api/video/v1/videos/<video rid>/streaming/whip" \
-H "Authorization: Bearer <api key>"
import requests
response = requests.post(
"https://api.gov.nominal.io/api/video/v1/videos/<video rid>/streaming/whip",
headers={"Authorization": "Bearer <api key>"},
)
response.raise_for_status()
print(response.json())
import httpx
response = httpx.post(
"https://api.gov.nominal.io/api/video/v1/videos/<video rid>/streaming/whip",
headers={"Authorization": "Bearer <api key>"},
)
response.raise_for_status()
print(response.json())
import asyncio
import aiohttp
async def main() -> None:
async with aiohttp.ClientSession() as session:
async with session.post(
"https://api.gov.nominal.io/api/video/v1/videos/<video rid>/streaming/whip",
headers={"Authorization": "Bearer <api key>"},
) as response:
response.raise_for_status()
print(await response.json())
asyncio.run(main())
Response: 200
{
"streamId": "<stream id>",
"whipUrl": "<whip url>",
"iceServers": [
{
"urls": [
"<urls>"
],
"username": "<username>",
"credential": "<credential>"
}
]
}
Generate WHIP stream v2#
POST /video/v2/videos/streaming/whip
Generates a stream ID scoped to a channel-backed live video series and returns a WHIP URL with a MediaMTX JWT and ICE servers. Currently only datasource-backed dataset channels are supported.
Body
channelSeriesVideoChannelSeriesrequired
Set
typeto"dataSource".dataSourceVideoDataSourceChannel
Fields of
VideoDataSourceChanneldataSourceRidstring required
channelstring required
tagsmap ofTagNameto string
Set
typeto"asset".assetVideoAssetChannel
Fields of
VideoAssetChannelassetRidstring required
dataScopeNamestring required
channelstring required
tagsmap ofTagNameto string
Response
streamIdstring
whipUrlstring
iceServersarray ofIceServer
Fields of
IceServerurlsarray of string
usernamestring
credentialstring
Request
curl -X POST "https://api.gov.nominal.io/api/video/v2/videos/streaming/whip" \
-H "Authorization: Bearer <api key>" \
-H "Content-Type: application/json" \
--data '{
"channelSeries": {
"type": "dataSource",
"dataSource": {
"dataSourceRid": "<data source rid>",
"channel": "<channel>"
}
}
}'
import requests
response = requests.post(
"https://api.gov.nominal.io/api/video/v2/videos/streaming/whip",
headers={"Authorization": "Bearer <api key>"},
json={
"channelSeries": {
"type": "dataSource",
"dataSource": {"dataSourceRid": "<data source rid>", "channel": "<channel>"},
},
},
)
response.raise_for_status()
print(response.json())
import httpx
response = httpx.post(
"https://api.gov.nominal.io/api/video/v2/videos/streaming/whip",
headers={"Authorization": "Bearer <api key>"},
json={
"channelSeries": {
"type": "dataSource",
"dataSource": {"dataSourceRid": "<data source rid>", "channel": "<channel>"},
},
},
)
response.raise_for_status()
print(response.json())
import asyncio
import aiohttp
async def main() -> None:
async with aiohttp.ClientSession() as session:
async with session.post(
"https://api.gov.nominal.io/api/video/v2/videos/streaming/whip",
headers={"Authorization": "Bearer <api key>"},
json={
"channelSeries": {
"type": "dataSource",
"dataSource": {
"dataSourceRid": "<data source rid>",
"channel": "<channel>",
},
},
},
) as response:
response.raise_for_status()
print(await response.json())
asyncio.run(main())
Response: 200
{
"streamId": "<stream id>",
"whipUrl": "<whip url>",
"iceServers": [
{
"urls": [
"<urls>"
],
"username": "<username>",
"credential": "<credential>"
}
]
}
Generate WHEP stream#
POST /video/v1/videos/{videoRid}/streaming/whep
Deprecated: Replaced by generateWhepStreamV2, which addresses a channel-backed live video series instead of a Video rid.
Returns WHEP URL, ICE servers, and token for playing back the active stream. Returns empty if there is no active stream. Enforces read permission on the video.
Path parameters
videoRidstring (RID) required
Response
whepUrlstring
iceServersarray ofIceServer
Fields of
IceServerurlsarray of string
usernamestring
credentialstring
tokenstring
When there is nothing to return, the response is HTTP 204 with no body.
Request
curl -X POST "https://api.gov.nominal.io/api/video/v1/videos/<video rid>/streaming/whep" \
-H "Authorization: Bearer <api key>"
import requests
response = requests.post(
"https://api.gov.nominal.io/api/video/v1/videos/<video rid>/streaming/whep",
headers={"Authorization": "Bearer <api key>"},
)
response.raise_for_status()
print(response.json())
import httpx
response = httpx.post(
"https://api.gov.nominal.io/api/video/v1/videos/<video rid>/streaming/whep",
headers={"Authorization": "Bearer <api key>"},
)
response.raise_for_status()
print(response.json())
import asyncio
import aiohttp
async def main() -> None:
async with aiohttp.ClientSession() as session:
async with session.post(
"https://api.gov.nominal.io/api/video/v1/videos/<video rid>/streaming/whep",
headers={"Authorization": "Bearer <api key>"},
) as response:
response.raise_for_status()
print(await response.json())
asyncio.run(main())
Response: 200
{
"whepUrl": "<whep url>",
"iceServers": [
{
"urls": [
"<urls>"
],
"username": "<username>",
"credential": "<credential>"
}
],
"token": "<token>"
}
Generate WHEP stream v2#
POST /video/v2/videos/streaming/whep
Returns WHEP URL, ICE servers, and token for playing back the active channel-backed live video stream. Returns empty if there is no active stream. Currently only datasource-backed dataset channels are supported.
Body
channelSeriesVideoChannelSeriesrequired
Set
typeto"dataSource".dataSourceVideoDataSourceChannel
Fields of
VideoDataSourceChanneldataSourceRidstring required
channelstring required
tagsmap ofTagNameto string
Set
typeto"asset".assetVideoAssetChannel
Fields of
VideoAssetChannelassetRidstring required
dataScopeNamestring required
channelstring required
tagsmap ofTagNameto string
Response
whepUrlstring
iceServersarray ofIceServer
Fields of
IceServerurlsarray of string
usernamestring
credentialstring
tokenstring
When there is nothing to return, the response is HTTP 204 with no body.
Request
curl -X POST "https://api.gov.nominal.io/api/video/v2/videos/streaming/whep" \
-H "Authorization: Bearer <api key>" \
-H "Content-Type: application/json" \
--data '{
"channelSeries": {
"type": "dataSource",
"dataSource": {
"dataSourceRid": "<data source rid>",
"channel": "<channel>"
}
}
}'
import requests
response = requests.post(
"https://api.gov.nominal.io/api/video/v2/videos/streaming/whep",
headers={"Authorization": "Bearer <api key>"},
json={
"channelSeries": {
"type": "dataSource",
"dataSource": {"dataSourceRid": "<data source rid>", "channel": "<channel>"},
},
},
)
response.raise_for_status()
print(response.json())
import httpx
response = httpx.post(
"https://api.gov.nominal.io/api/video/v2/videos/streaming/whep",
headers={"Authorization": "Bearer <api key>"},
json={
"channelSeries": {
"type": "dataSource",
"dataSource": {"dataSourceRid": "<data source rid>", "channel": "<channel>"},
},
},
)
response.raise_for_status()
print(response.json())
import asyncio
import aiohttp
async def main() -> None:
async with aiohttp.ClientSession() as session:
async with session.post(
"https://api.gov.nominal.io/api/video/v2/videos/streaming/whep",
headers={"Authorization": "Bearer <api key>"},
json={
"channelSeries": {
"type": "dataSource",
"dataSource": {
"dataSourceRid": "<data source rid>",
"channel": "<channel>",
},
},
},
) as response:
response.raise_for_status()
print(await response.json())
asyncio.run(main())
Response: 200
{
"whepUrl": "<whep url>",
"iceServers": [
{
"urls": [
"<urls>"
],
"username": "<username>",
"credential": "<credential>"
}
],
"token": "<token>"
}
Get stream#
GET /video/v1/videos/{videoRid}/streaming/streams/{streamId}
Returns stream session metadata for a given stream ID scoped to the video. Enforces read permission on the video.
Path parameters
videoRidstring (RID) required
streamIdstring required
Response
streamIdstring
videoRidstring (RID)
streamStatusstring
startstring (date-time)
endstring (date-time)
createdAtstring (date-time)
updatedAtstring (date-time)
When there is nothing to return, the response is HTTP 204 with no body.
Request
curl "https://api.gov.nominal.io/api/video/v1/videos/<video rid>/streaming/streams/<stream id>" \
-H "Authorization: Bearer <api key>"
import requests
response = requests.get(
"https://api.gov.nominal.io/api/video/v1/videos/<video rid>/streaming/streams/<stream id>",
headers={"Authorization": "Bearer <api key>"},
)
response.raise_for_status()
print(response.json())
import httpx
response = httpx.get(
"https://api.gov.nominal.io/api/video/v1/videos/<video rid>/streaming/streams/<stream id>",
headers={"Authorization": "Bearer <api key>"},
)
response.raise_for_status()
print(response.json())
import asyncio
import aiohttp
async def main() -> None:
async with aiohttp.ClientSession() as session:
async with session.get(
"https://api.gov.nominal.io/api/video/v1/videos/<video rid>/streaming/streams/<stream id>",
headers={"Authorization": "Bearer <api key>"},
) as response:
response.raise_for_status()
print(await response.json())
asyncio.run(main())
Response: 200
{
"streamId": "<stream id>",
"videoRid": "<video rid>",
"streamStatus": "<stream status>",
"start": "2026-01-01T00:00:00Z",
"end": "2026-01-01T00:00:00Z",
"createdAt": "2026-01-01T00:00:00Z",
"updatedAt": "2026-01-01T00:00:00Z"
}
Get streams in bounds#
POST /video/v1/videos/{videoRid}/streaming/streams-in-bounds
Deprecated: Replaced by getStreamsInBoundsV2, which addresses a channel-backed live video series instead of a Video rid.
Returns all stream sessions for a video that overlap with the specified time bounds. A stream overlaps if there is any intersection between its [start, end] interval and the provided bounds. Enforces read permission on the video.
Path parameters
videoRidstring (RID) required
Body
boundsBoundsrequired
pageSizeintegerDefaults to 100. Will throw if larger than 1_000.
tokenstring
Response
streamsarray ofVideoStream
Fields of
VideoStreamstreamIdstring
videoRidstring (RID)
streamStatusstring
startstring (date-time)
endstring (date-time)
createdAtstring (date-time)
updatedAtstring (date-time)
nextPageTokenstring
Request
curl -X POST "https://api.gov.nominal.io/api/video/v1/videos/<video rid>/streaming/streams-in-bounds" \
-H "Authorization: Bearer <api key>" \
-H "Content-Type: application/json" \
--data '{
"bounds": {
"start": {
"seconds": 1,
"nanos": 1
},
"end": {
"seconds": 1,
"nanos": 1
}
}
}'
import requests
response = requests.post(
"https://api.gov.nominal.io/api/video/v1/videos/<video rid>/streaming/streams-in-bounds",
headers={"Authorization": "Bearer <api key>"},
json={
"bounds": {
"start": {"seconds": 1, "nanos": 1},
"end": {"seconds": 1, "nanos": 1},
},
},
)
response.raise_for_status()
print(response.json())
import httpx
response = httpx.post(
"https://api.gov.nominal.io/api/video/v1/videos/<video rid>/streaming/streams-in-bounds",
headers={"Authorization": "Bearer <api key>"},
json={
"bounds": {
"start": {"seconds": 1, "nanos": 1},
"end": {"seconds": 1, "nanos": 1},
},
},
)
response.raise_for_status()
print(response.json())
import asyncio
import aiohttp
async def main() -> None:
async with aiohttp.ClientSession() as session:
async with session.post(
"https://api.gov.nominal.io/api/video/v1/videos/<video rid>/streaming/streams-in-bounds",
headers={"Authorization": "Bearer <api key>"},
json={
"bounds": {
"start": {"seconds": 1, "nanos": 1},
"end": {"seconds": 1, "nanos": 1},
},
},
) as response:
response.raise_for_status()
print(await response.json())
asyncio.run(main())
Response: 200
{
"streams": [
{
"streamId": "<stream id>",
"videoRid": "<video rid>",
"streamStatus": "<stream status>",
"start": "2026-01-01T00:00:00Z",
"end": "2026-01-01T00:00:00Z",
"createdAt": "2026-01-01T00:00:00Z",
"updatedAt": "2026-01-01T00:00:00Z"
}
],
"nextPageToken": "<token>"
}
Get streams in bounds v2#
POST /video/v2/videos/streaming/streams-in-bounds
Returns all channel-backed stream sessions for a dataset/channel that overlap with the specified time bounds. A stream overlaps if there is any intersection between its [start, end] interval and the provided bounds. Enforces read metadata permission on the dataset.
Body
channelSeriesVideoChannelSeriesrequired
Set
typeto"dataSource".dataSourceVideoDataSourceChannel
Fields of
VideoDataSourceChanneldataSourceRidstring required
channelstring required
tagsmap ofTagNameto string
Set
typeto"asset".assetVideoAssetChannel
Fields of
VideoAssetChannelassetRidstring required
dataScopeNamestring required
channelstring required
tagsmap ofTagNameto string
boundsBoundsrequired
pageSizeintegerDefaults to 100. Will throw if larger than 1_000.
tokenstring
Response
streamsarray ofVideoStreamV2
Fields of
VideoStreamV2streamIdstring
streamStatusstring
createdAtstring (date-time)
updatedAtstring (date-time)
startstring (date-time)
endstring (date-time)
nextPageTokenstring
Request
curl -X POST "https://api.gov.nominal.io/api/video/v2/videos/streaming/streams-in-bounds" \
-H "Authorization: Bearer <api key>" \
-H "Content-Type: application/json" \
--data '{
"channelSeries": {
"type": "dataSource",
"dataSource": {
"dataSourceRid": "<data source rid>",
"channel": "<channel>"
}
},
"bounds": {
"start": {
"seconds": 1,
"nanos": 1
},
"end": {
"seconds": 1,
"nanos": 1
}
}
}'
import requests
response = requests.post(
"https://api.gov.nominal.io/api/video/v2/videos/streaming/streams-in-bounds",
headers={"Authorization": "Bearer <api key>"},
json={
"channelSeries": {
"type": "dataSource",
"dataSource": {"dataSourceRid": "<data source rid>", "channel": "<channel>"},
},
"bounds": {
"start": {"seconds": 1, "nanos": 1},
"end": {"seconds": 1, "nanos": 1},
},
},
)
response.raise_for_status()
print(response.json())
import httpx
response = httpx.post(
"https://api.gov.nominal.io/api/video/v2/videos/streaming/streams-in-bounds",
headers={"Authorization": "Bearer <api key>"},
json={
"channelSeries": {
"type": "dataSource",
"dataSource": {"dataSourceRid": "<data source rid>", "channel": "<channel>"},
},
"bounds": {
"start": {"seconds": 1, "nanos": 1},
"end": {"seconds": 1, "nanos": 1},
},
},
)
response.raise_for_status()
print(response.json())
import asyncio
import aiohttp
async def main() -> None:
async with aiohttp.ClientSession() as session:
async with session.post(
"https://api.gov.nominal.io/api/video/v2/videos/streaming/streams-in-bounds",
headers={"Authorization": "Bearer <api key>"},
json={
"channelSeries": {
"type": "dataSource",
"dataSource": {
"dataSourceRid": "<data source rid>",
"channel": "<channel>",
},
},
"bounds": {
"start": {"seconds": 1, "nanos": 1},
"end": {"seconds": 1, "nanos": 1},
},
},
) as response:
response.raise_for_status()
print(await response.json())
asyncio.run(main())
Response: 200
{
"streams": [
{
"streamId": "<stream id>",
"streamStatus": "<stream status>",
"createdAt": "2026-01-01T00:00:00Z",
"updatedAt": "2026-01-01T00:00:00Z",
"start": "2026-01-01T00:00:00Z",
"end": "2026-01-01T00:00:00Z"
}
],
"nextPageToken": "<token>"
}
List video channel dataset files#
POST /video/v2/videos/channel-dataset-files
Returns the dataset files backing a video channel (identified by channel + tags), ordered by start timestamp ascending and paginated. Each entry carries the min/max absolute timestamps the file contributes to the channel. Optionally filtered by time bounds. Streamed sessions are not included; use getStreamsInBoundsV2 for those. Enforces read metadata permission on the datasource.
Body
channelSeriesVideoChannelSeriesrequired
Set
typeto"dataSource".dataSourceVideoDataSourceChannel
Fields of
VideoDataSourceChanneldataSourceRidstring required
channelstring required
tagsmap ofTagNameto string
Set
typeto"asset".assetVideoAssetChannel
Fields of
VideoAssetChannelassetRidstring required
dataScopeNamestring required
channelstring required
tagsmap ofTagNameto string
boundsBounds
pageSizeintegerDefaults to 100. Will throw if larger than 1_000.
tokenstring
Response
datasetFilesarray ofVideoChannelDatasetFile
nextPageTokenstring
Request
curl -X POST "https://api.gov.nominal.io/api/video/v2/videos/channel-dataset-files" \
-H "Authorization: Bearer <api key>" \
-H "Content-Type: application/json" \
--data '{
"channelSeries": {
"type": "dataSource",
"dataSource": {
"dataSourceRid": "<data source rid>",
"channel": "<channel>"
}
}
}'
import requests
response = requests.post(
"https://api.gov.nominal.io/api/video/v2/videos/channel-dataset-files",
headers={"Authorization": "Bearer <api key>"},
json={
"channelSeries": {
"type": "dataSource",
"dataSource": {"dataSourceRid": "<data source rid>", "channel": "<channel>"},
},
},
)
response.raise_for_status()
print(response.json())
import httpx
response = httpx.post(
"https://api.gov.nominal.io/api/video/v2/videos/channel-dataset-files",
headers={"Authorization": "Bearer <api key>"},
json={
"channelSeries": {
"type": "dataSource",
"dataSource": {"dataSourceRid": "<data source rid>", "channel": "<channel>"},
},
},
)
response.raise_for_status()
print(response.json())
import asyncio
import aiohttp
async def main() -> None:
async with aiohttp.ClientSession() as session:
async with session.post(
"https://api.gov.nominal.io/api/video/v2/videos/channel-dataset-files",
headers={"Authorization": "Bearer <api key>"},
json={
"channelSeries": {
"type": "dataSource",
"dataSource": {
"dataSourceRid": "<data source rid>",
"channel": "<channel>",
},
},
},
) as response:
response.raise_for_status()
print(await response.json())
asyncio.run(main())
Response: 200
{
"datasetFiles": [
{
"datasetFileId": "<dataset file id>",
"start": {
"seconds": 1,
"nanos": 1
},
"end": {
"seconds": 1,
"nanos": 1
}
}
],
"nextPageToken": "<token>"
}
Batch update video channel dataset files#
POST /video/v2/videos/channel-dataset-files/batch-update
Updates one or more video dataset files in a channel in a single transaction. Each update may set a new absolute start timestamp (segments shifted so the earliest starts at the given timestamp), a scale parameter (frame timestamps rescaled around the file’s start), and/or a new title (file name). If a resulting layout would overlap segments of another file in the channel, no files are updated and VIDEO_SEGMENT_CONFLICT is thrown (all-or-nothing). Returns the updated files with their new bounds and persists those bounds to the corresponding Catalog DatasetFile. Currently only datasource-backed dataset channels are supported. Enforces write data permission on the datasource.
Body
channelSeriesVideoChannelSeries
Set
typeto"dataSource".dataSourceVideoDataSourceChannel
Fields of
VideoDataSourceChanneldataSourceRidstring required
channelstring required
tagsmap ofTagNameto string
Set
typeto"asset".assetVideoAssetChannel
Fields of
VideoAssetChannelassetRidstring required
dataScopeNamestring required
channelstring required
tagsmap ofTagNameto string
datasetRidstring (RID)The dataset owning the files to update. Every requested file must belong to this dataset and be a video file (back a video series); enforces write data permission on the dataset.
updatesarray ofVideoChannelDatasetFileUpdate
Fields of
VideoChannelDatasetFileUpdatedatasetFileIdstring (UUID) required
startTimestampNew absolute start timestamp for the file. The file’s earliest segment is shifted to this timestamp and every other segment in the file is shifted by the same offset.
Fields of
Timestampsecondsinteger (int64) required
nanosinteger (int64) required
titlestringNew name (title) for the dataset file.
scaleParameterScaleParameterRescales the file’s frame timestamps around its start (e.g. a corrected true frame rate, an absolute ending timestamp, or a direct scale factor). The file’s cached segment metadata (scale factor, frame rate) is recomputed.
Set
typeto"trueFrameRate".trueFrameRatenumber
Set
typeto"endingTimestamp".endingTimestampTimestamp
Set
typeto"scaleFactor".scaleFactornumberthe scale factor can be used to calculate whether media duration differs from a video’s | real duration, and if so, the true frame rate of the camera. The video time will thus be scaled | by the ratio of the real duration to media duration, or media frame rate to true frame rate.
Response
datasetFilesarray ofVideoChannelDatasetFile
Request
curl -X POST "https://api.gov.nominal.io/api/video/v2/videos/channel-dataset-files/batch-update" \
-H "Authorization: Bearer <api key>" \
-H "Content-Type: application/json" \
--data '{
"channelSeries": {
"type": "dataSource",
"dataSource": {
"dataSourceRid": "<data source rid>",
"channel": "<channel>"
}
},
"datasetRid": "<dataset rid>",
"updates": [
{
"datasetFileId": "<dataset file id>"
}
]
}'
import requests
response = requests.post(
"https://api.gov.nominal.io/api/video/v2/videos/channel-dataset-files/batch-update",
headers={"Authorization": "Bearer <api key>"},
json={
"channelSeries": {
"type": "dataSource",
"dataSource": {"dataSourceRid": "<data source rid>", "channel": "<channel>"},
},
"datasetRid": "<dataset rid>",
"updates": [{"datasetFileId": "<dataset file id>"}],
},
)
response.raise_for_status()
print(response.json())
import httpx
response = httpx.post(
"https://api.gov.nominal.io/api/video/v2/videos/channel-dataset-files/batch-update",
headers={"Authorization": "Bearer <api key>"},
json={
"channelSeries": {
"type": "dataSource",
"dataSource": {"dataSourceRid": "<data source rid>", "channel": "<channel>"},
},
"datasetRid": "<dataset rid>",
"updates": [{"datasetFileId": "<dataset file id>"}],
},
)
response.raise_for_status()
print(response.json())
import asyncio
import aiohttp
async def main() -> None:
async with aiohttp.ClientSession() as session:
async with session.post(
"https://api.gov.nominal.io/api/video/v2/videos/channel-dataset-files/batch-update",
headers={"Authorization": "Bearer <api key>"},
json={
"channelSeries": {
"type": "dataSource",
"dataSource": {
"dataSourceRid": "<data source rid>",
"channel": "<channel>",
},
},
"datasetRid": "<dataset rid>",
"updates": [{"datasetFileId": "<dataset file id>"}],
},
) as response:
response.raise_for_status()
print(await response.json())
asyncio.run(main())
Response: 200
{
"datasetFiles": [
{
"datasetFileId": "<dataset file id>",
"start": {
"seconds": 1,
"nanos": 1
},
"end": {
"seconds": 1,
"nanos": 1
}
}
]
}
End stream#
POST /video/v1/videos/{videoRid}/streaming/end
Deprecated: Replaced by endStreamV2, which addresses a channel-backed live video series instead of a Video rid.
Marks the active stream session as ended for the video. Throws VIDEO_NOT_FOUND if no active stream exists. Enforces write permission on the video.
Path parameters
videoRidstring (RID) required
Response
streamIdstring
endedAtTimestamp
Fields of
Timestampsecondsinteger (int64)
nanosinteger (int64)
Request
curl -X POST "https://api.gov.nominal.io/api/video/v1/videos/<video rid>/streaming/end" \
-H "Authorization: Bearer <api key>"
import requests
response = requests.post(
"https://api.gov.nominal.io/api/video/v1/videos/<video rid>/streaming/end",
headers={"Authorization": "Bearer <api key>"},
)
response.raise_for_status()
print(response.json())
import httpx
response = httpx.post(
"https://api.gov.nominal.io/api/video/v1/videos/<video rid>/streaming/end",
headers={"Authorization": "Bearer <api key>"},
)
response.raise_for_status()
print(response.json())
import asyncio
import aiohttp
async def main() -> None:
async with aiohttp.ClientSession() as session:
async with session.post(
"https://api.gov.nominal.io/api/video/v1/videos/<video rid>/streaming/end",
headers={"Authorization": "Bearer <api key>"},
) as response:
response.raise_for_status()
print(await response.json())
asyncio.run(main())
Response: 200
{
"streamId": "<stream id>",
"endedAt": {
"seconds": 1,
"nanos": 1
}
}
End stream v2#
POST /video/v2/videos/streaming/end
Marks the active stream session as ended for a channel-backed live video series. Returns empty when no active stream exists, so a publisher-disconnect hook that fires more than once — or races the reaper — is a no-op rather than an error. Currently only datasource-backed dataset channels are supported. Enforces write permission on the data source.
Body
channelSeriesVideoChannelSeriesrequired
Set
typeto"dataSource".dataSourceVideoDataSourceChannel
Fields of
VideoDataSourceChanneldataSourceRidstring required
channelstring required
tagsmap ofTagNameto string
Set
typeto"asset".assetVideoAssetChannel
Fields of
VideoAssetChannelassetRidstring required
dataScopeNamestring required
channelstring required
tagsmap ofTagNameto string
Response
streamIdstring
endedAtTimestamp
Fields of
Timestampsecondsinteger (int64)
nanosinteger (int64)
When there is nothing to return, the response is HTTP 204 with no body.
Request
curl -X POST "https://api.gov.nominal.io/api/video/v2/videos/streaming/end" \
-H "Authorization: Bearer <api key>" \
-H "Content-Type: application/json" \
--data '{
"channelSeries": {
"type": "dataSource",
"dataSource": {
"dataSourceRid": "<data source rid>",
"channel": "<channel>"
}
}
}'
import requests
response = requests.post(
"https://api.gov.nominal.io/api/video/v2/videos/streaming/end",
headers={"Authorization": "Bearer <api key>"},
json={
"channelSeries": {
"type": "dataSource",
"dataSource": {"dataSourceRid": "<data source rid>", "channel": "<channel>"},
},
},
)
response.raise_for_status()
print(response.json())
import httpx
response = httpx.post(
"https://api.gov.nominal.io/api/video/v2/videos/streaming/end",
headers={"Authorization": "Bearer <api key>"},
json={
"channelSeries": {
"type": "dataSource",
"dataSource": {"dataSourceRid": "<data source rid>", "channel": "<channel>"},
},
},
)
response.raise_for_status()
print(response.json())
import asyncio
import aiohttp
async def main() -> None:
async with aiohttp.ClientSession() as session:
async with session.post(
"https://api.gov.nominal.io/api/video/v2/videos/streaming/end",
headers={"Authorization": "Bearer <api key>"},
json={
"channelSeries": {
"type": "dataSource",
"dataSource": {
"dataSourceRid": "<data source rid>",
"channel": "<channel>",
},
},
},
) as response:
response.raise_for_status()
print(await response.json())
asyncio.run(main())
Response: 200
{
"streamId": "<stream id>",
"endedAt": {
"seconds": 1,
"nanos": 1
}
}
Upload segment from media mtx#
POST /video/v1/segment/upload
MediaMTX segment upload endpoint. Receives video segments from MediaMTX hooks. Validates JWT and logs session. Future: create video segments from uploaded files.
Query parameters
streamPathstring requiredMTX_PATH from MediaMTX indicating the stream path
filePathstring requiredFile path of the uploaded segment
durationstring requiredMTX_SEGMENT_DURATION from MediaMTX in seconds
minTimestampSecondsinteger (int64) requiredMinimum timestamp seconds since epoch
minTimestampNanosinteger (int64) requiredNanosecond offset (0-999999999)
Headers
Content-Lengthinteger (int64) requiredSize of the segment in bytes from Content-Length header
Body: application/octet-stream
The body is the raw bytes.
Response
No content (HTTP 204).
Request
curl -X POST "https://api.gov.nominal.io/api/video/v1/segment/upload?streamPath=<stream path>&filePath=<file path>&duration=<duration>&minTimestampSeconds=1&minTimestampNanos=1" \
-H "Authorization: Bearer <api key>" \
-H "Content-Length: 1" \
-H "Content-Type: application/octet-stream" \
--data-binary "@<file>"
from pathlib import Path
import requests
response = requests.post(
"https://api.gov.nominal.io/api/video/v1/segment/upload?streamPath=<stream path>&filePath=<file path>&duration=<duration>&minTimestampSeconds=1&minTimestampNanos=1",
headers={
"Authorization": "Bearer <api key>",
"Content-Length": "1",
"Content-Type": "application/octet-stream",
},
data=Path("<file>").read_bytes(),
)
response.raise_for_status()
from pathlib import Path
import httpx
response = httpx.post(
"https://api.gov.nominal.io/api/video/v1/segment/upload?streamPath=<stream path>&filePath=<file path>&duration=<duration>&minTimestampSeconds=1&minTimestampNanos=1",
headers={
"Authorization": "Bearer <api key>",
"Content-Length": "1",
"Content-Type": "application/octet-stream",
},
content=Path("<file>").read_bytes(),
)
response.raise_for_status()
import asyncio
from pathlib import Path
import aiohttp
async def main() -> None:
async with aiohttp.ClientSession() as session:
async with session.post(
"https://api.gov.nominal.io/api/video/v1/segment/upload?streamPath=<stream path>&filePath=<file path>&duration=<duration>&minTimestampSeconds=1&minTimestampNanos=1",
headers={
"Authorization": "Bearer <api key>",
"Content-Length": "1",
"Content-Type": "application/octet-stream",
},
data=Path("<file>").read_bytes(),
) as response:
response.raise_for_status()
asyncio.run(main())
Response: 204
No content.
Types#
ArchivedStatus#
NOT_ARCHIVED
ARCHIVED
Bounds#
DetailedIngestStatus#
Set type to the name of one of the other fields, and set only that field.
successSuccessIngestStatus
errorErrorIngestStatus
inProgressnumberA number between 0 and 1 representing percentage progress.
Empty#
An empty JSON object, {}.
ErrorIngestStatus#
errorsarray ofIngestError
FileSummary#
fileRidstring (RID) required
boundsBoundsrequired
Handle#
Set type to the name of one of the other fields, and set only that field.
s3string
IceServer#
WebRTC ICE server configuration
urlsarray of string
usernamestring
credentialstring
IngestError#
errorTypestring required
messagestring required
errorInstanceIdstring
IngestStatus#
SUCCEEDED
FAILED
IN_PROGRESS
McapChannelLocator#
Locator for a channel in an mcap file. Channel name is not guaranteed to be unique, so channel ID should be used for mcap files with duplicate channel names.
Set type to the name of one of the other fields, and set only that field.
topicstring
idinteger
McapTimestampManifest#
Timestamps are derived from the mcap file containing the video frames.
mcapChannelLocatorMcapChannelLocatorrequired
NoTimestampManifest#
these values will not be updated after ingest time, to allow for resetting. The updated values are stored implicitly through the segment timestamps.
startingTimestampTimestamprequiredSpecifies the original starting timestamp of the video.
scaleParameterScaleParameterA field that specifies that the frame rate of the video does not match the frame rate of the camera | i.e. a slowed down or sped up video. Can specify either the camera frame rate or the absolute end time.
Property#
namestring required
valuestring required
ScaleParameter#
Set type to the name of one of the other fields, and set only that field.
trueFrameRatenumber
endingTimestampTimestamp
scaleFactornumberthe scale factor can be used to calculate whether media duration differs from a video’s | real duration, and if so, the true frame rate of the camera. The video time will thus be scaled | by the ratio of the real duration to media duration, or media frame rate to true frame rate.
SearchVideosQuery#
Set type to the name of one of the other fields, and set only that field.
searchTextstring
labelstring
propertyProperty
andarray ofSearchVideosQuery
orarray ofSearchVideosQuery
ingestStatusIngestStatus
workspacestring (RID)
SegmentSummary#
Bounding timestamps for the frames within a segment. For non-frame-mapped videos, the min and max media timestamps will be empty.
SegmentSummaryV2#
Bounding timestamps for the frames within a segment. Includes datasetFileId for V2 channel-based API.
SegmentTimestamps#
A video segment will either contain timestamps or timestamp mappings depending on whether it is intended to be frame-mapped. Without a frame-timestamp mapping manifest file, a list of absolute timestamps will be automatically assigned to each segment based on media timestamps.. Otherwise, media timestamps will be extracted and mapped to those in the provided manifest.
Set type to the name of one of the other fields, and set only that field.
timestampMappingsTimestampMappings
SortField#
CREATED_AT
SortOptions#
isDescendingboolean required
fieldSortFieldrequired
SuccessIngestStatus#
An empty JSON object, {}.
Timestamp#
Deprecated for new APIs. Use google.protobuf.Timestamp for absolute instants in proto APIs.
This legacy nanosecond precision timestamp type is represented by an epoch time in seconds and a nanosecond offset. The nanosecond offset is from the start of the epoch second, so must be less than 1 billion.
secondsinteger (int64) required
nanosinteger (int64) required
TimestampMappings#
contains 2 equal-length lists, which contain the video media time and user-provided absolute time for the frame at each index. Enables frame-mapping on the front-end.
mediaTimestampsarray of number
absoluteTimestampsarray ofTimestamp
Video#
ridstring (RID) required
titlestring required
descriptionstring
labelsarray of string
propertiesmap ofPropertyNameto string
createdBystring (RID) required
createdAtstring (date-time) required
isArchivedboolean required
originMetadataVideoOriginMetadatadeprecatedDeprecated: deprecated in favor of per-file VideoFileOriginMetadata. Will be removed after April 15th.
allSegmentsMetadataVideoAllSegmentsMetadata
VideoAllSegmentsMetadata#
ridstring (RID) required
numFramesinteger required
numSegmentsinteger required
scaleFactornumberdeprecated, in favor of per-file VideoFileSegmentsMetadata scaleFactor. Will be removed after April 15th.
minAbsoluteTimestampTimestamprequired
maxAbsoluteTimestampTimestamprequiredthe timestamp corresponding to absolute starting timestamp plus absolute duration of the video.
mediaDurationSecondsnumber required
mediaFrameRatenumber requiredThe average media frame rate (FPS) of the video calculated as total frames / duration in seconds.
minTimestampTimestampdeprecated. Will be removed after April 15th.
maxTimestampTimestampdeprecated. Will be removed after April 15th.
durationSecondsnumberdeprecated. Will be removed after April 15th.
frameRatenumberdeprecated. Will be removed after April 15th.
VideoAssetChannel#
Reference a video channel via an Asset’s data scope
assetRidstring required
dataScopeNamestring required
channelstring required
tagsmap ofTagNameto string
VideoChannelDatasetFile#
A dataset file backing a video channel, with the min and max absolute timestamps of the segments it contributes to the channel.
VideoChannelDatasetFileUpdate#
An update to apply to a single video dataset file backing a channel. Only the provided fields are changed; at least one must be set. When both start and scaleParameter are set, the file is rescaled first (around its current start) and then shifted to the new start.
datasetFileIdstring (UUID) required
startTimestampNew absolute start timestamp for the file. The file’s earliest segment is shifted to this timestamp and every other segment in the file is shifted by the same offset.
titlestringNew name (title) for the dataset file.
scaleParameterScaleParameterRescales the file’s frame timestamps around its start (e.g. a corrected true frame rate, an absolute ending timestamp, or a direct scale factor). The file’s cached segment metadata (scale factor, frame rate) is recomputed.
VideoChannelSeries#
Union type for referencing a video channel. Allows querying video data via datasource/channel, asset data scopes, or run data scopes.
Set type to the name of one of the other fields, and set only that field.
dataSourceVideoDataSourceChannel
assetVideoAssetChannel
VideoDataSourceChannel#
Reference a video channel directly from a datasource/dataset
dataSourceRidstring required
channelstring required
tagsmap ofTagNameto string
VideoFileIngestStatus#
Set type to the name of one of the other fields, and set only that field.
successSuccessIngestStatus
errorIngestError
inProgressEmpty
VideoIngestStatus#
Set type to the name of one of the other fields, and set only that field.
VideoOriginMetadata#
videoSourcesarray ofHandledeprecatedDeprecated: deprecated in favor of per-file VideoFileOriginMetadata. Will be removed after April 15th.
timestampManifestVideoTimestampManifestrequired deprecatedDeprecated: deprecated in favor of per-file VideoFileOriginMetadata. Will be removed after April 15th.
VideoStream#
Metadata for a single video stream session.
streamIdstring required
videoRidstring (RID) required
streamStatusstring required
startstring (date-time)
endstring (date-time)
createdAtstring (date-time) required
updatedAtstring (date-time) required
VideoStreamV2#
Metadata for a single channel-backed video stream session.
streamIdstring required
streamStatusstring required
createdAtstring (date-time) required
updatedAtstring (date-time) required
startstring (date-time)
endstring (date-time)
VideoTimestampManifest#
Set type to the name of one of the other fields, and set only that field.
mcapMcapTimestampManifest
s3pathsarray of string
noManifestNoTimestampManifest
Page design based on Scalar, MIT License.