{
  "openapi": "3.1.0",
  "info": {
    "title": "Douyin API",
    "version": "1.0.0",
    "description": "A Douyin API for public Douyin (抖音) data: videos and image posts with exact like, comment, share and save counts, account profiles with exact follower counts, an account’s recent videos, a video’s top-level comments, whole collections (合集) in episode order, related videos, hashtag summaries and the hot-search board — as structured JSON, with cursor paging and a free URL parser."
  },
  "servers": [
    {
      "url": "https://api.fetchlayer.dev/douyin"
    }
  ],
  "security": [
    {
      "BearerAuth": []
    }
  ],
  "components": {
    "schemas": {
      "Error": {
        "type": "object",
        "description": "Every error, on every route. Branch on code and retryable rather than on the text; on a 5xx the text is generic. MCP tool errors carry the same fields in structuredContent, and as a JSON text block.",
        "properties": {
          "error": {
            "type": "string",
            "description": "What went wrong, in words. For a 400, what to change."
          },
          "status": {
            "type": "integer",
            "description": "The HTTP status, repeated in the body."
          },
          "code": {
            "type": "string",
            "description": "The kind of error, stable: invalid_input, unauthorized, insufficient_credits, forbidden, not_found, expired, quota_exceeded, cancelled, time_limit, temporarily_unavailable, store_unreachable, upstream_error, internal_error, tool_error. A platform may add its own; more may be added. Treat a code you do not recognise by its retryable flag."
          },
          "retryable": {
            "type": "boolean",
            "description": "Whether asking again can succeed."
          },
          "requestId": {
            "type": "string",
            "description": "This request’s id, also sent as the X-Request-Id header. Quote it when reporting a problem."
          },
          "missing": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "With invalid_input for missing required parameters: the parameters that were missing."
          }
        },
        "required": [
          "error",
          "code",
          "retryable",
          "requestId"
        ]
      }
    },
    "securitySchemes": {
      "BearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "API Key",
        "description": "Send your FetchLayer key as Authorization: Bearer ss-your-key."
      }
    }
  },
  "paths": {
    "/video-detail": {
      "post": {
        "operationId": "video-detail",
        "tags": [
          "Videos"
        ],
        "summary": "Get one video in full",
        "description": "One Douyin video or image post in full by id, link or share text: caption, exact like, comment, share and save counts, author with exact follower count, music, hashtags, media and the collection it belongs to. 1 credit.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "video": {
                    "type": "string",
                    "description": "A video or image post: its id (7665908051974704410), a douyin.com or iesdouyin.com link, a v.douyin.com share link, or pasted share text containing one."
                  },
                  "format": {
                    "type": "string",
                    "description": "json or markdown, lowercase; any other value is a 400. Over MCP, markdown returns the result rendered as text; the REST API accepts it and returns JSON.",
                    "example": "json"
                  },
                  "timeoutMs": {
                    "type": "integer",
                    "description": "Time limit for the whole request, in milliseconds (1000–120000); a value outside that range is a 400. Where possible a partial answer comes back with a note; a request with nothing to return yet fails with a 503 you can retry, marked with the response header X-Timeout-Source: caller."
                  }
                },
                "additionalProperties": false,
                "required": [
                  "video"
                ]
              },
              "examples": {
                "default": {
                  "value": {
                    "video": "https://www.douyin.com/video/7665908051974704410"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "transport": {
                      "type": "string",
                      "description": "The data source: always the platform id, \"douyin\"."
                    },
                    "fetchedAt": {
                      "type": "string",
                      "description": "When the data was read (ISO 8601)."
                    },
                    "notes": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      },
                      "description": "Caveats you can act on, such as older videos existing beyond the list. Empty when there are none."
                    },
                    "video": {
                      "type": "object",
                      "additionalProperties": true,
                      "description": "The video. One that does not exist or is not public is a 404.",
                      "properties": {
                        "id": {
                          "type": "string",
                          "description": "The video id, which every route that takes a video accepts."
                        },
                        "url": {
                          "type": "string",
                          "description": "Link to the video on douyin.com."
                        },
                        "kind": {
                          "type": "string",
                          "description": "\"video\", or \"images\" for an image post."
                        },
                        "description": {
                          "type": "string",
                          "description": "The caption."
                        },
                        "createdAt": {
                          "type": "string",
                          "description": "When it was posted (ISO 8601); createTime is the same moment in unix seconds."
                        },
                        "durationMs": {
                          "type": [
                            "number",
                            "null"
                          ],
                          "description": "Length of a video, in milliseconds."
                        },
                        "hashtags": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "additionalProperties": true
                          },
                          "description": "{ name, id } for each hashtag; the id works with hashtag-detail."
                        },
                        "stats": {
                          "type": "object",
                          "additionalProperties": true,
                          "description": "likes, comments, shares and saves — exact integers. plays is always null: Douyin does not publish play counts."
                        },
                        "author": {
                          "type": "object",
                          "additionalProperties": true,
                          "description": "uid, secUid, uniqueId (抖音号), nickname, avatarUrl, followerCount, verification and profileUrl. followerCount is exact here."
                        },
                        "music": {
                          "type": [
                            "object",
                            "null"
                          ],
                          "additionalProperties": true,
                          "description": "{ id, title, author } of the sound."
                        },
                        "coverUrl": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "Cover image. Douyin’s media links expire after a while."
                        },
                        "playUrl": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "The video stream. Expires after a while."
                        },
                        "imageUrls": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          },
                          "description": "The images of an image post; empty for a video."
                        },
                        "isAd": {
                          "type": "boolean",
                          "description": "Whether Douyin marks it as an ad."
                        },
                        "pinned": {
                          "type": "boolean",
                          "description": "Whether the author pinned it to their profile."
                        },
                        "collection": {
                          "type": [
                            "object",
                            "null"
                          ],
                          "additionalProperties": true,
                          "description": "The collection (合集) it belongs to: { id, name, episode }, or null. The id works with collection-videos."
                        },
                        "shareUrl": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "Douyin’s share link for it."
                        }
                      }
                    }
                  },
                  "additionalProperties": false
                },
                "examples": {
                  "default": {
                    "value": {
                      "transport": "douyin",
                      "fetchedAt": "2026-10-15T15:54:02.000Z",
                      "notes": [
                        "Douyin does not publish play counts, so stats.plays is always null."
                      ],
                      "video": {
                        "id": "7665908051974704410",
                        "url": "https://www.douyin.com/video/7665908051974704410",
                        "kind": "video",
                        "description": "1-8合集《这是我的世界》第一季|异世界篇 …",
                        "createdAt": "2026-07-24T01:58:31.000Z",
                        "createTime": 1784858311,
                        "durationMs": 2574891,
                        "hashtags": [
                          {
                            "name": "这是我的世界",
                            "id": "1587906243760205"
                          }
                        ],
                        "stats": {
                          "likes": 356766,
                          "comments": 6899,
                          "shares": 90087,
                          "saves": 176104,
                          "plays": null
                        },
                        "author": {
                          "uid": "593384953094045",
                          "secUid": "MS4wLjABAAAAYOEVkUXnngwqKUvaFEGdZWxDxUD6cEbk7zYTJGMrqPA",
                          "uniqueId": "Mom2024017",
                          "nickname": "林杉导演AIGC",
                          "followerCount": 397848,
                          "verification": null,
                          "profileUrl": "https://www.douyin.com/user/MS4wLjABAAAAYOEVkUXnngwqKUvaFEGdZWxDxUD6cEbk7zYTJGMrqPA"
                        },
                        "music": {
                          "id": "7665909117738830598",
                          "title": "@林杉导演AIGC创作的原声",
                          "author": "林杉导演AIGC"
                        },
                        "width": 2208,
                        "height": 936,
                        "imageUrls": [],
                        "isAd": false,
                        "pinned": false,
                        "collection": {
                          "id": "7640462496620349491",
                          "name": "原创AI《这是我的世界》第一季|异世界篇",
                          "episode": 11
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "invalid_input: the request needs fixing; error names the field.",
            "headers": {
              "X-Request-Id": {
                "description": "The request id, equal to requestId in the body.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized: the API key is missing or not valid.",
            "headers": {
              "X-Request-Id": {
                "description": "The request id, equal to requestId in the body.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "insufficient_credits: no credits, trial or monthly allowance left.",
            "headers": {
              "X-Request-Id": {
                "description": "The request id, equal to requestId in the body.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "forbidden: this key or account is not allowed this request.",
            "headers": {
              "X-Request-Id": {
                "description": "The request id, equal to requestId in the body.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "quota_exceeded: a request-rate limit was reached.",
            "headers": {
              "X-Request-Id": {
                "description": "The request id, equal to requestId in the body.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "temporarily_unavailable, time_limit or (on a store route) store_unreachable: ask again (with time_limit, allow more time). Retryable.",
            "headers": {
              "X-Request-Id": {
                "description": "The request id, equal to requestId in the body.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "BearerAuth": []
          }
        ]
      }
    },
    "/video-comments": {
      "post": {
        "operationId": "video-comments",
        "tags": [
          "Videos"
        ],
        "summary": "Read the comments on a video",
        "description": "Top-level comments on a video in Douyin’s own ranking, each with its exact likes, reply count and the province it was posted from. Up to 2000 in one request, continuing with a cursor. comment-replies reads the replies. 1 credit per 50 comments.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "video": {
                    "type": "string",
                    "description": "A video or image post: its id (7665908051974704410), a douyin.com or iesdouyin.com link, a v.douyin.com share link, or pasted share text containing one."
                  },
                  "limit": {
                    "type": "integer",
                    "description": "Maximum comments returned, up to 2000, or -1 for as many as available. Comments come 50 to a page and each page is 1 credit; leaving out repeats can occasionally take one more page.",
                    "example": "50"
                  },
                  "cursor": {
                    "type": "string",
                    "description": "The cursor from a previous response, passed back unchanged with the same request, to continue exactly where it stopped. Treat it as opaque: a cursor from another route, video or collection, or one this service did not issue, is a 400 naming cursor."
                  },
                  "format": {
                    "type": "string",
                    "description": "json or markdown, lowercase; any other value is a 400. Over MCP, markdown returns the result rendered as text; the REST API accepts it and returns JSON.",
                    "example": "json"
                  },
                  "timeoutMs": {
                    "type": "integer",
                    "description": "Time limit for the whole request, in milliseconds (1000–120000); a value outside that range is a 400. Where possible a partial answer comes back with a note; a request with nothing to return yet fails with a 503 you can retry, marked with the response header X-Timeout-Source: caller."
                  }
                },
                "additionalProperties": false,
                "required": [
                  "video"
                ]
              },
              "examples": {
                "default": {
                  "value": {
                    "video": "7665908051974704410",
                    "limit": 120
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "transport": {
                      "type": "string",
                      "description": "The data source: always the platform id, \"douyin\"."
                    },
                    "fetchedAt": {
                      "type": "string",
                      "description": "When the data was read (ISO 8601)."
                    },
                    "notes": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      },
                      "description": "Caveats you can act on, such as older videos existing beyond the list. Empty when there are none."
                    },
                    "videoId": {
                      "type": "string",
                      "description": "The video’s id."
                    },
                    "totalComments": {
                      "type": "number",
                      "description": "Douyin’s own comment total for the video."
                    },
                    "comments": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "additionalProperties": true,
                        "properties": {
                          "id": {
                            "type": "string",
                            "description": "The comment’s id."
                          },
                          "text": {
                            "type": "string",
                            "description": "The comment’s text."
                          },
                          "createdAt": {
                            "type": "string",
                            "description": "When it was posted (ISO 8601); createTime is unix seconds."
                          },
                          "likes": {
                            "type": "number",
                            "description": "Likes, exact."
                          },
                          "replyCount": {
                            "type": "number",
                            "description": "How many replies it has. comment-replies reads them."
                          },
                          "ipLocation": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "The province or country Douyin shows for the commenter (IP属地), e.g. 山东."
                          },
                          "author": {
                            "type": "object",
                            "additionalProperties": true,
                            "description": "The same shape as a video’s author: uid, secUid, uniqueId, nickname, avatarUrl, followerCount (null here, never zero), verification and profileUrl."
                          }
                        }
                      },
                      "description": "Top-level comments, in Douyin’s ranking. The ranking can shift slightly between calls, so a continuation may differ a little from one long read."
                    },
                    "commentCount": {
                      "type": "number",
                      "description": "How many comments are in this response."
                    },
                    "skippedRecords": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "additionalProperties": true
                      },
                      "description": "Items Douyin listed that could not be returned whole, each as { id, reason, fieldsPresent }; id may be null. Normally empty."
                    },
                    "pagesFetched": {
                      "type": "number",
                      "description": "Pages read, 50 comments to a page, which is what the request costs: one credit per page."
                    },
                    "hasMore": {
                      "type": "boolean",
                      "description": "Whether more comments remain."
                    },
                    "cursor": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Pass back as cursor, with the same request, to continue exactly where this response stopped. null when there is nothing further."
                    }
                  },
                  "additionalProperties": false
                },
                "examples": {
                  "default": {
                    "value": {
                      "transport": "douyin",
                      "fetchedAt": "2026-10-15T15:54:07.597Z",
                      "notes": [],
                      "videoId": "7665908051974704410",
                      "totalComments": 6899,
                      "comments": [
                        {
                          "id": "7666861957731435300",
                          "text": "奇怪的珠子能强化治疗自身…",
                          "createdAt": "2026-07-26T15:40:08.000Z",
                          "createTime": 1785080408,
                          "likes": 11,
                          "replyCount": 1,
                          "ipLocation": "山东",
                          "author": {
                            "uid": "3654426877240749",
                            "secUid": "MS4wLjABAAAAVjA_8KSzJiJtVxGi4u5W9YLL_fNAi4SxtfdymYk321853zRQdT0_UBrPcYnCyFOj",
                            "nickname": "²⁰²⁶"
                          }
                        }
                      ],
                      "commentCount": 120,
                      "pagesFetched": 3,
                      "hasMore": true,
                      "cursor": "dy1.eyJy…"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "invalid_input: the request needs fixing; error names the field.",
            "headers": {
              "X-Request-Id": {
                "description": "The request id, equal to requestId in the body.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized: the API key is missing or not valid.",
            "headers": {
              "X-Request-Id": {
                "description": "The request id, equal to requestId in the body.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "insufficient_credits: no credits, trial or monthly allowance left.",
            "headers": {
              "X-Request-Id": {
                "description": "The request id, equal to requestId in the body.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "forbidden: this key or account is not allowed this request.",
            "headers": {
              "X-Request-Id": {
                "description": "The request id, equal to requestId in the body.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "quota_exceeded: a request-rate limit was reached.",
            "headers": {
              "X-Request-Id": {
                "description": "The request id, equal to requestId in the body.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "temporarily_unavailable, time_limit or (on a store route) store_unreachable: ask again (with time_limit, allow more time). Retryable.",
            "headers": {
              "X-Request-Id": {
                "description": "The request id, equal to requestId in the body.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "BearerAuth": []
          }
        ]
      }
    },
    "/comment-replies": {
      "post": {
        "operationId": "comment-replies",
        "tags": [
          "Videos"
        ],
        "summary": "Read the replies to a comment",
        "description": "The replies under one comment, as a flat list in Douyin’s order, each with its exact likes, the province it was posted from and the reply it answers (replyTo). Take commentId from video-comments, and pass the same video. Up to 500 in one request, continuing with a cursor. 1 credit per 29 replies.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "video": {
                    "type": "string",
                    "description": "A video or image post: its id (7665908051974704410), a douyin.com or iesdouyin.com link, a v.douyin.com share link, or pasted share text containing one."
                  },
                  "commentId": {
                    "type": "string",
                    "description": "The comment’s id, 15 to 19 digits, as video-comments returns it in comments[].id. It cannot be derived from the video alone."
                  },
                  "limit": {
                    "type": "integer",
                    "description": "Maximum replies returned, up to 500, or -1 for as many as available. Replies come 29 to a page and each page is 1 credit; use a larger limit and a cursor rather than a larger page.",
                    "example": "50"
                  },
                  "cursor": {
                    "type": "string",
                    "description": "The cursor from a previous response, passed back unchanged with the same request, to continue exactly where it stopped. Treat it as opaque: a cursor from another route, video or collection, or one this service did not issue, is a 400 naming cursor."
                  },
                  "format": {
                    "type": "string",
                    "description": "json or markdown, lowercase; any other value is a 400. Over MCP, markdown returns the result rendered as text; the REST API accepts it and returns JSON.",
                    "example": "json"
                  },
                  "timeoutMs": {
                    "type": "integer",
                    "description": "Time limit for the whole request, in milliseconds (1000–120000); a value outside that range is a 400. Where possible a partial answer comes back with a note; a request with nothing to return yet fails with a 503 you can retry, marked with the response header X-Timeout-Source: caller."
                  }
                },
                "additionalProperties": false,
                "required": [
                  "video",
                  "commentId"
                ]
              },
              "examples": {
                "default": {
                  "value": {
                    "video": "7665908051974704410",
                    "commentId": "7666958298617054001",
                    "limit": 9
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "transport": {
                      "type": "string",
                      "description": "The data source: always the platform id, \"douyin\"."
                    },
                    "fetchedAt": {
                      "type": "string",
                      "description": "When the data was read (ISO 8601)."
                    },
                    "notes": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      },
                      "description": "Caveats you can act on, such as older videos existing beyond the list. Empty when there are none."
                    },
                    "videoId": {
                      "type": "string",
                      "description": "The video’s id."
                    },
                    "commentId": {
                      "type": "string",
                      "description": "The comment the replies are under."
                    },
                    "totalReplies": {
                      "type": "number",
                      "description": "Douyin’s own reply count for the comment. It can be one higher than the list served, and notes says so rather than leaving it looking like a dropped record."
                    },
                    "replies": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "additionalProperties": true,
                        "properties": {
                          "id": {
                            "type": "string",
                            "description": "The reply’s id."
                          },
                          "text": {
                            "type": "string",
                            "description": "The reply’s text."
                          },
                          "createdAt": {
                            "type": "string",
                            "description": "When it was posted (ISO 8601); createTime is unix seconds."
                          },
                          "likes": {
                            "type": "number",
                            "description": "Likes, exact."
                          },
                          "replyCount": {
                            "type": "object",
                            "additionalProperties": true,
                            "description": "Always null: a reply has no replies of its own."
                          },
                          "ipLocation": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "The province or country Douyin shows for the replier (IP属地)."
                          },
                          "author": {
                            "type": "object",
                            "additionalProperties": true,
                            "description": "The same shape as a video’s author: uid, secUid, uniqueId, nickname, avatarUrl, followerCount (null here, never zero), verification and profileUrl."
                          },
                          "replyTo": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "The id of the reply this one answers, or null when it answers the comment itself. The only thread signal: replies are a flat list."
                          }
                        }
                      },
                      "description": "The replies, as a flat list. A comment with no replies returns an empty list with a note; a comment id that names no comment, or one on another video, is a 404."
                    },
                    "replyCount": {
                      "type": "number",
                      "description": "How many replies are in this response."
                    },
                    "skippedRecords": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "additionalProperties": true
                      },
                      "description": "Items Douyin listed that could not be returned whole, each as { id, reason, fieldsPresent }; id may be null. Normally empty."
                    },
                    "pagesFetched": {
                      "type": "number",
                      "description": "Pages read, 29 replies to a page, which is what the request costs: one credit per page."
                    },
                    "hasMore": {
                      "type": "boolean",
                      "description": "Whether more replies remain."
                    },
                    "cursor": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Pass back as cursor, with the same request, to continue exactly where this response stopped. null when there is nothing further."
                    }
                  },
                  "additionalProperties": false
                },
                "examples": {
                  "default": {
                    "value": {
                      "transport": "douyin",
                      "fetchedAt": "2026-10-16T09:00:00.000Z",
                      "notes": [
                        "Replies are a flat list; replyTo names the reply each one answers, and is null when it answers the comment itself."
                      ],
                      "videoId": "7665908051974704410",
                      "commentId": "7666958298617054001",
                      "totalReplies": 9,
                      "replies": [
                        {
                          "id": "7667152618309780261",
                          "text": "我说的这些都是常识…",
                          "createdAt": "2026-07-27T08:00:00.000Z",
                          "likes": 14,
                          "replyCount": null,
                          "ipLocation": "浙江",
                          "author": {
                            "uid": "3654426877240749",
                            "secUid": "MS4wLjABAAAA…",
                            "nickname": "喜欢丑的",
                            "followerCount": null
                          },
                          "replyTo": "7666988496317629190"
                        }
                      ],
                      "replyCount": 9,
                      "skippedRecords": [],
                      "pagesFetched": 1,
                      "hasMore": false,
                      "cursor": null
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "invalid_input: the request needs fixing; error names the field.",
            "headers": {
              "X-Request-Id": {
                "description": "The request id, equal to requestId in the body.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized: the API key is missing or not valid.",
            "headers": {
              "X-Request-Id": {
                "description": "The request id, equal to requestId in the body.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "insufficient_credits: no credits, trial or monthly allowance left.",
            "headers": {
              "X-Request-Id": {
                "description": "The request id, equal to requestId in the body.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "forbidden: this key or account is not allowed this request.",
            "headers": {
              "X-Request-Id": {
                "description": "The request id, equal to requestId in the body.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "quota_exceeded: a request-rate limit was reached.",
            "headers": {
              "X-Request-Id": {
                "description": "The request id, equal to requestId in the body.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "temporarily_unavailable, time_limit or (on a store route) store_unreachable: ask again (with time_limit, allow more time). Retryable.",
            "headers": {
              "X-Request-Id": {
                "description": "The request id, equal to requestId in the body.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "BearerAuth": []
          }
        ]
      }
    },
    "/related-videos": {
      "post": {
        "operationId": "related-videos",
        "tags": [
          "Videos"
        ],
        "summary": "Videos recommended alongside a video",
        "description": "The videos Douyin recommends alongside a video, about 10, in the same shape as video-detail. 1 credit.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "video": {
                    "type": "string",
                    "description": "A video or image post: its id (7665908051974704410), a douyin.com or iesdouyin.com link, a v.douyin.com share link, or pasted share text containing one."
                  },
                  "limit": {
                    "type": "integer",
                    "description": "Maximum videos, up to 20, or -1. Left out, all Douyin suggests (about 10)."
                  },
                  "format": {
                    "type": "string",
                    "description": "json or markdown, lowercase; any other value is a 400. Over MCP, markdown returns the result rendered as text; the REST API accepts it and returns JSON.",
                    "example": "json"
                  },
                  "timeoutMs": {
                    "type": "integer",
                    "description": "Time limit for the whole request, in milliseconds (1000–120000); a value outside that range is a 400. Where possible a partial answer comes back with a note; a request with nothing to return yet fails with a 503 you can retry, marked with the response header X-Timeout-Source: caller."
                  }
                },
                "additionalProperties": false,
                "required": [
                  "video"
                ]
              },
              "examples": {
                "default": {
                  "value": {
                    "video": "7665908051974704410",
                    "limit": 10
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "transport": {
                      "type": "string",
                      "description": "The data source: always the platform id, \"douyin\"."
                    },
                    "fetchedAt": {
                      "type": "string",
                      "description": "When the data was read (ISO 8601)."
                    },
                    "notes": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      },
                      "description": "Caveats you can act on, such as older videos existing beyond the list. Empty when there are none."
                    },
                    "videoId": {
                      "type": "string",
                      "description": "The video the recommendations are for."
                    },
                    "videos": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "additionalProperties": true,
                        "properties": {
                          "id": {
                            "type": "string",
                            "description": "The video id, which every route that takes a video accepts."
                          },
                          "url": {
                            "type": "string",
                            "description": "Link to the video on douyin.com."
                          },
                          "kind": {
                            "type": "string",
                            "description": "\"video\", or \"images\" for an image post."
                          },
                          "description": {
                            "type": "string",
                            "description": "The caption."
                          },
                          "createdAt": {
                            "type": "string",
                            "description": "When it was posted (ISO 8601); createTime is the same moment in unix seconds."
                          },
                          "durationMs": {
                            "type": [
                              "number",
                              "null"
                            ],
                            "description": "Length of a video, in milliseconds."
                          },
                          "hashtags": {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "additionalProperties": true
                            },
                            "description": "{ name, id } for each hashtag; the id works with hashtag-detail."
                          },
                          "stats": {
                            "type": "object",
                            "additionalProperties": true,
                            "description": "likes, comments, shares and saves — exact integers. plays is always null: Douyin does not publish play counts."
                          },
                          "author": {
                            "type": "object",
                            "additionalProperties": true,
                            "description": "uid, secUid, uniqueId (抖音号), nickname, avatarUrl, followerCount, verification and profileUrl. followerCount is null on this list, which means not on this answer, never zero; user-profile has it."
                          },
                          "music": {
                            "type": [
                              "object",
                              "null"
                            ],
                            "additionalProperties": true,
                            "description": "{ id, title, author } of the sound."
                          },
                          "coverUrl": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "Cover image. Douyin’s media links expire after a while."
                          },
                          "playUrl": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "The video stream. Expires after a while."
                          },
                          "imageUrls": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            },
                            "description": "The images of an image post; empty for a video."
                          },
                          "isAd": {
                            "type": "boolean",
                            "description": "Whether Douyin marks it as an ad."
                          },
                          "pinned": {
                            "type": "boolean",
                            "description": "Whether the author pinned it to their profile."
                          },
                          "collection": {
                            "type": [
                              "object",
                              "null"
                            ],
                            "additionalProperties": true,
                            "description": "The collection (合集) it belongs to: { id, name, episode }, or null. The id works with collection-videos."
                          },
                          "shareUrl": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "Douyin’s share link for it."
                          }
                        }
                      },
                      "description": "The recommended videos."
                    },
                    "videoCount": {
                      "type": "number",
                      "description": "How many videos are in this response."
                    },
                    "skippedRecords": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "additionalProperties": true
                      },
                      "description": "Items Douyin listed that could not be returned whole, each as { id, reason, fieldsPresent }; id may be null. Normally empty."
                    }
                  },
                  "additionalProperties": false
                },
                "examples": {
                  "default": {
                    "value": {
                      "transport": "douyin",
                      "fetchedAt": "2026-10-15T15:54:03.000Z",
                      "notes": [
                        "Douyin does not publish play counts, so stats.plays is always null."
                      ],
                      "videoId": "7665908051974704410",
                      "videos": [
                        {
                          "id": "7665908051974704410",
                          "url": "https://www.douyin.com/video/7665908051974704410",
                          "kind": "video",
                          "description": "1-8合集《这是我的世界》第一季|异世界篇 …",
                          "createdAt": "2026-07-24T01:58:31.000Z",
                          "createTime": 1784858311,
                          "durationMs": 2574891,
                          "hashtags": [
                            {
                              "name": "这是我的世界",
                              "id": "1587906243760205"
                            }
                          ],
                          "stats": {
                            "likes": 356766,
                            "comments": 6899,
                            "shares": 90087,
                            "saves": 176104,
                            "plays": null
                          },
                          "author": {
                            "uid": "593384953094045",
                            "secUid": "MS4wLjABAAAAYOEVkUXnngwqKUvaFEGdZWxDxUD6cEbk7zYTJGMrqPA",
                            "uniqueId": "Mom2024017",
                            "nickname": "林杉导演AIGC",
                            "followerCount": null,
                            "verification": null,
                            "profileUrl": "https://www.douyin.com/user/MS4wLjABAAAAYOEVkUXnngwqKUvaFEGdZWxDxUD6cEbk7zYTJGMrqPA"
                          },
                          "music": {
                            "id": "7665909117738830598",
                            "title": "@林杉导演AIGC创作的原声",
                            "author": "林杉导演AIGC"
                          },
                          "width": 2208,
                          "height": 936,
                          "imageUrls": [],
                          "isAd": false,
                          "pinned": false,
                          "collection": {
                            "id": "7640462496620349491",
                            "name": "原创AI《这是我的世界》第一季|异世界篇",
                            "episode": 11
                          }
                        }
                      ],
                      "videoCount": 10
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "invalid_input: the request needs fixing; error names the field.",
            "headers": {
              "X-Request-Id": {
                "description": "The request id, equal to requestId in the body.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized: the API key is missing or not valid.",
            "headers": {
              "X-Request-Id": {
                "description": "The request id, equal to requestId in the body.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "insufficient_credits: no credits, trial or monthly allowance left.",
            "headers": {
              "X-Request-Id": {
                "description": "The request id, equal to requestId in the body.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "forbidden: this key or account is not allowed this request.",
            "headers": {
              "X-Request-Id": {
                "description": "The request id, equal to requestId in the body.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "quota_exceeded: a request-rate limit was reached.",
            "headers": {
              "X-Request-Id": {
                "description": "The request id, equal to requestId in the body.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "temporarily_unavailable, time_limit or (on a store route) store_unreachable: ask again (with time_limit, allow more time). Retryable.",
            "headers": {
              "X-Request-Id": {
                "description": "The request id, equal to requestId in the body.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "BearerAuth": []
          }
        ]
      }
    },
    "/collection-videos": {
      "post": {
        "operationId": "collection-videos",
        "tags": [
          "Videos"
        ],
        "summary": "Every video in a collection",
        "description": "Every video in one collection (合集), in episode order, with the collection’s total plays and saves. Start from the collection’s id or link, or any video in it. Up to 500 in one request, continuing with a cursor. 1 credit per 15 videos.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "collection": {
                    "type": "string",
                    "description": "A collection id (as in any video’s collection.id) or a douyin.com/collection/... link. Give this or video, not both."
                  },
                  "video": {
                    "type": "string",
                    "description": "Any video in the collection (id or link); its collection is used. A video in no collection is a 404."
                  },
                  "limit": {
                    "type": "integer",
                    "description": "Maximum videos, up to 500, or -1 for the whole collection. Videos come 15 to a page and each page is 1 credit.",
                    "example": "50"
                  },
                  "cursor": {
                    "type": "string",
                    "description": "The cursor from a previous response, passed back unchanged with the same request, to continue exactly where it stopped. Treat it as opaque: a cursor from another route, video or collection, or one this service did not issue, is a 400 naming cursor."
                  },
                  "format": {
                    "type": "string",
                    "description": "json or markdown, lowercase; any other value is a 400. Over MCP, markdown returns the result rendered as text; the REST API accepts it and returns JSON.",
                    "example": "json"
                  },
                  "timeoutMs": {
                    "type": "integer",
                    "description": "Time limit for the whole request, in milliseconds (1000–120000); a value outside that range is a 400. Where possible a partial answer comes back with a note; a request with nothing to return yet fails with a 503 you can retry, marked with the response header X-Timeout-Source: caller."
                  }
                },
                "additionalProperties": false
              },
              "examples": {
                "default": {
                  "value": {
                    "collection": "7640462496620349491",
                    "limit": -1
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "transport": {
                      "type": "string",
                      "description": "The data source: always the platform id, \"douyin\"."
                    },
                    "fetchedAt": {
                      "type": "string",
                      "description": "When the data was read (ISO 8601)."
                    },
                    "notes": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      },
                      "description": "Caveats you can act on, such as older videos existing beyond the list. Empty when there are none."
                    },
                    "collection": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "description": "The collection’s id."
                        },
                        "name": {
                          "type": "string",
                          "description": "Its name."
                        },
                        "description": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "Its description."
                        },
                        "episodeCount": {
                          "type": "number",
                          "description": "Episodes in it."
                        },
                        "playCount": {
                          "type": "number",
                          "description": "Total plays across the collection, which Douyin publishes for collections."
                        },
                        "saveCount": {
                          "type": "number",
                          "description": "Total saves."
                        },
                        "author": {
                          "type": "object",
                          "additionalProperties": true,
                          "description": "The account that made it."
                        },
                        "createdAt": {
                          "type": "string",
                          "description": "When it was created; updatedAt is when it last changed."
                        },
                        "url": {
                          "type": "string",
                          "description": "Link to it."
                        }
                      },
                      "additionalProperties": false
                    },
                    "videos": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "additionalProperties": true,
                        "properties": {
                          "id": {
                            "type": "string",
                            "description": "The video id, which every route that takes a video accepts."
                          },
                          "url": {
                            "type": "string",
                            "description": "Link to the video on douyin.com."
                          },
                          "kind": {
                            "type": "string",
                            "description": "\"video\", or \"images\" for an image post."
                          },
                          "description": {
                            "type": "string",
                            "description": "The caption."
                          },
                          "createdAt": {
                            "type": "string",
                            "description": "When it was posted (ISO 8601); createTime is the same moment in unix seconds."
                          },
                          "durationMs": {
                            "type": [
                              "number",
                              "null"
                            ],
                            "description": "Length of a video, in milliseconds."
                          },
                          "hashtags": {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "additionalProperties": true
                            },
                            "description": "{ name, id } for each hashtag; the id works with hashtag-detail."
                          },
                          "stats": {
                            "type": "object",
                            "additionalProperties": true,
                            "description": "likes, comments, shares and saves — exact integers. plays is always null: Douyin does not publish play counts."
                          },
                          "author": {
                            "type": "object",
                            "additionalProperties": true,
                            "description": "uid, secUid, uniqueId (抖音号), nickname, avatarUrl, followerCount, verification and profileUrl. followerCount is null on this list, which means not on this answer, never zero; user-profile has it."
                          },
                          "music": {
                            "type": [
                              "object",
                              "null"
                            ],
                            "additionalProperties": true,
                            "description": "{ id, title, author } of the sound."
                          },
                          "coverUrl": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "Cover image. Douyin’s media links expire after a while."
                          },
                          "playUrl": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "The video stream. Expires after a while."
                          },
                          "imageUrls": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            },
                            "description": "The images of an image post; empty for a video."
                          },
                          "isAd": {
                            "type": "boolean",
                            "description": "Whether Douyin marks it as an ad."
                          },
                          "pinned": {
                            "type": "boolean",
                            "description": "Whether the author pinned it to their profile."
                          },
                          "collection": {
                            "type": [
                              "object",
                              "null"
                            ],
                            "additionalProperties": true,
                            "description": "The collection (合集) it belongs to: { id, name, episode }, or null. The id works with collection-videos."
                          },
                          "shareUrl": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "Douyin’s share link for it."
                          }
                        }
                      },
                      "description": "The videos in episode order, each with collection.episode set."
                    },
                    "videoCount": {
                      "type": "number",
                      "description": "How many videos are in this response."
                    },
                    "skippedRecords": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "additionalProperties": true
                      },
                      "description": "Items Douyin listed that could not be returned whole, each as { id, reason, fieldsPresent }; id may be null. Normally empty."
                    },
                    "pagesFetched": {
                      "type": "number",
                      "description": "Pages read, 15 videos to a page, which is what the request costs: one credit per page."
                    },
                    "hasMore": {
                      "type": "boolean",
                      "description": "Whether more videos remain."
                    },
                    "cursor": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Pass back as cursor, with the same request, to continue exactly where this response stopped. null when there is nothing further."
                    }
                  },
                  "additionalProperties": false
                },
                "examples": {
                  "default": {
                    "value": {
                      "transport": "douyin",
                      "fetchedAt": "2026-10-15T15:54:18.837Z",
                      "notes": [
                        "Douyin does not publish play counts, so stats.plays is always null."
                      ],
                      "collection": {
                        "id": "7640462496620349491",
                        "name": "原创AI《这是我的世界》第一季|异世界篇",
                        "episodeCount": 18,
                        "playCount": 57660398,
                        "saveCount": 635035,
                        "createdAt": "2026-05-16T12:16:40.000Z",
                        "updatedAt": "2026-09-02T13:40:12.000Z",
                        "url": "https://www.douyin.com/collection/7640462496620349491"
                      },
                      "videos": [
                        {
                          "id": "7665908051974704410",
                          "url": "https://www.douyin.com/video/7665908051974704410",
                          "kind": "video",
                          "description": "1-8合集《这是我的世界》第一季|异世界篇 …",
                          "createdAt": "2026-07-24T01:58:31.000Z",
                          "createTime": 1784858311,
                          "durationMs": 2574891,
                          "hashtags": [
                            {
                              "name": "这是我的世界",
                              "id": "1587906243760205"
                            }
                          ],
                          "stats": {
                            "likes": 356766,
                            "comments": 6899,
                            "shares": 90087,
                            "saves": 176104,
                            "plays": null
                          },
                          "author": {
                            "uid": "593384953094045",
                            "secUid": "MS4wLjABAAAAYOEVkUXnngwqKUvaFEGdZWxDxUD6cEbk7zYTJGMrqPA",
                            "uniqueId": "Mom2024017",
                            "nickname": "林杉导演AIGC",
                            "followerCount": 397848,
                            "verification": null,
                            "profileUrl": "https://www.douyin.com/user/MS4wLjABAAAAYOEVkUXnngwqKUvaFEGdZWxDxUD6cEbk7zYTJGMrqPA"
                          },
                          "music": {
                            "id": "7665909117738830598",
                            "title": "@林杉导演AIGC创作的原声",
                            "author": "林杉导演AIGC"
                          },
                          "width": 2208,
                          "height": 936,
                          "imageUrls": [],
                          "isAd": false,
                          "pinned": false,
                          "collection": {
                            "id": "7640462496620349491",
                            "name": "原创AI《这是我的世界》第一季|异世界篇",
                            "episode": 11
                          }
                        }
                      ],
                      "videoCount": 18,
                      "pagesFetched": 2,
                      "hasMore": false,
                      "cursor": null
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "invalid_input: the request needs fixing; error names the field.",
            "headers": {
              "X-Request-Id": {
                "description": "The request id, equal to requestId in the body.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized: the API key is missing or not valid.",
            "headers": {
              "X-Request-Id": {
                "description": "The request id, equal to requestId in the body.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "insufficient_credits: no credits, trial or monthly allowance left.",
            "headers": {
              "X-Request-Id": {
                "description": "The request id, equal to requestId in the body.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "forbidden: this key or account is not allowed this request.",
            "headers": {
              "X-Request-Id": {
                "description": "The request id, equal to requestId in the body.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "quota_exceeded: a request-rate limit was reached.",
            "headers": {
              "X-Request-Id": {
                "description": "The request id, equal to requestId in the body.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "temporarily_unavailable, time_limit or (on a store route) store_unreachable: ask again (with time_limit, allow more time). Retryable.",
            "headers": {
              "X-Request-Id": {
                "description": "The request id, equal to requestId in the body.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "BearerAuth": []
          }
        ]
      }
    },
    "/user-profile": {
      "post": {
        "operationId": "user-profile",
        "tags": [
          "Accounts"
        ],
        "summary": "Get an account’s profile",
        "description": "A Douyin account’s profile by sec_uid, profile link or share link: bio, IP location, verification, exact follower and following counts, video count and the likes its videos have received. 1 credit.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "user": {
                    "type": "string",
                    "description": "An account: its sec_uid (starts with MS4wLjAB), a douyin.com/user/... link, or a v.douyin.com share link to the profile."
                  },
                  "format": {
                    "type": "string",
                    "description": "json or markdown, lowercase; any other value is a 400. Over MCP, markdown returns the result rendered as text; the REST API accepts it and returns JSON.",
                    "example": "json"
                  },
                  "timeoutMs": {
                    "type": "integer",
                    "description": "Time limit for the whole request, in milliseconds (1000–120000); a value outside that range is a 400. Where possible a partial answer comes back with a note; a request with nothing to return yet fails with a 503 you can retry, marked with the response header X-Timeout-Source: caller."
                  }
                },
                "additionalProperties": false,
                "required": [
                  "user"
                ]
              },
              "examples": {
                "default": {
                  "value": {
                    "user": "MS4wLjABAAAAYOEVkUXnngwqKUvaFEGdZWxDxUD6cEbk7zYTJGMrqPA"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "transport": {
                      "type": "string",
                      "description": "The data source: always the platform id, \"douyin\"."
                    },
                    "fetchedAt": {
                      "type": "string",
                      "description": "When the data was read (ISO 8601)."
                    },
                    "notes": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      },
                      "description": "Caveats you can act on, such as older videos existing beyond the list. Empty when there are none."
                    },
                    "profile": {
                      "type": "object",
                      "properties": {
                        "secUid": {
                          "type": "string",
                          "description": "The account’s sec_uid, which every account route accepts."
                        },
                        "uid": {
                          "type": "string",
                          "description": "Douyin’s numeric account id."
                        },
                        "uniqueId": {
                          "type": "string",
                          "description": "The 抖音号 (Douyin handle)."
                        },
                        "nickname": {
                          "type": "string",
                          "description": "The display name."
                        },
                        "signature": {
                          "type": "string",
                          "description": "The bio."
                        },
                        "avatarUrl": {
                          "type": "string",
                          "description": "Avatar image."
                        },
                        "followerCount": {
                          "type": "number",
                          "description": "Followers, exact."
                        },
                        "followingCount": {
                          "type": "number",
                          "description": "Accounts it follows."
                        },
                        "totalLikes": {
                          "type": "number",
                          "description": "Likes its videos have received."
                        },
                        "videoCount": {
                          "type": "number",
                          "description": "Videos it has posted."
                        },
                        "ipLocation": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "The province or country Douyin shows on the profile (IP属地), e.g. 广西."
                        },
                        "verification": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "Douyin’s verification text, or null."
                        },
                        "isPrivate": {
                          "type": "boolean",
                          "description": "Whether the account is private."
                        },
                        "profileUrl": {
                          "type": "string",
                          "description": "Link to the profile."
                        }
                      },
                      "additionalProperties": false
                    }
                  },
                  "additionalProperties": false
                },
                "examples": {
                  "default": {
                    "value": {
                      "transport": "douyin",
                      "fetchedAt": "2026-10-15T15:54:17.000Z",
                      "notes": [],
                      "profile": {
                        "secUid": "MS4wLjABAAAAYOEVkUXnngwqKUvaFEGdZWxDxUD6cEbk7zYTJGMrqPA",
                        "uid": "593384953094045",
                        "uniqueId": "Mom2024017",
                        "nickname": "林杉导演AIGC",
                        "signature": "❤️AI原创剧集《这是我的世界》持续更新中🎬",
                        "followerCount": 397848,
                        "followingCount": 22,
                        "totalLikes": 1441789,
                        "videoCount": 33,
                        "ipLocation": "广西",
                        "verification": null,
                        "isPrivate": false,
                        "profileUrl": "https://www.douyin.com/user/MS4wLjABAAAAYOEVkUXnngwqKUvaFEGdZWxDxUD6cEbk7zYTJGMrqPA"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "invalid_input: the request needs fixing; error names the field.",
            "headers": {
              "X-Request-Id": {
                "description": "The request id, equal to requestId in the body.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized: the API key is missing or not valid.",
            "headers": {
              "X-Request-Id": {
                "description": "The request id, equal to requestId in the body.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "insufficient_credits: no credits, trial or monthly allowance left.",
            "headers": {
              "X-Request-Id": {
                "description": "The request id, equal to requestId in the body.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "forbidden: this key or account is not allowed this request.",
            "headers": {
              "X-Request-Id": {
                "description": "The request id, equal to requestId in the body.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "quota_exceeded: a request-rate limit was reached.",
            "headers": {
              "X-Request-Id": {
                "description": "The request id, equal to requestId in the body.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "temporarily_unavailable, time_limit or (on a store route) store_unreachable: ask again (with time_limit, allow more time). Retryable.",
            "headers": {
              "X-Request-Id": {
                "description": "The request id, equal to requestId in the body.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "BearerAuth": []
          }
        ]
      }
    },
    "/user-videos": {
      "post": {
        "operationId": "user-videos",
        "tags": [
          "Accounts"
        ],
        "summary": "List an account’s recent videos",
        "description": "An account’s most recent videos, newest first: up to about 41, in one response, with no cursor for older ones. olderVideosExist says when the account has more; older videos in a collection can be read with collection-videos. 1 credit.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "user": {
                    "type": "string",
                    "description": "An account: its sec_uid (starts with MS4wLjAB), a douyin.com/user/... link, or a v.douyin.com share link to the profile."
                  },
                  "limit": {
                    "type": "integer",
                    "description": "Maximum videos, up to 50, or -1. Left out, every video shown (about 41)."
                  },
                  "format": {
                    "type": "string",
                    "description": "json or markdown, lowercase; any other value is a 400. Over MCP, markdown returns the result rendered as text; the REST API accepts it and returns JSON.",
                    "example": "json"
                  },
                  "timeoutMs": {
                    "type": "integer",
                    "description": "Time limit for the whole request, in milliseconds (1000–120000); a value outside that range is a 400. Where possible a partial answer comes back with a note; a request with nothing to return yet fails with a 503 you can retry, marked with the response header X-Timeout-Source: caller."
                  }
                },
                "additionalProperties": false,
                "required": [
                  "user"
                ]
              },
              "examples": {
                "default": {
                  "value": {
                    "user": "https://www.douyin.com/user/MS4wLjABAAAAYOEVkUXnngwqKUvaFEGdZWxDxUD6cEbk7zYTJGMrqPA",
                    "limit": 10
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "transport": {
                      "type": "string",
                      "description": "The data source: always the platform id, \"douyin\"."
                    },
                    "fetchedAt": {
                      "type": "string",
                      "description": "When the data was read (ISO 8601)."
                    },
                    "notes": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      },
                      "description": "Caveats you can act on, such as older videos existing beyond the list. Empty when there are none."
                    },
                    "secUid": {
                      "type": "string",
                      "description": "The account’s sec_uid."
                    },
                    "videos": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "additionalProperties": true,
                        "properties": {
                          "id": {
                            "type": "string",
                            "description": "The video id, which every route that takes a video accepts."
                          },
                          "url": {
                            "type": "string",
                            "description": "Link to the video on douyin.com."
                          },
                          "kind": {
                            "type": "string",
                            "description": "\"video\", or \"images\" for an image post."
                          },
                          "description": {
                            "type": "string",
                            "description": "The caption."
                          },
                          "createdAt": {
                            "type": "string",
                            "description": "When it was posted (ISO 8601); createTime is the same moment in unix seconds."
                          },
                          "durationMs": {
                            "type": [
                              "number",
                              "null"
                            ],
                            "description": "Length of a video, in milliseconds."
                          },
                          "hashtags": {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "additionalProperties": true
                            },
                            "description": "{ name, id } for each hashtag; the id works with hashtag-detail."
                          },
                          "stats": {
                            "type": "object",
                            "additionalProperties": true,
                            "description": "likes, comments, shares and saves — exact integers. plays is always null: Douyin does not publish play counts."
                          },
                          "author": {
                            "type": "object",
                            "additionalProperties": true,
                            "description": "uid, secUid, uniqueId (抖音号), nickname, avatarUrl, followerCount, verification and profileUrl. followerCount is null on this list, which means not on this answer, never zero; user-profile has it."
                          },
                          "music": {
                            "type": [
                              "object",
                              "null"
                            ],
                            "additionalProperties": true,
                            "description": "{ id, title, author } of the sound."
                          },
                          "coverUrl": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "Cover image. Douyin’s media links expire after a while."
                          },
                          "playUrl": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "The video stream. Expires after a while."
                          },
                          "imageUrls": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            },
                            "description": "The images of an image post; empty for a video."
                          },
                          "isAd": {
                            "type": "boolean",
                            "description": "Whether Douyin marks it as an ad."
                          },
                          "pinned": {
                            "type": "boolean",
                            "description": "Whether the author pinned it to their profile."
                          },
                          "collection": {
                            "type": [
                              "object",
                              "null"
                            ],
                            "additionalProperties": true,
                            "description": "The collection (合集) it belongs to: { id, name, episode }, or null. The id works with collection-videos."
                          },
                          "shareUrl": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "Douyin’s share link for it."
                          }
                        }
                      },
                      "description": "The videos, newest first."
                    },
                    "videoCount": {
                      "type": "number",
                      "description": "How many videos are in this response."
                    },
                    "skippedRecords": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "additionalProperties": true
                      },
                      "description": "Items Douyin listed that could not be returned whole, each as { id, reason, fieldsPresent }; id may be null. Normally empty."
                    },
                    "olderVideosExist": {
                      "type": "boolean",
                      "description": "True when the account has older videos than this list reaches; notes says so too."
                    }
                  },
                  "additionalProperties": false
                },
                "examples": {
                  "default": {
                    "value": {
                      "transport": "douyin",
                      "fetchedAt": "2026-10-15T15:54:21.896Z",
                      "notes": [
                        "Douyin does not publish play counts, so stats.plays is always null."
                      ],
                      "secUid": "MS4wLjABAAAAYOEVkUXnngwqKUvaFEGdZWxDxUD6cEbk7zYTJGMrqPA",
                      "videos": [
                        {
                          "id": "7665908051974704410",
                          "url": "https://www.douyin.com/video/7665908051974704410",
                          "kind": "video",
                          "description": "1-8合集《这是我的世界》第一季|异世界篇 …",
                          "createdAt": "2026-07-24T01:58:31.000Z",
                          "createTime": 1784858311,
                          "durationMs": 2574891,
                          "hashtags": [
                            {
                              "name": "这是我的世界",
                              "id": "1587906243760205"
                            }
                          ],
                          "stats": {
                            "likes": 356766,
                            "comments": 6899,
                            "shares": 90087,
                            "saves": 176104,
                            "plays": null
                          },
                          "author": {
                            "uid": "593384953094045",
                            "secUid": "MS4wLjABAAAAYOEVkUXnngwqKUvaFEGdZWxDxUD6cEbk7zYTJGMrqPA",
                            "uniqueId": "Mom2024017",
                            "nickname": "林杉导演AIGC",
                            "followerCount": null,
                            "verification": null,
                            "profileUrl": "https://www.douyin.com/user/MS4wLjABAAAAYOEVkUXnngwqKUvaFEGdZWxDxUD6cEbk7zYTJGMrqPA"
                          },
                          "music": {
                            "id": "7665909117738830598",
                            "title": "@林杉导演AIGC创作的原声",
                            "author": "林杉导演AIGC"
                          },
                          "width": 2208,
                          "height": 936,
                          "imageUrls": [],
                          "isAd": false,
                          "pinned": false,
                          "collection": {
                            "id": "7640462496620349491",
                            "name": "原创AI《这是我的世界》第一季|异世界篇",
                            "episode": 11
                          }
                        }
                      ],
                      "videoCount": 10,
                      "olderVideosExist": false
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "invalid_input: the request needs fixing; error names the field.",
            "headers": {
              "X-Request-Id": {
                "description": "The request id, equal to requestId in the body.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized: the API key is missing or not valid.",
            "headers": {
              "X-Request-Id": {
                "description": "The request id, equal to requestId in the body.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "insufficient_credits: no credits, trial or monthly allowance left.",
            "headers": {
              "X-Request-Id": {
                "description": "The request id, equal to requestId in the body.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "forbidden: this key or account is not allowed this request.",
            "headers": {
              "X-Request-Id": {
                "description": "The request id, equal to requestId in the body.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "quota_exceeded: a request-rate limit was reached.",
            "headers": {
              "X-Request-Id": {
                "description": "The request id, equal to requestId in the body.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "temporarily_unavailable, time_limit or (on a store route) store_unreachable: ask again (with time_limit, allow more time). Retryable.",
            "headers": {
              "X-Request-Id": {
                "description": "The request id, equal to requestId in the body.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "BearerAuth": []
          }
        ]
      }
    },
    "/trending": {
      "post": {
        "operationId": "trending",
        "tags": [
          "Trending & hashtags"
        ],
        "summary": "Get the hot-search board",
        "description": "Douyin’s hot-search board: rank, word, heat score, view and video counts, Douyin’s badge code and when the entry broke. Entries pinned above the board come with position null and pinned true. 1 credit.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "limit": {
                    "type": "integer",
                    "description": "Maximum entries, up to 100, or -1. Left out, the whole board (about 50)."
                  },
                  "format": {
                    "type": "string",
                    "description": "json or markdown, lowercase; any other value is a 400. Over MCP, markdown returns the result rendered as text; the REST API accepts it and returns JSON.",
                    "example": "json"
                  },
                  "timeoutMs": {
                    "type": "integer",
                    "description": "Time limit for the whole request, in milliseconds (1000–120000); a value outside that range is a 400. Where possible a partial answer comes back with a note; a request with nothing to return yet fails with a 503 you can retry, marked with the response header X-Timeout-Source: caller."
                  }
                },
                "additionalProperties": false
              },
              "examples": {
                "default": {
                  "value": {
                    "limit": 20
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "transport": {
                      "type": "string",
                      "description": "The data source: always the platform id, \"douyin\"."
                    },
                    "fetchedAt": {
                      "type": "string",
                      "description": "When the data was read (ISO 8601)."
                    },
                    "notes": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      },
                      "description": "Caveats you can act on, such as older videos existing beyond the list. Empty when there are none."
                    },
                    "items": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "additionalProperties": true,
                        "properties": {
                          "position": {
                            "type": [
                              "number",
                              "null"
                            ],
                            "description": "Rank, or null for an entry pinned above the board."
                          },
                          "pinned": {
                            "type": "boolean",
                            "description": "True for an entry pinned above the board."
                          },
                          "word": {
                            "type": "string",
                            "description": "The topic."
                          },
                          "hotValue": {
                            "type": [
                              "number",
                              "null"
                            ],
                            "description": "Douyin’s heat score."
                          },
                          "viewCount": {
                            "type": [
                              "number",
                              "null"
                            ],
                            "description": "Views of the topic."
                          },
                          "videoCount": {
                            "type": [
                              "number",
                              "null"
                            ],
                            "description": "Videos on the topic."
                          },
                          "labelCode": {
                            "type": [
                              "number",
                              "null"
                            ],
                            "description": "Douyin’s badge code for the entry, as published."
                          },
                          "eventTime": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "When the entry broke (ISO 8601)."
                          },
                          "sentenceId": {
                            "type": "string",
                            "description": "Douyin’s id for the entry."
                          },
                          "coverUrl": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "Cover image."
                          }
                        }
                      },
                      "description": "The board, in order."
                    },
                    "itemCount": {
                      "type": "number",
                      "description": "How many entries are in this response."
                    }
                  },
                  "additionalProperties": false
                },
                "examples": {
                  "default": {
                    "value": {
                      "transport": "douyin",
                      "fetchedAt": "2026-10-15T15:54:01.000Z",
                      "notes": [],
                      "items": [
                        {
                          "position": 1,
                          "pinned": false,
                          "word": "抖音商城双11超级补贴来啦",
                          "hotValue": 12296885,
                          "viewCount": 66580116,
                          "videoCount": 3,
                          "labelCode": 3,
                          "eventTime": "2026-10-15T04:20:52.000Z",
                          "sentenceId": "2696275"
                        }
                      ],
                      "itemCount": 20
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "invalid_input: the request needs fixing; error names the field.",
            "headers": {
              "X-Request-Id": {
                "description": "The request id, equal to requestId in the body.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized: the API key is missing or not valid.",
            "headers": {
              "X-Request-Id": {
                "description": "The request id, equal to requestId in the body.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "insufficient_credits: no credits, trial or monthly allowance left.",
            "headers": {
              "X-Request-Id": {
                "description": "The request id, equal to requestId in the body.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "forbidden: this key or account is not allowed this request.",
            "headers": {
              "X-Request-Id": {
                "description": "The request id, equal to requestId in the body.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "quota_exceeded: a request-rate limit was reached.",
            "headers": {
              "X-Request-Id": {
                "description": "The request id, equal to requestId in the body.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "temporarily_unavailable, time_limit or (on a store route) store_unreachable: ask again (with time_limit, allow more time). Retryable.",
            "headers": {
              "X-Request-Id": {
                "description": "The request id, equal to requestId in the body.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "BearerAuth": []
          }
        ]
      }
    },
    "/hashtag-detail": {
      "post": {
        "operationId": "hashtag-detail",
        "tags": [
          "Trending & hashtags"
        ],
        "summary": "Get a hashtag’s summary",
        "description": "A hashtag’s views and the number of accounts that have posted with it, by id or link. The videos under a hashtag are not available. 1 credit.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "hashtag": {
                    "type": "string",
                    "description": "A hashtag id (digits, as in a video’s hashtags[].id) or a douyin.com/hashtag/... link."
                  },
                  "format": {
                    "type": "string",
                    "description": "json or markdown, lowercase; any other value is a 400. Over MCP, markdown returns the result rendered as text; the REST API accepts it and returns JSON.",
                    "example": "json"
                  },
                  "timeoutMs": {
                    "type": "integer",
                    "description": "Time limit for the whole request, in milliseconds (1000–120000); a value outside that range is a 400. Where possible a partial answer comes back with a note; a request with nothing to return yet fails with a 503 you can retry, marked with the response header X-Timeout-Source: caller."
                  }
                },
                "additionalProperties": false,
                "required": [
                  "hashtag"
                ]
              },
              "examples": {
                "default": {
                  "value": {
                    "hashtag": "1587906243760205"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "transport": {
                      "type": "string",
                      "description": "The data source: always the platform id, \"douyin\"."
                    },
                    "fetchedAt": {
                      "type": "string",
                      "description": "When the data was read (ISO 8601)."
                    },
                    "notes": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      },
                      "description": "Caveats you can act on, such as older videos existing beyond the list. Empty when there are none."
                    },
                    "hashtag": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "description": "The hashtag’s id."
                        },
                        "name": {
                          "type": "string",
                          "description": "Its name, without the #."
                        },
                        "description": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "Its description."
                        },
                        "viewCount": {
                          "type": "number",
                          "description": "Views across its videos."
                        },
                        "userCount": {
                          "type": "number",
                          "description": "Accounts that have posted with it."
                        },
                        "coverUrl": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "Cover image."
                        },
                        "url": {
                          "type": "string",
                          "description": "Link to it."
                        }
                      },
                      "additionalProperties": false
                    }
                  },
                  "additionalProperties": false
                },
                "examples": {
                  "default": {
                    "value": {
                      "transport": "douyin",
                      "fetchedAt": "2026-10-15T15:54:17.269Z",
                      "notes": [],
                      "hashtag": {
                        "id": "1587906243760205",
                        "name": "这是我的世界",
                        "description": null,
                        "viewCount": 69706664,
                        "userCount": 1826,
                        "url": "https://www.douyin.com/hashtag/1587906243760205"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "invalid_input: the request needs fixing; error names the field.",
            "headers": {
              "X-Request-Id": {
                "description": "The request id, equal to requestId in the body.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized: the API key is missing or not valid.",
            "headers": {
              "X-Request-Id": {
                "description": "The request id, equal to requestId in the body.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "insufficient_credits: no credits, trial or monthly allowance left.",
            "headers": {
              "X-Request-Id": {
                "description": "The request id, equal to requestId in the body.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "forbidden: this key or account is not allowed this request.",
            "headers": {
              "X-Request-Id": {
                "description": "The request id, equal to requestId in the body.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "quota_exceeded: a request-rate limit was reached.",
            "headers": {
              "X-Request-Id": {
                "description": "The request id, equal to requestId in the body.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "temporarily_unavailable, time_limit or (on a store route) store_unreachable: ask again (with time_limit, allow more time). Retryable.",
            "headers": {
              "X-Request-Id": {
                "description": "The request id, equal to requestId in the body.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "BearerAuth": []
          }
        ]
      }
    },
    "/resolve-url": {
      "post": {
        "operationId": "resolve-url",
        "tags": [
          "Utilities"
        ],
        "summary": "Parse a Douyin link",
        "description": "Whether a Douyin link or pasted share text is a video, an account, a hashtag or a collection, with its id and canonical address. Free.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "url": {
                    "type": "string",
                    "description": "Any Douyin link — video, image post, profile, hashtag, collection, or a v.douyin.com share link — or share text containing one."
                  },
                  "format": {
                    "type": "string",
                    "description": "json or markdown, lowercase; any other value is a 400. Over MCP, markdown returns the result rendered as text; the REST API accepts it and returns JSON.",
                    "example": "json"
                  },
                  "timeoutMs": {
                    "type": "integer",
                    "description": "Time limit for the whole request, in milliseconds (1000–120000); a value outside that range is a 400. Where possible a partial answer comes back with a note; a request with nothing to return yet fails with a 503 you can retry, marked with the response header X-Timeout-Source: caller."
                  }
                },
                "additionalProperties": false,
                "required": [
                  "url"
                ]
              },
              "examples": {
                "default": {
                  "value": {
                    "url": "https://www.douyin.com/video/7665908051974704410"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "transport": {
                      "type": "string",
                      "description": "The data source: always the platform id, \"douyin\"."
                    },
                    "fetchedAt": {
                      "type": "string",
                      "description": "When the data was read (ISO 8601)."
                    },
                    "notes": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      },
                      "description": "Caveats you can act on, such as older videos existing beyond the list. Empty when there are none."
                    },
                    "kind": {
                      "type": "string",
                      "description": "video, user, hashtag or collection."
                    },
                    "id": {
                      "type": "string",
                      "description": "The video id, sec_uid, hashtag id or collection id."
                    },
                    "canonicalUrl": {
                      "type": "string",
                      "description": "The canonical address."
                    }
                  },
                  "additionalProperties": false
                },
                "examples": {
                  "default": {
                    "value": {
                      "transport": "douyin",
                      "fetchedAt": "2026-10-15T15:54:02.874Z",
                      "notes": [],
                      "kind": "video",
                      "id": "7665908051974704410",
                      "canonicalUrl": "https://www.douyin.com/video/7665908051974704410"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "invalid_input: the request needs fixing; error names the field.",
            "headers": {
              "X-Request-Id": {
                "description": "The request id, equal to requestId in the body.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized: the API key is missing or not valid.",
            "headers": {
              "X-Request-Id": {
                "description": "The request id, equal to requestId in the body.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "insufficient_credits: no credits, trial or monthly allowance left.",
            "headers": {
              "X-Request-Id": {
                "description": "The request id, equal to requestId in the body.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "forbidden: this key or account is not allowed this request.",
            "headers": {
              "X-Request-Id": {
                "description": "The request id, equal to requestId in the body.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "quota_exceeded: a request-rate limit was reached.",
            "headers": {
              "X-Request-Id": {
                "description": "The request id, equal to requestId in the body.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "temporarily_unavailable, time_limit or (on a store route) store_unreachable: ask again (with time_limit, allow more time). Retryable.",
            "headers": {
              "X-Request-Id": {
                "description": "The request id, equal to requestId in the body.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "BearerAuth": []
          }
        ]
      }
    }
  }
}