ShortDrama Integration API (1.0.0)

Download OpenAPI specification:

The ShortDrama Integration API gives licensed partners programmatic access to our short-drama catalogue: the tag vocabulary, series metadata, the episodes within each series, and signed credentials for playing an episode.

It is a read-only, JSON-over-HTTPS API. Every request is authenticated with a signed HMAC signature.

Getting started

  1. Your account manager issues you an API key, an API secret, and the base URL for your environment. The secret is used only to sign requests - never send it in a request.
  2. Sign and send a request to GET /tags. It takes no parameters, so it is the simplest way to confirm your signing implementation is correct.
  3. Pull the catalogue with GET /contents and GET /items, then request playback credentials per episode with POST /item/{item_id}/playback.

Keep your API secret server-side. It must never be embedded in a mobile app, a browser, or any client you do not control.

Authentication

Send these three headers on every request:

Header Value
x-api-key Your API key.
x-api-timestamp The current time, as an RFC 3339 UTC timestamp, e.g. 2026-09-05T09:41:00Z.
x-api-signature The request signature - see below.

Building the signature

Concatenate four values, separated by newline (\n) characters, and compute an HMAC-SHA256 over the result using your API secret. Send the digest as lowercase hexadecimal.

stringToSign = METHOD + "\n" + PATH + "\n" + QUERY + "\n" + TIMESTAMP
signature    = lowercase_hex( HMAC_SHA256( stringToSign, your_api_secret ) )
Part Rule
METHOD The HTTP method, uppercase: GET or POST.
PATH The path component of the request URI, with no query string and no scheme or host. If your base URL includes a path prefix, that prefix is part of PATH.
QUERY The query string without the leading ?. Empty for requests that have no query parameters, and always empty for POST requests - see the note below.
TIMESTAMP Byte-for-byte the same string you send in x-api-timestamp.

Query string rules

The query string is part of the signature, so it must be built identically on both sides. When a request has query parameters:

  • Format them as name=value pairs joined with &.
  • Percent-encode names and values using application/x-www-form-urlencoded rules - in particular, encode a space as +, not as %20.
  • Keep the pairs in the same order in the signature as in the request URI.
  • Send the exact same query string you signed.

For POST requests the QUERY line is always empty, even if the request URI carries query parameters. Do not put parameters in the query string of a POST.

Test vectors

Check your implementation against these before contacting support. All four use the example secret sk_test_51H9xQmLp7vNfR2kY and the timestamp 2026-09-05T09:41:00Z. This secret is for testing your signing code only and will not authenticate against any environment.

GET /tags

stringToSign: "GET\n/tags\n\n2026-09-05T09:41:00Z"
signature:    23120606736e9388670c2a48d47c88644292a4418c8568441db03bd057225b36

GET /contents?page=1&page_size=50

stringToSign: "GET\n/contents\npage=1&page_size=50\n2026-09-05T09:41:00Z"
signature:    b3d00e63a5583af5e65c43459c5f5388aca3d9746f41e701c8dcd7e8a40f0c58

GET /contents?keywords=lost+heiress&page=1 - note the space encoded as +

stringToSign: "GET\n/contents\nkeywords=lost+heiress&page=1\n2026-09-05T09:41:00Z"
signature:    9770792d56eba77edccb5dd5aaa7958002a109e44dcbe22beeca902c1e1f221a

POST /item/9001/playback - note the empty query line

stringToSign: "POST\n/item/9001/playback\n\n2026-09-05T09:41:00Z"
signature:    cf14407cd322c2a81ab665cdf90c8bb90e6042ab1c30e7bc0d3b064b7552e6e1

Clock skew

A request is rejected if its timestamp is more than 5 minutes from server time, in either direction. Keep your servers synchronised with NTP. Generate a fresh timestamp and signature per request rather than reusing them.

Catalogue scope

GET /contents and GET /items return only titles that are approved and published. Depending on how your key was provisioned, they return either the titles licensed to your account or the full partner catalogue. Your scope is fixed when the key is issued and is not reported in responses - if the catalogue looks smaller or larger than you expect, contact your account manager.

Response envelope

Every response, successful or not, uses the same three-key envelope:

{ "code": 2000, "messages": [], "payload": { } }
Key Meaning
code Application status code. 2000 on success; 4011 for authentication failures; 4041 for a resource that is unavailable.
messages Empty on success. On failure, one or more error objects.
payload The result on success. An empty array ([]) on failure.

Check the HTTP status code first. On a non-2xx response, branch on messages[0].error_type, which is a stable machine-readable key. Do not branch on messages[0].text - that wording may change without notice.

Pagination

GET /contents and GET /items accept page and page_size, and return a pagination object alongside the results.

Always send an explicit page_size. If you omit it, you receive the maximum page size of 1000 records, which is rarely what you want. Values above 1000 are capped, and values below 1 are treated as 1.

Keeping a local copy in sync

Both list endpoints are ordered by last-modified, most recent first, and accept updated_after and updated_before as Unix epoch seconds. To sync incrementally, record the highest timestamp you have seen and pass it as updated_after on your next run.

Poll no more than once every 5 minutes. Request playback credentials at the moment of playback rather than caching them - see the endpoint description for why.

Field conventions

  • Timestamps (created_at, updated_at, publish_at) are Unix epoch seconds, not date strings.
  • Numeric fields may be serialised as JSON strings. Parse identifiers and counts leniently rather than assuming a JSON number.
  • Images: use the *_view_url field, which is a ready-to-use URL. The corresponding image_path is an internal storage key that is not directly resolvable and may change.
  • Language codes are returned as stored on each translation record, and casing is not normalised. Compare them case-insensitively.
  • Optional fields may be absent or null. New fields may be added to any response without a version change, so parse permissively and ignore fields you do not recognise.

