Tagstore API v1.0.0
Authentication
- HTTP Authentication, scheme: bearer
Access to content fabric objects and resources is governed by an Ethereum-compatible blockchain. Each API resource (for example a library, content type or content object) is governed by a blockchain 'smart-contract'. All content fabric API operations require authentication using the "Bearer" token scheme. This scheme encompasses both "authentication" (identifying the caller) and "authorization" (specification of the operations that the caller has access to). The "Bearer" token is obtained by executing specific 'smart-contract' blockchain transactions for the API resources being accessed.
Private fabric nodes or development environments can also be configured for alternative authentication schemes. Currently this includes "Basic" authentication and, for development environments, no authentication.
The "Bearer" token can be specified as follows:
-
as an HTTP header
Authorization: Bearer TOKEN -
as a query parameter
?authorization=TOKEN
Bearer token general format: PAYLOAD.SIGNATURE
Where PAYLOAD is a base64 encoding of the JSON object:
{
"qspace_id": "SPACE-ID",
"qlib_id": "LIBRARY-ID",
"addr": "BLOCKCHAIN-ADDRESS",
"tx_id" : "BLOCKCHAIN-TRANSACTION-ID"
}
SIGNATURE is a base64 encoding of the Ethereum signature, calculated as specified by the Ethereum protocol: https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign
Creating, modifying and accessing content fabric objects require either "access" or "update" transaction IDs. These operations can only be executed by full blockchain user accounts, which must be funded in order to execute transactions. Once the transaction is executed by the blockchain, its ID will be specified in the token field "tx_id".
Consumer operations don't require funded blockchain accounts, and they are restricted to "viewer" operations, which are only available on content objects that have been specifically published for consumer access. The token is generated by executing a state channel transaction - the state channel allows for low latency response to the user (not requiring waiting for the execution of a blockchain transaction) and mass scalability by posting aggregated transactions to the blockchain in large batches.
Tracks
List all tracks
Code samples
# You can also use wget
curl -X GET /{qid}/tracks \
-H 'Accept: application/json' \
-H 'Authorization: Bearer {access-token}'
GET /{qid}/tracks HTTP/1.1
Accept: application/json
var headers = {
'Accept':'application/json',
'Authorization':'Bearer {access-token}'
};
$.ajax({
url: '/{qid}/tracks',
method: 'get',
headers: headers,
success: function(data) {
console.log(JSON.stringify(data));
}
})
const fetch = require('node-fetch');
const headers = {
'Accept':'application/json',
'Authorization':'Bearer {access-token}'
};
fetch('/{qid}/tracks',
{
method: 'GET',
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
require 'rest-client'
require 'json'
headers = {
'Accept' => 'application/json',
'Authorization' => 'Bearer {access-token}'
}
result = RestClient.get '/{qid}/tracks',
params: {
}, headers: headers
p JSON.parse(result)
import requests
headers = {
'Accept': 'application/json',
'Authorization': 'Bearer {access-token}'
}
r = requests.get('/{qid}/tracks', params={
}, headers = headers)
print r.json()
URL obj = new URL("/{qid}/tracks");
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
con.setRequestMethod("GET");
int responseCode = con.getResponseCode();
BufferedReader in = new BufferedReader(
new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
System.out.println(response.toString());
package main
import (
"bytes"
"net/http"
)
func main() {
headers := map[string][]string{
"Accept": []string{"application/json"},
"Authorization": []string{"Bearer {access-token}"},
}
data := bytes.NewBuffer([]byte{jsonReq})
req, err := http.NewRequest("GET", "/{qid}/tracks", data)
req.Header = headers
client := &http.Client{}
resp, err := client.Do(req)
// ...
}
'application/json',
'Authorization' => 'Bearer {access-token}',
);
$client = new \GuzzleHttp\Client();
// Define array of request body.
$request_body = array();
try {
$response = $client->request('GET','/{qid}/tracks', array(
'headers' => $headers,
'json' => $request_body,
)
);
print_r($response->getBody()->getContents());
}
catch (\GuzzleHttp\Exception\BadResponseException $e) {
// handle exception or api errors.
print_r($e->getMessage());
}
// ...
GET /{qid}/tracks
Returns a list of all tracks for a given content object (QID). Tracks organize tags by their source or purpose.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| qid | path | string | true | Content fabric content id. |
Example responses
200 Response
{
"tracks": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"qid": "iq__3Zi4NjhZfjUEdiMGfHduW5kLr3HY",
"name": "celebrity_detection",
"label": "Celebrity Detection",
"color": "#FF5733",
"description": "AI-generated celebrity tags"
},
{
"id": "550e8400-e29b-41d4-a716-446655440001",
"qid": "iq__3Zi4NjhZfjUEdiMGfHduW5kLr3HY",
"name": "shot_detection",
"label": "Shot Detection",
"color": "#33FF57",
"description": "Automatic shot boundary detection"
}
]
}
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK | List of tracks | Inline |
| 401 | Unauthorized | Provided authentication token cannot access the content object. | None |
Response Schema
Status Code 200
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » tracks | [Track] | false | none | [A Track represents a category or type of tags within a content object. Tracks organize tags by their source or purpose (e.g., "celebrity_detection", "shot_detection"). Each track has a name, display label, color for UI presentation, and optional description. ] |
| »» id | string | true | none | none |
| »» qid | string | true | none | none |
| »» name | string | true | none | Unique identifier for the track within the QID |
| »» label | string | true | none | Human-readable display name for the track |
| »» color | string | true | none | Hex color code for UI representation |
| »» description | string | false | none | Optional description of the track's purpose |
Create a new track
Code samples
# You can also use wget
curl -X POST /{qid}/tracks/{track} \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'Authorization: Bearer {access-token}'
POST /{qid}/tracks/{track} HTTP/1.1
Content-Type: application/json
Accept: application/json
var headers = {
'Content-Type':'application/json',
'Accept':'application/json',
'Authorization':'Bearer {access-token}'
};
$.ajax({
url: '/{qid}/tracks/{track}',
method: 'post',
headers: headers,
success: function(data) {
console.log(JSON.stringify(data));
}
})
const fetch = require('node-fetch');
const inputBody = 'null';
const headers = {
'Content-Type':'application/json',
'Accept':'application/json',
'Authorization':'Bearer {access-token}'
};
fetch('/{qid}/tracks/{track}',
{
method: 'POST',
body: inputBody,
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
require 'rest-client'
require 'json'
headers = {
'Content-Type' => 'application/json',
'Accept' => 'application/json',
'Authorization' => 'Bearer {access-token}'
}
result = RestClient.post '/{qid}/tracks/{track}',
params: {
}, headers: headers
p JSON.parse(result)
import requests
headers = {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': 'Bearer {access-token}'
}
r = requests.post('/{qid}/tracks/{track}', params={
}, headers = headers)
print r.json()
URL obj = new URL("/{qid}/tracks/{track}");
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
con.setRequestMethod("POST");
int responseCode = con.getResponseCode();
BufferedReader in = new BufferedReader(
new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
System.out.println(response.toString());
package main
import (
"bytes"
"net/http"
)
func main() {
headers := map[string][]string{
"Content-Type": []string{"application/json"},
"Accept": []string{"application/json"},
"Authorization": []string{"Bearer {access-token}"},
}
data := bytes.NewBuffer([]byte{jsonReq})
req, err := http.NewRequest("POST", "/{qid}/tracks/{track}", data)
req.Header = headers
client := &http.Client{}
resp, err := client.Do(req)
// ...
}
'application/json',
'Accept' => 'application/json',
'Authorization' => 'Bearer {access-token}',
);
$client = new \GuzzleHttp\Client();
// Define array of request body.
$request_body = array();
try {
$response = $client->request('POST','/{qid}/tracks/{track}', array(
'headers' => $headers,
'json' => $request_body,
)
);
print_r($response->getBody()->getContents());
}
catch (\GuzzleHttp\Exception\BadResponseException $e) {
// handle exception or api errors.
print_r($e->getMessage());
}
// ...
POST /{qid}/tracks/{track}
Creates a new track with the specified name and optional properties. If label and color are not provided, they will be auto-generated based on the track name. The request body is optional - if omitted or empty, all properties will be auto-generated.
Body parameter
Omit the request body entirely to use all defaults
null
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| qid | path | string | true | Content fabric content id. |
| track | path | string | true | Unique name for the track (e.g., "celebrity_detection") |
| body | body | object | false | none |
| » label | body | string | false | Human-readable display name (auto-generated if not provided) |
| » color | body | string | false | Hex color code (auto-generated if not provided) |
| » description | body | string | false | Optional description of the track's purpose |
Example responses
201 Response
{
"message": "Track created successfully",
"track_id": "550e8400-e29b-41d4-a716-446655440000"
}
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 201 | Created | Track created successfully | Inline |
| 400 | Bad Request | Invalid input (e.g., invalid color format) | None |
| 401 | Unauthorized | Provided authentication token cannot access the content object. | None |
| 409 | Conflict | Track with this name already exists | None |
Response Schema
Status Code 201
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » message | string | false | none | none |
| » track_id | string | false | none | none |
Update track properties
Code samples
# You can also use wget
curl -X PATCH /{qid}/tracks/{track} \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'Authorization: Bearer {access-token}'
PATCH /{qid}/tracks/{track} HTTP/1.1
Content-Type: application/json
Accept: application/json
var headers = {
'Content-Type':'application/json',
'Accept':'application/json',
'Authorization':'Bearer {access-token}'
};
$.ajax({
url: '/{qid}/tracks/{track}',
method: 'patch',
headers: headers,
success: function(data) {
console.log(JSON.stringify(data));
}
})
const fetch = require('node-fetch');
const inputBody = '{
"label": "Celebrity Recognition"
}';
const headers = {
'Content-Type':'application/json',
'Accept':'application/json',
'Authorization':'Bearer {access-token}'
};
fetch('/{qid}/tracks/{track}',
{
method: 'PATCH',
body: inputBody,
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
require 'rest-client'
require 'json'
headers = {
'Content-Type' => 'application/json',
'Accept' => 'application/json',
'Authorization' => 'Bearer {access-token}'
}
result = RestClient.patch '/{qid}/tracks/{track}',
params: {
}, headers: headers
p JSON.parse(result)
import requests
headers = {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': 'Bearer {access-token}'
}
r = requests.patch('/{qid}/tracks/{track}', params={
}, headers = headers)
print r.json()
URL obj = new URL("/{qid}/tracks/{track}");
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
con.setRequestMethod("PATCH");
int responseCode = con.getResponseCode();
BufferedReader in = new BufferedReader(
new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
System.out.println(response.toString());
package main
import (
"bytes"
"net/http"
)
func main() {
headers := map[string][]string{
"Content-Type": []string{"application/json"},
"Accept": []string{"application/json"},
"Authorization": []string{"Bearer {access-token}"},
}
data := bytes.NewBuffer([]byte{jsonReq})
req, err := http.NewRequest("PATCH", "/{qid}/tracks/{track}", data)
req.Header = headers
client := &http.Client{}
resp, err := client.Do(req)
// ...
}
'application/json',
'Accept' => 'application/json',
'Authorization' => 'Bearer {access-token}',
);
$client = new \GuzzleHttp\Client();
// Define array of request body.
$request_body = array();
try {
$response = $client->request('PATCH','/{qid}/tracks/{track}', array(
'headers' => $headers,
'json' => $request_body,
)
);
print_r($response->getBody()->getContents());
}
catch (\GuzzleHttp\Exception\BadResponseException $e) {
// handle exception or api errors.
print_r($e->getMessage());
}
// ...
PATCH /{qid}/tracks/{track}
Updates one or more properties of an existing track. Only the provided fields will be updated; others remain unchanged.
Body parameter
{
"label": "Celebrity Recognition"
}
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| qid | path | string | true | Content fabric content id. |
| track | path | string | true | Name of the track to update |
| body | body | object | true | none |
| » label | body | string | false | none |
| » color | body | string | false | none |
| » description | body | string | false | none |
Example responses
200 Response
{
"message": "Track updated successfully"
}
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK | Track updated successfully | Inline |
| 400 | Bad Request | Invalid input | None |
| 401 | Unauthorized | Provided authentication token cannot access the content object. | None |
| 404 | Not Found | Track not found | None |
Response Schema
Status Code 200
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » message | string | false | none | none |
Delete a track
Code samples
# You can also use wget
curl -X DELETE /{qid}/tracks/{track} \
-H 'Authorization: Bearer {access-token}'
DELETE /{qid}/tracks/{track} HTTP/1.1
var headers = {
'Authorization':'Bearer {access-token}'
};
$.ajax({
url: '/{qid}/tracks/{track}',
method: 'delete',
headers: headers,
success: function(data) {
console.log(JSON.stringify(data));
}
})
const fetch = require('node-fetch');
const headers = {
'Authorization':'Bearer {access-token}'
};
fetch('/{qid}/tracks/{track}',
{
method: 'DELETE',
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
require 'rest-client'
require 'json'
headers = {
'Authorization' => 'Bearer {access-token}'
}
result = RestClient.delete '/{qid}/tracks/{track}',
params: {
}, headers: headers
p JSON.parse(result)
import requests
headers = {
'Authorization': 'Bearer {access-token}'
}
r = requests.delete('/{qid}/tracks/{track}', params={
}, headers = headers)
print r.json()
URL obj = new URL("/{qid}/tracks/{track}");
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
con.setRequestMethod("DELETE");
int responseCode = con.getResponseCode();
BufferedReader in = new BufferedReader(
new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
System.out.println(response.toString());
package main
import (
"bytes"
"net/http"
)
func main() {
headers := map[string][]string{
"Authorization": []string{"Bearer {access-token}"},
}
data := bytes.NewBuffer([]byte{jsonReq})
req, err := http.NewRequest("DELETE", "/{qid}/tracks/{track}", data)
req.Header = headers
client := &http.Client{}
resp, err := client.Do(req)
// ...
}
'Bearer {access-token}',
);
$client = new \GuzzleHttp\Client();
// Define array of request body.
$request_body = array();
try {
$response = $client->request('DELETE','/{qid}/tracks/{track}', array(
'headers' => $headers,
'json' => $request_body,
)
);
print_r($response->getBody()->getContents());
}
catch (\GuzzleHttp\Exception\BadResponseException $e) {
// handle exception or api errors.
print_r($e->getMessage());
}
// ...
DELETE /{qid}/tracks/{track}
Permanently deletes a track by its name. All batches and tags associated with this track will also be deleted due to CASCADE constraints.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| qid | path | string | true | Content fabric content id. |
| track | path | string | true | Name of the track to delete |
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 204 | No Content | Track (and all related batches/tags) deleted successfully | None |
| 401 | Unauthorized | Provided authentication token cannot access the content object. | None |
| 404 | Not Found | Track not found | None |
Tags
Get a tag by id
Code samples
# You can also use wget
curl -X GET /{qid}/tags/{id} \
-H 'Accept: application/json' \
-H 'Authorization: Bearer {access-token}'
GET /{qid}/tags/{id} HTTP/1.1
Accept: application/json
var headers = {
'Accept':'application/json',
'Authorization':'Bearer {access-token}'
};
$.ajax({
url: '/{qid}/tags/{id}',
method: 'get',
headers: headers,
success: function(data) {
console.log(JSON.stringify(data));
}
})
const fetch = require('node-fetch');
const headers = {
'Accept':'application/json',
'Authorization':'Bearer {access-token}'
};
fetch('/{qid}/tags/{id}',
{
method: 'GET',
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
require 'rest-client'
require 'json'
headers = {
'Accept' => 'application/json',
'Authorization' => 'Bearer {access-token}'
}
result = RestClient.get '/{qid}/tags/{id}',
params: {
}, headers: headers
p JSON.parse(result)
import requests
headers = {
'Accept': 'application/json',
'Authorization': 'Bearer {access-token}'
}
r = requests.get('/{qid}/tags/{id}', params={
}, headers = headers)
print r.json()
URL obj = new URL("/{qid}/tags/{id}");
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
con.setRequestMethod("GET");
int responseCode = con.getResponseCode();
BufferedReader in = new BufferedReader(
new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
System.out.println(response.toString());
package main
import (
"bytes"
"net/http"
)
func main() {
headers := map[string][]string{
"Accept": []string{"application/json"},
"Authorization": []string{"Bearer {access-token}"},
}
data := bytes.NewBuffer([]byte{jsonReq})
req, err := http.NewRequest("GET", "/{qid}/tags/{id}", data)
req.Header = headers
client := &http.Client{}
resp, err := client.Do(req)
// ...
}
'application/json',
'Authorization' => 'Bearer {access-token}',
);
$client = new \GuzzleHttp\Client();
// Define array of request body.
$request_body = array();
try {
$response = $client->request('GET','/{qid}/tags/{id}', array(
'headers' => $headers,
'json' => $request_body,
)
);
print_r($response->getBody()->getContents());
}
catch (\GuzzleHttp\Exception\BadResponseException $e) {
// handle exception or api errors.
print_r($e->getMessage());
}
// ...
GET /{qid}/tags/{id}
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| qid | path | string | true | Content fabric content id. |
| id | path | string | true | The ID of the tag to retrieve. |
Example responses
200 Response
{
"id": "123",
"batch_id": "234",
"start_time": 5000,
"end_time": 8000,
"tag": "hot dog",
"track": "hot dog detection",
"additional_properties": {
"frame_tags": {
"25": {
"confidence": 0.6,
"box": {
"x1": 0.3,
"y1": 0.6,
"x2": 0.4,
"y2": 0.75
}
},
"30": {
"confidence": 0.65,
"box": {
"x1": 0.35,
"y1": 0.65,
"x2": 0.45,
"y2": 0.8
}
}
}
}
}
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK | Tag found | TagResponse |
| 401 | Unauthorized | Provided authentication token cannot access the content object. | None |
| 404 | Not Found | Tag not found | None |
Update an existing tag.
Code samples
# You can also use wget
curl -X PATCH /{qid}/tags/{id} \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'Authorization: Bearer {access-token}'
PATCH /{qid}/tags/{id} HTTP/1.1
Content-Type: application/json
Accept: application/json
var headers = {
'Content-Type':'application/json',
'Accept':'application/json',
'Authorization':'Bearer {access-token}'
};
$.ajax({
url: '/{qid}/tags/{id}',
method: 'patch',
headers: headers,
success: function(data) {
console.log(JSON.stringify(data));
}
})
const fetch = require('node-fetch');
const inputBody = '{
"start_time": 5000,
"end_time": 10000,
"tag": "Updated tag content",
"additional_info": {
"new_field": "new value"
}
}';
const headers = {
'Content-Type':'application/json',
'Accept':'application/json',
'Authorization':'Bearer {access-token}'
};
fetch('/{qid}/tags/{id}',
{
method: 'PATCH',
body: inputBody,
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
require 'rest-client'
require 'json'
headers = {
'Content-Type' => 'application/json',
'Accept' => 'application/json',
'Authorization' => 'Bearer {access-token}'
}
result = RestClient.patch '/{qid}/tags/{id}',
params: {
}, headers: headers
p JSON.parse(result)
import requests
headers = {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': 'Bearer {access-token}'
}
r = requests.patch('/{qid}/tags/{id}', params={
}, headers = headers)
print r.json()
URL obj = new URL("/{qid}/tags/{id}");
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
con.setRequestMethod("PATCH");
int responseCode = con.getResponseCode();
BufferedReader in = new BufferedReader(
new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
System.out.println(response.toString());
package main
import (
"bytes"
"net/http"
)
func main() {
headers := map[string][]string{
"Content-Type": []string{"application/json"},
"Accept": []string{"application/json"},
"Authorization": []string{"Bearer {access-token}"},
}
data := bytes.NewBuffer([]byte{jsonReq})
req, err := http.NewRequest("PATCH", "/{qid}/tags/{id}", data)
req.Header = headers
client := &http.Client{}
resp, err := client.Do(req)
// ...
}
'application/json',
'Accept' => 'application/json',
'Authorization' => 'Bearer {access-token}',
);
$client = new \GuzzleHttp\Client();
// Define array of request body.
$request_body = array();
try {
$response = $client->request('PATCH','/{qid}/tags/{id}', array(
'headers' => $headers,
'json' => $request_body,
)
);
print_r($response->getBody()->getContents());
}
catch (\GuzzleHttp\Exception\BadResponseException $e) {
// handle exception or api errors.
print_r($e->getMessage());
}
// ...
PATCH /{qid}/tags/{id}
Body parameter
{
"start_time": 5000,
"end_time": 10000,
"tag": "Updated tag content",
"additional_info": {
"new_field": "new value"
}
}
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| qid | path | string | true | Content fabric content id. |
| id | path | string | true | The ID of the tag to update. |
| body | body | object | true | none |
| » start_time | body | integer | true | none |
| » end_time | body | integer | true | none |
| » tag | body | string | true | none |
| » additional_info | body | object | false | none |
Example responses
200 Response
{
"id": "123",
"batch_id": "234",
"start_time": 5000,
"end_time": 8000,
"tag": "hot dog",
"track": "hot dog detection",
"additional_properties": {
"frame_tags": {
"25": {
"confidence": 0.6,
"box": {
"x1": 0.3,
"y1": 0.6,
"x2": 0.4,
"y2": 0.75
}
},
"30": {
"confidence": 0.65,
"box": {
"x1": 0.35,
"y1": 0.65,
"x2": 0.45,
"y2": 0.8
}
}
}
}
}
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK | Tag updated successfully | TagResponse |
| 400 | Bad Request | Invalid input | None |
| 401 | Unauthorized | Provided authentication token cannot access the content object. | None |
| 404 | Not Found | Tag not found | None |
Delete a tag
Code samples
# You can also use wget
curl -X DELETE /{qid}/tags/{id} \
-H 'Authorization: Bearer {access-token}'
DELETE /{qid}/tags/{id} HTTP/1.1
var headers = {
'Authorization':'Bearer {access-token}'
};
$.ajax({
url: '/{qid}/tags/{id}',
method: 'delete',
headers: headers,
success: function(data) {
console.log(JSON.stringify(data));
}
})
const fetch = require('node-fetch');
const headers = {
'Authorization':'Bearer {access-token}'
};
fetch('/{qid}/tags/{id}',
{
method: 'DELETE',
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
require 'rest-client'
require 'json'
headers = {
'Authorization' => 'Bearer {access-token}'
}
result = RestClient.delete '/{qid}/tags/{id}',
params: {
}, headers: headers
p JSON.parse(result)
import requests
headers = {
'Authorization': 'Bearer {access-token}'
}
r = requests.delete('/{qid}/tags/{id}', params={
}, headers = headers)
print r.json()
URL obj = new URL("/{qid}/tags/{id}");
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
con.setRequestMethod("DELETE");
int responseCode = con.getResponseCode();
BufferedReader in = new BufferedReader(
new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
System.out.println(response.toString());
package main
import (
"bytes"
"net/http"
)
func main() {
headers := map[string][]string{
"Authorization": []string{"Bearer {access-token}"},
}
data := bytes.NewBuffer([]byte{jsonReq})
req, err := http.NewRequest("DELETE", "/{qid}/tags/{id}", data)
req.Header = headers
client := &http.Client{}
resp, err := client.Do(req)
// ...
}
'Bearer {access-token}',
);
$client = new \GuzzleHttp\Client();
// Define array of request body.
$request_body = array();
try {
$response = $client->request('DELETE','/{qid}/tags/{id}', array(
'headers' => $headers,
'json' => $request_body,
)
);
print_r($response->getBody()->getContents());
}
catch (\GuzzleHttp\Exception\BadResponseException $e) {
// handle exception or api errors.
print_r($e->getMessage());
}
// ...
DELETE /{qid}/tags/{id}
Permanently deletes a video tag by its ID.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| qid | path | string | true | Content fabric content id. |
| id | path | string | true | The ID of the tag to delete. |
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 204 | No Content | Tag deleted successfully (no content returned) | None |
| 401 | Unauthorized | Provided authentication token cannot access the content object. | None |
| 404 | Not Found | Tag not found | None |
Query tags
Code samples
# You can also use wget
curl -X GET /{qid}/tags \
-H 'Accept: application/json' \
-H 'Authorization: Bearer {access-token}'
GET /{qid}/tags HTTP/1.1
Accept: application/json
var headers = {
'Accept':'application/json',
'Authorization':'Bearer {access-token}'
};
$.ajax({
url: '/{qid}/tags',
method: 'get',
headers: headers,
success: function(data) {
console.log(JSON.stringify(data));
}
})
const fetch = require('node-fetch');
const headers = {
'Accept':'application/json',
'Authorization':'Bearer {access-token}'
};
fetch('/{qid}/tags',
{
method: 'GET',
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
require 'rest-client'
require 'json'
headers = {
'Accept' => 'application/json',
'Authorization' => 'Bearer {access-token}'
}
result = RestClient.get '/{qid}/tags',
params: {
}, headers: headers
p JSON.parse(result)
import requests
headers = {
'Accept': 'application/json',
'Authorization': 'Bearer {access-token}'
}
r = requests.get('/{qid}/tags', params={
}, headers = headers)
print r.json()
URL obj = new URL("/{qid}/tags");
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
con.setRequestMethod("GET");
int responseCode = con.getResponseCode();
BufferedReader in = new BufferedReader(
new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
System.out.println(response.toString());
package main
import (
"bytes"
"net/http"
)
func main() {
headers := map[string][]string{
"Accept": []string{"application/json"},
"Authorization": []string{"Bearer {access-token}"},
}
data := bytes.NewBuffer([]byte{jsonReq})
req, err := http.NewRequest("GET", "/{qid}/tags", data)
req.Header = headers
client := &http.Client{}
resp, err := client.Do(req)
// ...
}
'application/json',
'Authorization' => 'Bearer {access-token}',
);
$client = new \GuzzleHttp\Client();
// Define array of request body.
$request_body = array();
try {
$response = $client->request('GET','/{qid}/tags', array(
'headers' => $headers,
'json' => $request_body,
)
);
print_r($response->getBody()->getContents());
}
catch (\GuzzleHttp\Exception\BadResponseException $e) {
// handle exception or api errors.
print_r($e->getMessage());
}
// ...
GET /{qid}/tags
Returns a list of tags matching the query. If batch_id is not specified, then the result will include tags from the most recent batch per track and per author for each taggable source in the content.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| qid | path | string | true | Content fabric content id. |
| batch_id | query | string | false | Restrict tags to a specific batch. |
| start_time_gte | query | integer | false | Filter tags with start_time >= specified value (in milliseconds) |
| start_time_lte | query | integer | false | Filter tags with start_time <= specified value (in milliseconds) |
| end_time_gte | query | integer | false | Filter tags with end_time >= specified value (in milliseconds) |
| end_time_lte | query | integer | false | Filter tags with end_time <= specified value (in milliseconds) |
| track | query | string | false | none |
| author | query | string | false | none |
| text_contains | query | string | false | Filter tags to those containing this substring |
| start | query | integer | false | Offset for pagination |
| limit | query | integer | false | Number of results to return |
Example responses
200 Response
{
"tags": [
{
"id": "123",
"batch_id": "234",
"start_time": 5000,
"end_time": 8000,
"tag": "hot dog",
"track": "hot dog detection",
"additional_properties": {
"frame_tags": {
"25": {
"confidence": 0.6,
"box": {
"x1": 0.3,
"y1": 0.6,
"x2": 0.4,
"y2": 0.75
}
},
"30": {
"confidence": 0.65,
"box": {
"x1": 0.35,
"y1": 0.65,
"x2": 0.45,
"y2": 0.8
}
}
}
}
}
],
"meta": {
"total": 100,
"count": 1,
"start": 5,
"limit": 1
}
}
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK | List of matching tags | Inline |
| 401 | Unauthorized | Provided authentication token cannot access the content object. | None |
Response Schema
Status Code 200
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » tags | [TagResponse] | false | none | [A Tag represents a labeled segment of a content object. Tags are associated with a specific batch, which groups together tags created by the same author for the same track. Tags can include additional metadata in the additional_properties field, which is a JSON object that can store arbitrary key-value pairs. A common use case for the additional properties is to store bounding box information for video tags which define where in the frame a tag was found, and this can be used for rendering overlays.] |
| »» id | string | true | none | none |
| »» batch_id | string | true | none | none |
| »» start_time | integer | true | none | start time of the tag in milliseconds |
| »» end_time | integer | true | none | end time of the tag in milliseconds |
| »» tag | string | true | none | none |
| »» track | string | true | none | none |
| »» additional_properties | object | false | none | none |
| » meta | Meta | false | none | none |
| »» total | integer | false | none | Total number of results before pagination |
| »» count | integer | false | none | Number of results in the response |
| »» start | integer | false | none | none |
| »» limit | integer | false | none | none |
Add a list of tags
Code samples
# You can also use wget
curl -X POST /{qid}/tags \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'Authorization: Bearer {access-token}'
POST /{qid}/tags HTTP/1.1
Content-Type: application/json
Accept: application/json
var headers = {
'Content-Type':'application/json',
'Accept':'application/json',
'Authorization':'Bearer {access-token}'
};
$.ajax({
url: '/{qid}/tags',
method: 'post',
headers: headers,
success: function(data) {
console.log(JSON.stringify(data));
}
})
const fetch = require('node-fetch');
const inputBody = '{
"batch_id": "12345",
"tags": [
{
"start_time": 1000,
"end_time": 2000,
"tag": "dog"
},
{
"start_time": 3000,
"end_time": 3500,
"tag": "cat",
"additional_info": {
"frame_tags": {
"25": {
"confidence": 0.6,
"box": {
"x1": 0.3,
"y1": 0.6,
"x2": 0.4,
"y2": 0.75
}
},
"30": {
"confidence": 0.65,
"box": {
"x1": 0.35,
"y1": 0.65,
"x2": 0.45,
"y2": 0.8
}
}
}
}
}
]
}';
const headers = {
'Content-Type':'application/json',
'Accept':'application/json',
'Authorization':'Bearer {access-token}'
};
fetch('/{qid}/tags',
{
method: 'POST',
body: inputBody,
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
require 'rest-client'
require 'json'
headers = {
'Content-Type' => 'application/json',
'Accept' => 'application/json',
'Authorization' => 'Bearer {access-token}'
}
result = RestClient.post '/{qid}/tags',
params: {
}, headers: headers
p JSON.parse(result)
import requests
headers = {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': 'Bearer {access-token}'
}
r = requests.post('/{qid}/tags', params={
}, headers = headers)
print r.json()
URL obj = new URL("/{qid}/tags");
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
con.setRequestMethod("POST");
int responseCode = con.getResponseCode();
BufferedReader in = new BufferedReader(
new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
System.out.println(response.toString());
package main
import (
"bytes"
"net/http"
)
func main() {
headers := map[string][]string{
"Content-Type": []string{"application/json"},
"Accept": []string{"application/json"},
"Authorization": []string{"Bearer {access-token}"},
}
data := bytes.NewBuffer([]byte{jsonReq})
req, err := http.NewRequest("POST", "/{qid}/tags", data)
req.Header = headers
client := &http.Client{}
resp, err := client.Do(req)
// ...
}
'application/json',
'Accept' => 'application/json',
'Authorization' => 'Bearer {access-token}',
);
$client = new \GuzzleHttp\Client();
// Define array of request body.
$request_body = array();
try {
$response = $client->request('POST','/{qid}/tags', array(
'headers' => $headers,
'json' => $request_body,
)
);
print_r($response->getBody()->getContents());
}
catch (\GuzzleHttp\Exception\BadResponseException $e) {
// handle exception or api errors.
print_r($e->getMessage());
}
// ...
POST /{qid}/tags
Adds one or more tags. Tags are always associated with a batch. Either you can specify the batch_id explicitly, or provide the triplet (qid, author, track) to automatically add to the most recent batch with that triplet (creating a new batch if none exists).
Body parameter
{
"batch_id": "12345",
"tags": [
{
"start_time": 1000,
"end_time": 2000,
"tag": "dog"
},
{
"start_time": 3000,
"end_time": 3500,
"tag": "cat",
"additional_info": {
"frame_tags": {
"25": {
"confidence": 0.6,
"box": {
"x1": 0.3,
"y1": 0.6,
"x2": 0.4,
"y2": 0.75
}
},
"30": {
"confidence": 0.65,
"box": {
"x1": 0.35,
"y1": 0.65,
"x2": 0.45,
"y2": 0.8
}
}
}
}
}
]
}
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| qid | path | string | true | Content fabric content id. |
| body | body | object | true | none |
| » batch_id | body | string | false | An existing batch ID to add tags to. If not provided, then author and track must be provided. If provided, then author and track will be ignored. |
| » author | body | string | false | Batch author (required if no batch_id). |
| » track | body | string | false | Batch track (required if no batch_id). |
| » tags | body | [object] | false | List of video tags to add. |
| »» start_time | body | integer | false | none |
| »» end_time | body | integer | false | none |
| »» tag | body | string | false | none |
| »» source | body | string | false | none |
| »» additional_info | body | object | false | Additional tag metadata as a JSON object. A common use case is to store bounding box information for video tags here. |
Example responses
200 Response
{
"batch_id": "12345",
"created_tag_ids": [
"67890",
"67891"
]
}
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK | Tags created successfully | Inline |
| 400 | Bad Request | Invalid input | None |
| 401 | Unauthorized | Provided authentication token cannot access the content object. | None |
Response Schema
Status Code 200
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » batch_id | string | false | none | none |
| » created_tag_ids | [string] | false | none | none |
Stream tags (Server-Sent Events)
Code samples
# You can also use wget
curl -X GET /{qid}/tags/stream \
-H 'Accept: text/event-stream' \
-H 'Authorization: Bearer {access-token}'
GET /{qid}/tags/stream HTTP/1.1
Accept: text/event-stream
var headers = {
'Accept':'text/event-stream',
'Authorization':'Bearer {access-token}'
};
$.ajax({
url: '/{qid}/tags/stream',
method: 'get',
headers: headers,
success: function(data) {
console.log(JSON.stringify(data));
}
})
const fetch = require('node-fetch');
const headers = {
'Accept':'text/event-stream',
'Authorization':'Bearer {access-token}'
};
fetch('/{qid}/tags/stream',
{
method: 'GET',
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
require 'rest-client'
require 'json'
headers = {
'Accept' => 'text/event-stream',
'Authorization' => 'Bearer {access-token}'
}
result = RestClient.get '/{qid}/tags/stream',
params: {
}, headers: headers
p JSON.parse(result)
import requests
headers = {
'Accept': 'text/event-stream',
'Authorization': 'Bearer {access-token}'
}
r = requests.get('/{qid}/tags/stream', params={
}, headers = headers)
print r.json()
URL obj = new URL("/{qid}/tags/stream");
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
con.setRequestMethod("GET");
int responseCode = con.getResponseCode();
BufferedReader in = new BufferedReader(
new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
System.out.println(response.toString());
package main
import (
"bytes"
"net/http"
)
func main() {
headers := map[string][]string{
"Accept": []string{"text/event-stream"},
"Authorization": []string{"Bearer {access-token}"},
}
data := bytes.NewBuffer([]byte{jsonReq})
req, err := http.NewRequest("GET", "/{qid}/tags/stream", data)
req.Header = headers
client := &http.Client{}
resp, err := client.Do(req)
// ...
}
'text/event-stream',
'Authorization' => 'Bearer {access-token}',
);
$client = new \GuzzleHttp\Client();
// Define array of request body.
$request_body = array();
try {
$response = $client->request('GET','/{qid}/tags/stream', array(
'headers' => $headers,
'json' => $request_body,
)
);
print_r($response->getBody()->getContents());
}
catch (\GuzzleHttp\Exception\BadResponseException $e) {
// handle exception or api errors.
print_r($e->getMessage());
}
// ...
GET /{qid}/tags/stream
Streams new created tags belonging to the provided content object id.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| qid | path | string | true | Content fabric content id. |
Example responses
Stream of tag events
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK | Stream of tag events | string |
| 401 | Unauthorized | Provided authentication token cannot access the content object. | None |
Bulk upload tags from multiple tracks
Code samples
# You can also use wget
curl -X POST /{qid}/tags/upload?author=string \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'Authorization: Bearer {access-token}'
POST /{qid}/tags/upload?author=string HTTP/1.1
Content-Type: application/json
Accept: application/json
var headers = {
'Content-Type':'application/json',
'Accept':'application/json',
'Authorization':'Bearer {access-token}'
};
$.ajax({
url: '/{qid}/tags/upload',
method: 'post',
data: '?author=string',
headers: headers,
success: function(data) {
console.log(JSON.stringify(data));
}
})
const fetch = require('node-fetch');
const inputBody = '{}';
const headers = {
'Content-Type':'application/json',
'Accept':'application/json',
'Authorization':'Bearer {access-token}'
};
fetch('/{qid}/tags/upload?author=string',
{
method: 'POST',
body: inputBody,
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
require 'rest-client'
require 'json'
headers = {
'Content-Type' => 'application/json',
'Accept' => 'application/json',
'Authorization' => 'Bearer {access-token}'
}
result = RestClient.post '/{qid}/tags/upload',
params: {
'author' => 'string'
}, headers: headers
p JSON.parse(result)
import requests
headers = {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': 'Bearer {access-token}'
}
r = requests.post('/{qid}/tags/upload', params={
'author': 'string'
}, headers = headers)
print r.json()
URL obj = new URL("/{qid}/tags/upload?author=string");
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
con.setRequestMethod("POST");
int responseCode = con.getResponseCode();
BufferedReader in = new BufferedReader(
new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
System.out.println(response.toString());
package main
import (
"bytes"
"net/http"
)
func main() {
headers := map[string][]string{
"Content-Type": []string{"application/json"},
"Accept": []string{"application/json"},
"Authorization": []string{"Bearer {access-token}"},
}
data := bytes.NewBuffer([]byte{jsonReq})
req, err := http.NewRequest("POST", "/{qid}/tags/upload", data)
req.Header = headers
client := &http.Client{}
resp, err := client.Do(req)
// ...
}
'application/json',
'Accept' => 'application/json',
'Authorization' => 'Bearer {access-token}',
);
$client = new \GuzzleHttp\Client();
// Define array of request body.
$request_body = array();
try {
$response = $client->request('POST','/{qid}/tags/upload', array(
'headers' => $headers,
'json' => $request_body,
)
);
print_r($response->getBody()->getContents());
}
catch (\GuzzleHttp\Exception\BadResponseException $e) {
// handle exception or api errors.
print_r($e->getMessage());
}
// ...
POST /{qid}/tags/upload
Upload tags from multiple tracks at once in one json body. Returns a map from track to batch_id.
Body parameter
{}
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| qid | path | string | true | Content fabric content id. |
| author | query | string | true | none |
| body | body | object | true | none |
Example responses
200 Response
{
"celebrity_detection": 101,
"shot_detection": 102
}
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK | File processed successfully | Inline |
| 400 | Bad Request | Invalid input | None |
| 401 | Unauthorized | Provided authentication token cannot access the content object. | None |
Response Schema
Status Code 200
*A map where each key is a track name (string) from the uploaded file and each value is the corresponding batch ID (integer) that was either created or reused for that track. *
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » additionalProperties | string | false | none | none |
Batches
Get a batch by ID
Code samples
# You can also use wget
curl -X GET /{qid}/batches/{id} \
-H 'Accept: application/json' \
-H 'Authorization: Bearer {access-token}'
GET /{qid}/batches/{id} HTTP/1.1
Accept: application/json
var headers = {
'Accept':'application/json',
'Authorization':'Bearer {access-token}'
};
$.ajax({
url: '/{qid}/batches/{id}',
method: 'get',
headers: headers,
success: function(data) {
console.log(JSON.stringify(data));
}
})
const fetch = require('node-fetch');
const headers = {
'Accept':'application/json',
'Authorization':'Bearer {access-token}'
};
fetch('/{qid}/batches/{id}',
{
method: 'GET',
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
require 'rest-client'
require 'json'
headers = {
'Accept' => 'application/json',
'Authorization' => 'Bearer {access-token}'
}
result = RestClient.get '/{qid}/batches/{id}',
params: {
}, headers: headers
p JSON.parse(result)
import requests
headers = {
'Accept': 'application/json',
'Authorization': 'Bearer {access-token}'
}
r = requests.get('/{qid}/batches/{id}', params={
}, headers = headers)
print r.json()
URL obj = new URL("/{qid}/batches/{id}");
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
con.setRequestMethod("GET");
int responseCode = con.getResponseCode();
BufferedReader in = new BufferedReader(
new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
System.out.println(response.toString());
package main
import (
"bytes"
"net/http"
)
func main() {
headers := map[string][]string{
"Accept": []string{"application/json"},
"Authorization": []string{"Bearer {access-token}"},
}
data := bytes.NewBuffer([]byte{jsonReq})
req, err := http.NewRequest("GET", "/{qid}/batches/{id}", data)
req.Header = headers
client := &http.Client{}
resp, err := client.Do(req)
// ...
}
'application/json',
'Authorization' => 'Bearer {access-token}',
);
$client = new \GuzzleHttp\Client();
// Define array of request body.
$request_body = array();
try {
$response = $client->request('GET','/{qid}/batches/{id}', array(
'headers' => $headers,
'json' => $request_body,
)
);
print_r($response->getBody()->getContents());
}
catch (\GuzzleHttp\Exception\BadResponseException $e) {
// handle exception or api errors.
print_r($e->getMessage());
}
// ...
GET /{qid}/batches/{id}
Retrieve a single batch by its unique ID.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| qid | path | string | true | Content fabric content id. |
| id | path | string | true | The ID of the batch to retrieve. |
Example responses
200 Response
{
"id": 0,
"qid": "string",
"author": "string",
"track": "string",
"timestamp": "2025-11-14T07:30:31Z"
}
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK | Batch found | Batch |
| 401 | Unauthorized | Provided authentication token cannot access the content object. | None |
| 404 | Not Found | Batch not found | None |
Delete a batch
Code samples
# You can also use wget
curl -X DELETE /{qid}/batches/{id} \
-H 'Authorization: Bearer {access-token}'
DELETE /{qid}/batches/{id} HTTP/1.1
var headers = {
'Authorization':'Bearer {access-token}'
};
$.ajax({
url: '/{qid}/batches/{id}',
method: 'delete',
headers: headers,
success: function(data) {
console.log(JSON.stringify(data));
}
})
const fetch = require('node-fetch');
const headers = {
'Authorization':'Bearer {access-token}'
};
fetch('/{qid}/batches/{id}',
{
method: 'DELETE',
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
require 'rest-client'
require 'json'
headers = {
'Authorization' => 'Bearer {access-token}'
}
result = RestClient.delete '/{qid}/batches/{id}',
params: {
}, headers: headers
p JSON.parse(result)
import requests
headers = {
'Authorization': 'Bearer {access-token}'
}
r = requests.delete('/{qid}/batches/{id}', params={
}, headers = headers)
print r.json()
URL obj = new URL("/{qid}/batches/{id}");
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
con.setRequestMethod("DELETE");
int responseCode = con.getResponseCode();
BufferedReader in = new BufferedReader(
new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
System.out.println(response.toString());
package main
import (
"bytes"
"net/http"
)
func main() {
headers := map[string][]string{
"Authorization": []string{"Bearer {access-token}"},
}
data := bytes.NewBuffer([]byte{jsonReq})
req, err := http.NewRequest("DELETE", "/{qid}/batches/{id}", data)
req.Header = headers
client := &http.Client{}
resp, err := client.Do(req)
// ...
}
'Bearer {access-token}',
);
$client = new \GuzzleHttp\Client();
// Define array of request body.
$request_body = array();
try {
$response = $client->request('DELETE','/{qid}/batches/{id}', array(
'headers' => $headers,
'json' => $request_body,
)
);
print_r($response->getBody()->getContents());
}
catch (\GuzzleHttp\Exception\BadResponseException $e) {
// handle exception or api errors.
print_r($e->getMessage());
}
// ...
DELETE /{qid}/batches/{id}
Permanently deletes a batch by its ID. All tags associated with the batch will also be deleted.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| qid | path | string | true | Content fabric content id. |
| id | path | string | true | The ID of the batch to delete. |
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 204 | No Content | Batch (and all related tags) deleted successfully | None |
| 401 | Unauthorized | Provided authentication token cannot access the content object. | None |
| 404 | Not Found | Batch not found | None |
Query batches
Code samples
# You can also use wget
curl -X GET /{qid}/batches \
-H 'Accept: application/json' \
-H 'Authorization: Bearer {access-token}'
GET /{qid}/batches HTTP/1.1
Accept: application/json
var headers = {
'Accept':'application/json',
'Authorization':'Bearer {access-token}'
};
$.ajax({
url: '/{qid}/batches',
method: 'get',
headers: headers,
success: function(data) {
console.log(JSON.stringify(data));
}
})
const fetch = require('node-fetch');
const headers = {
'Accept':'application/json',
'Authorization':'Bearer {access-token}'
};
fetch('/{qid}/batches',
{
method: 'GET',
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
require 'rest-client'
require 'json'
headers = {
'Accept' => 'application/json',
'Authorization' => 'Bearer {access-token}'
}
result = RestClient.get '/{qid}/batches',
params: {
}, headers: headers
p JSON.parse(result)
import requests
headers = {
'Accept': 'application/json',
'Authorization': 'Bearer {access-token}'
}
r = requests.get('/{qid}/batches', params={
}, headers = headers)
print r.json()
URL obj = new URL("/{qid}/batches");
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
con.setRequestMethod("GET");
int responseCode = con.getResponseCode();
BufferedReader in = new BufferedReader(
new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
System.out.println(response.toString());
package main
import (
"bytes"
"net/http"
)
func main() {
headers := map[string][]string{
"Accept": []string{"application/json"},
"Authorization": []string{"Bearer {access-token}"},
}
data := bytes.NewBuffer([]byte{jsonReq})
req, err := http.NewRequest("GET", "/{qid}/batches", data)
req.Header = headers
client := &http.Client{}
resp, err := client.Do(req)
// ...
}
'application/json',
'Authorization' => 'Bearer {access-token}',
);
$client = new \GuzzleHttp\Client();
// Define array of request body.
$request_body = array();
try {
$response = $client->request('GET','/{qid}/batches', array(
'headers' => $headers,
'json' => $request_body,
)
);
print_r($response->getBody()->getContents());
}
catch (\GuzzleHttp\Exception\BadResponseException $e) {
// handle exception or api errors.
print_r($e->getMessage());
}
// ...
GET /{qid}/batches
Returns a list of batches matching the query. Supports filtering by QID, author, and track. Results are paginated with start and limit.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| qid | path | string | true | Content fabric content id. |
| author | query | string | false | Filter batches by author. |
| track | query | string | false | Filter batches by track. |
| start | query | integer | false | Offset for pagination. |
| limit | query | integer | false | Number of results to return. |
Example responses
200 Response
{
"batches": [
{
"id": 0,
"qid": "string",
"author": "string",
"track": "string",
"timestamp": "2025-11-14T07:30:31Z"
}
],
"meta": {
"total": 100,
"count": 1,
"start": 5,
"limit": 1
}
}
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK | List of matching batches | Inline |
| 400 | Bad Request | Invalid query parameters | None |
| 401 | Unauthorized | Provided authentication token cannot access the content object. | None |
Response Schema
Status Code 200
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » batches | [Batch] | false | none | [A Batch groups together one or more tags for a given (QID, track, author). Batches are created explicitly or implicitly when tags are uploaded. ] |
| »» id | integer | false | none | none |
| »» qid | string | false | none | none |
| »» author | string | false | none | none |
| »» track | string | false | none | none |
| »» timestamp | string(date-time) | false | none | none |
| » meta | Meta | false | none | none |
| »» total | integer | false | none | Total number of results before pagination |
| »» count | integer | false | none | Number of results in the response |
| »» start | integer | false | none | none |
| »» limit | integer | false | none | none |
Create a batch
Code samples
# You can also use wget
curl -X POST /{qid}/batches \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'Authorization: Bearer {access-token}'
POST /{qid}/batches HTTP/1.1
Content-Type: application/json
Accept: application/json
var headers = {
'Content-Type':'application/json',
'Accept':'application/json',
'Authorization':'Bearer {access-token}'
};
$.ajax({
url: '/{qid}/batches',
method: 'post',
headers: headers,
success: function(data) {
console.log(JSON.stringify(data));
}
})
const fetch = require('node-fetch');
const inputBody = '{
"author": "string",
"track": "string",
"additional_info": {}
}';
const headers = {
'Content-Type':'application/json',
'Accept':'application/json',
'Authorization':'Bearer {access-token}'
};
fetch('/{qid}/batches',
{
method: 'POST',
body: inputBody,
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
require 'rest-client'
require 'json'
headers = {
'Content-Type' => 'application/json',
'Accept' => 'application/json',
'Authorization' => 'Bearer {access-token}'
}
result = RestClient.post '/{qid}/batches',
params: {
}, headers: headers
p JSON.parse(result)
import requests
headers = {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': 'Bearer {access-token}'
}
r = requests.post('/{qid}/batches', params={
}, headers = headers)
print r.json()
URL obj = new URL("/{qid}/batches");
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
con.setRequestMethod("POST");
int responseCode = con.getResponseCode();
BufferedReader in = new BufferedReader(
new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
System.out.println(response.toString());
package main
import (
"bytes"
"net/http"
)
func main() {
headers := map[string][]string{
"Content-Type": []string{"application/json"},
"Accept": []string{"application/json"},
"Authorization": []string{"Bearer {access-token}"},
}
data := bytes.NewBuffer([]byte{jsonReq})
req, err := http.NewRequest("POST", "/{qid}/batches", data)
req.Header = headers
client := &http.Client{}
resp, err := client.Do(req)
// ...
}
'application/json',
'Accept' => 'application/json',
'Authorization' => 'Bearer {access-token}',
);
$client = new \GuzzleHttp\Client();
// Define array of request body.
$request_body = array();
try {
$response = $client->request('POST','/{qid}/batches', array(
'headers' => $headers,
'json' => $request_body,
)
);
print_r($response->getBody()->getContents());
}
catch (\GuzzleHttp\Exception\BadResponseException $e) {
// handle exception or api errors.
print_r($e->getMessage());
}
// ...
POST /{qid}/batches
Creates a new batch and returns the batch_id. If a batch with the same (qid, author, track) triplet already exists, then future read requests which don't specify a batch_id explicitly will resolve to the most recent one. So, this call will have the effect of clearing previous tags for that triplet in the default read path.
Body parameter
{
"author": "string",
"track": "string",
"additional_info": {}
}
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| qid | path | string | true | Content fabric content id. |
| body | body | object | true | none |
| » author | body | string | true | none |
| » track | body | string | true | none |
| » additional_info | body | object | false | Additional batch metadata |
Example responses
200 Response
{
"batch_id": "string"
}
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK | Batch created | Inline |
| 400 | Bad Request | Invalid input | None |
| 401 | Unauthorized | Provided authentication token cannot access the content object. | None |
Response Schema
Status Code 200
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » batch_id | string | false | none | none |
Admin
Write tags to fabric
Code samples
# You can also use wget
curl -X POST /{qid}/write?write_token=string \
-H 'Authorization: Bearer {access-token}'
POST /{qid}/write?write_token=string HTTP/1.1
var headers = {
'Authorization':'Bearer {access-token}'
};
$.ajax({
url: '/{qid}/write',
method: 'post',
data: '?write_token=string',
headers: headers,
success: function(data) {
console.log(JSON.stringify(data));
}
})
const fetch = require('node-fetch');
const headers = {
'Authorization':'Bearer {access-token}'
};
fetch('/{qid}/write?write_token=string',
{
method: 'POST',
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
require 'rest-client'
require 'json'
headers = {
'Authorization' => 'Bearer {access-token}'
}
result = RestClient.post '/{qid}/write',
params: {
'write_token' => 'string'
}, headers: headers
p JSON.parse(result)
import requests
headers = {
'Authorization': 'Bearer {access-token}'
}
r = requests.post('/{qid}/write', params={
'write_token': 'string'
}, headers = headers)
print r.json()
URL obj = new URL("/{qid}/write?write_token=string");
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
con.setRequestMethod("POST");
int responseCode = con.getResponseCode();
BufferedReader in = new BufferedReader(
new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
System.out.println(response.toString());
package main
import (
"bytes"
"net/http"
)
func main() {
headers := map[string][]string{
"Authorization": []string{"Bearer {access-token}"},
}
data := bytes.NewBuffer([]byte{jsonReq})
req, err := http.NewRequest("POST", "/{qid}/write", data)
req.Header = headers
client := &http.Client{}
resp, err := client.Do(req)
// ...
}
'Bearer {access-token}',
);
$client = new \GuzzleHttp\Client();
// Define array of request body.
$request_body = array();
try {
$response = $client->request('POST','/{qid}/write', array(
'headers' => $headers,
'json' => $request_body,
)
);
print_r($response->getBody()->getContents());
}
catch (\GuzzleHttp\Exception\BadResponseException $e) {
// handle exception or api errors.
print_r($e->getMessage());
}
// ...
POST /{qid}/write
Stores all tags from the tagstore under the provided qid to the write_token given in the url parameters.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| qid | path | string | true | Content fabric content id (source for tags). |
| write_token | query | string | true | Write token for the target content object |
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK | Tags successfully written to fabric | None |
| 400 | Bad Request | Invalid input (missing write_token or invalid QID format) | None |
| 401 | Unauthorized | Provided authentication token cannot access the content object. | None |
| 403 | Forbidden | The provided authorization token is missing certain priviliged permissions in order to be able to write files to the given write token. | None |
Schemas
Track
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"qid": "iq__3Zi4NjhZfjUEdiMGfHduW5kLr3HY",
"name": "celebrity_detection",
"label": "Celebrity Detection",
"color": "#FF5733",
"description": "Tags generated by celebrity detection AI model"
}
A Track represents a category or type of tags within a content object. Tracks organize tags by their source or purpose (e.g., "celebrity_detection", "shot_detection"). Each track has a name, display label, color for UI presentation, and optional description.
Properties
| Name | Type | Required | Description |
|---|---|---|---|
| id | string | true | none |
| qid | string | true | none |
| name | string | true | Unique identifier for the track within the QID |
| label | string | true | Human-readable display name for the track |
| color | string | true | Hex color code for UI representation |
| description | string | false | Optional description of the track's purpose |
TagResponse
{
"id": "123",
"batch_id": "234",
"start_time": 5000,
"end_time": 8000,
"tag": "hot dog",
"track": "hot dog detection",
"additional_properties": {
"frame_tags": {
"25": {
"confidence": 0.6,
"box": {
"x1": 0.3,
"y1": 0.6,
"x2": 0.4,
"y2": 0.75
}
},
"30": {
"confidence": 0.65,
"box": {
"x1": 0.35,
"y1": 0.65,
"x2": 0.45,
"y2": 0.8
}
}
}
}
}
A Tag represents a labeled segment of a content object. Tags are associated with a specific batch, which groups together tags created by the same author for the same track. Tags can include additional metadata in the additional_properties field, which is a JSON object that can store arbitrary key-value pairs. A common use case for the additional properties is to store bounding box information for video tags which define where in the frame a tag was found, and this can be used for rendering overlays.
Properties
| Name | Type | Required | Description |
|---|---|---|---|
| id | string | true | none |
| batch_id | string | true | none |
| start_time | integer | true | start time of the tag in milliseconds |
| end_time | integer | true | end time of the tag in milliseconds |
| tag | string | true | none |
| track | string | true | none |
| additional_properties | object | false | none |
TagWrite
{
"start_time": 5000,
"end_time": 8000,
"tag": "hot dog",
"source": "hqp_JBFUvSFH4vpz386EDjVD8BL7vz3RK89sXRXfH9Ajxadya2vE",
"additional_properties": {
"frame_tags": {
"25": {
"confidence": 0.6,
"box": {
"x1": 0.3,
"y1": 0.6,
"x2": 0.4,
"y2": 0.75
}
},
"30": {
"confidence": 0.65,
"box": {
"x1": 0.35,
"y1": 0.65,
"x2": 0.45,
"y2": 0.8
}
}
}
}
}
Properties
| Name | Type | Required | Description |
|---|---|---|---|
| start_time | integer | true | start time of the tag in milliseconds |
| end_time | integer | true | end time of the tag in milliseconds |
| tag | string | true | none |
| source | string | false | The source of the tag with respect to the content. Could be a part or a file asset, or the full-length content. probably will not be touched by the user directly. |
| additional_properties | object | false | none |
Batch
{
"id": 0,
"qid": "string",
"author": "string",
"track": "string",
"timestamp": "2025-11-14T07:30:31Z"
}
A Batch groups together one or more tags for a given (QID, track, author). Batches are created explicitly or implicitly when tags are uploaded.
Properties
| Name | Type | Required | Description |
|---|---|---|---|
| id | integer | false | none |
| qid | string | false | none |
| author | string | false | none |
| track | string | false | none |
| timestamp | string(date-time) | false | none |
Meta
{
"total": 100,
"count": 1,
"start": 5,
"limit": 1
}
Properties
| Name | Type | Required | Description |
|---|---|---|---|
| total | integer | false | Total number of results before pagination |
| count | integer | false | Number of results in the response |
| start | integer | false | none |
| limit | integer | false | none |