NAV Navigation
Shell HTTP JavaScript Node.js Ruby Python Java Go PHP

Tagstore API v1.0.0

API for managing tags on content objects.

Authentication

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:

  1. as an HTTP header Authorization: Bearer TOKEN
  2. 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