Tags

The tag vocabulary used to categorise titles.

List all tags

Returns the full tag vocabulary with every translation, most recently updated first.

The list is small and changes rarely. Cache it and refresh periodically rather than requesting it alongside every catalogue call. Titles reference tags by id in the tags array on each content record.

This endpoint takes no parameters, which makes it the simplest request to verify your signing implementation against.

Authorizations:
(ApiKeyAuthApiSignatureApiTimestamp)

Responses

Response Schema: application/json
code
required
integer

Application status code. 2000 on success.

required
Array of objects (ErrorMessage)

Empty on success.

required
Array of objects

The result. Shape depends on the endpoint.

Response samples

Content type
application/json
{
  • "code": 2000,
  • "messages": [ ],
  • "payload": [
    • {
      }
    ]
}

Catalogue

Series and the episodes within them.

List series

Returns a paginated list of series available to your account, most recently updated first. Each record includes its tag ids, all translations, and any supporting documents.

To retrieve the episodes of a series, call GET /items with content_ids set to the series' content_id.

Authorizations:
(ApiKeyAuthApiSignatureApiTimestamp)
query Parameters
page
integer >= 1
Default: 1
Example: page=1

The page to return, starting at 1.

page_size
integer [ 1 .. 1000 ]
Default: 1000
Example: page_size=50

Records per page, from 1 to 1000. Omitting this returns the maximum of 1000 records, so always send an explicit value. Larger values are capped at 1000.

keywords
string
Example: keywords=lost heiress

Free-text search across translated titles and descriptions, in every language.

Two behaviours to handle when using this parameter: a series that matches in more than one language may appear more than once in results, and total counts those matches rather than distinct series, so treat it as an upper bound. De-duplicate on content_id.

content_ids
string
Example: content_ids=101,102,103

Restrict the result to specific series. Comma-separated content_id values, with no spaces.

updated_after
integer <int64>
Example: updated_after=1756000000

Return only records modified at or after this time, as Unix epoch seconds. Use this to sync incrementally.

updated_before
integer <int64>
Example: updated_before=1757000000

Return only records modified strictly before this time, as Unix epoch seconds.

Responses

Response Schema: application/json
code
required
integer

Application status code. 2000 on success.

required
Array of objects (ErrorMessage)

Empty on success.

required
object

The result. Shape depends on the endpoint.

Response samples

Content type
application/json
{
  • "code": 2000,
  • "messages": [ ],
  • "payload": {
    • "results": [
      ],
    • "pagination": {
      }
    }
}

List episodes

Returns a paginated list of episodes available to your account, most recently updated first, each with its translations.

Episodes belong to a series through content_id. Filter by content_ids to fetch the episodes of one or more specific series.

Authorizations:
(ApiKeyAuthApiSignatureApiTimestamp)
query Parameters
page
integer >= 1
Default: 1
Example: page=1

The page to return, starting at 1.

page_size
integer [ 1 .. 1000 ]
Default: 1000
Example: page_size=50

Records per page, from 1 to 1000. Omitting this returns the maximum of 1000 records, so always send an explicit value. Larger values are capped at 1000.

content_ids
string
Example: content_ids=101,102

Return only episodes belonging to these series. Comma-separated content_id values, with no spaces.

item_ids
string
Example: item_ids=9001,9002

Return only these episodes. Comma-separated item_id values, with no spaces.

updated_after
integer <int64>
Example: updated_after=1756000000

Return only records modified at or after this time, as Unix epoch seconds. Use this to sync incrementally.

updated_before
integer <int64>
Example: updated_before=1757000000

Return only records modified strictly before this time, as Unix epoch seconds.

Responses

Response Schema: application/json
code
required
integer

Application status code. 2000 on success.

required
Array of objects (ErrorMessage)

Empty on success.

required
object

The result. Shape depends on the endpoint.

Response samples

Content type
application/json
{
  • "code": 2000,
  • "messages": [ ],
  • "payload": {
    • "results": [
      ],
    • "pagination": {
      }
    }
}

Playback

Signed credentials for playing an episode.

Get playback credentials for an episode

Returns the credentials needed to play one episode through the Tencent Cloud VOD player SDK.

Pass the returned fileID, appID and psign to the player. Playback is delivered as protected adaptive streaming with Widevine DRM.

The credentials expire 60 seconds after they are issued. Request them at the point of playback, in response to a viewer pressing play. Do not fetch them ahead of time, cache them, or request them in bulk while syncing your catalogue - they will have expired by the time they are used.

The request has no body. Any query parameters on the request URI are ignored, and are not part of the signature.

A 404 is returned if the episode does not exist, is not published, or is not available for playback.

Authorizations:
(ApiKeyAuthApiSignatureApiTimestamp)
path Parameters
item_id
required
integer <int64>
Example: 9001

The item_id of the episode, as returned by GET /items.

Responses

Response Schema: application/json
code
required
integer

Application status code. 2000 on success.

required
Array of objects (ErrorMessage)

Empty on success.

required
object

The result. Shape depends on the endpoint.

Response samples

Content type
application/json
{
  • "code": 2000,
  • "messages": [ ],
  • "payload": {
    • "fileID": "1397757911008782056",
    • "appID": 1500000000,
    • "psign": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.xxx.yyy"
    }
}