> ## Documentation Index
> Fetch the complete documentation index at: https://docs.vidnavigator.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Submit TikTok Search

> Start an asynchronous TikTok keyword search task and return a `task_id` immediately. Poll `GET /tiktok/search/{task_id}` for cursor-paginated results. Results are retained for ~1 hour.

Results are returned sorted by `published_at` descending (newest first) across pagination, full retrieval, and the signed `download_url` payload.

**parallel_search_slices billing:** by default (`1`), the search runs a single paginated query chain and is naturally capped near 120 items by TikTok. Setting `parallel_search_slices` to `2..4` runs that many concurrent chains in parallel and dedups by video id, lifting the effective ceiling. Cost scales linearly: each additional slice consumes up to ~1x the residential pages of a single search, so an N-slice request bills up to **Nx the residential pages**. `parallel_search_slices` is *not* a time filter — use `after_datetime` / `before_datetime` for time windows.

**Usage disclosure:** This endpoint does NOT accept `include_usage`. Billing happens in the background worker after the 202 response is sent, so there is nothing to disclose at submit time. Pass `include_usage=true` on `GET /tiktok/search/{task_id}` instead — the GET endpoint replays the final charges once `task_status=completed`.

Start an asynchronous TikTok keyword search and get a `task_id` back immediately.

## Overview

This endpoint runs an actual keyword search across TikTok (not a single profile) and returns multiple matching videos. It is asynchronous: the search runs in a background worker, and you poll [`GET /tiktok/search/{task_id}`](/api-reference/endpoint/tiktok-search-result) for cursor-paginated results. Results are retained for \~1 hour.

Results are returned sorted by `published_at` descending (newest first) across pagination, full retrieval, and the signed `download_url` payload.

<Note>
  This is different from the [TikTok Profile scrape](/api-reference/endpoint/tiktok-profile), which walks a single account's videos. Use this endpoint to discover videos across TikTok by keyword.
</Note>

## Billing

Charges happen in the background worker and are disclosed on the polling endpoint (see below), not here.

* Billing is `pages_fetched × residential_request`. **No `search_request`** is billed for TikTok keyword search.
* **`parallel_search_slices`** scales the cost linearly. By default (`1`) the search runs a single paginated query chain, naturally capped near \~120 items by TikTok. Setting it to `2..4` runs that many concurrent chains and dedups by video id, lifting the ceiling — but an N-slice request bills up to **N× the residential pages** of a single search.

<Warning>
  **Usage disclosure:** this endpoint does **not** accept `include_usage`. Because billing happens after the `202` response is sent, there is nothing to disclose at submit time. Pass `include_usage=true` on [`GET /tiktok/search/{task_id}`](/api-reference/endpoint/tiktok-search-result) instead — it replays the final charges once `task_status=completed`.
</Warning>

## Request Parameters

| Parameter                | Type    | Required | Description                                                                                                                                                                                                                                                                 |
| ------------------------ | ------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `query`                  | string  | Yes      | Keyword phrase to search on TikTok (min length 2).                                                                                                                                                                                                                          |
| `max_results`            | integer | No       | Upper bound on results the task will try to collect. `0` (default) or omitted means **unlimited** — pagination stops only at TikTok's `has_more=false` or the upstream page cap. No hard server-side cap is enforced; you are billed per residential page actually fetched. |
| `parallel_search_slices` | integer | No       | How many concurrent paginated query chains to run and dedup (`1`–`4`, default `1`). Higher values lift the result ceiling at up to **\~N× the residential pages** of a single search. Not a time filter — use `after_datetime` / `before_datetime` for time windows.        |
| `after_datetime`         | string  | No       | Only include videos published on or after this boundary. Accepts `YYYY-MM-DD` or an ISO datetime with timezone.                                                                                                                                                             |
| `before_datetime`        | string  | No       | Only include videos published on or before this boundary. Accepts `YYYY-MM-DD` or an ISO datetime with timezone.                                                                                                                                                            |
| `min_likes`              | integer | No       | Only include videos with at least this many likes.                                                                                                                                                                                                                          |
| `max_likes`              | integer | No       | Only include videos with at most this many likes.                                                                                                                                                                                                                           |
| `min_views`              | integer | No       | Only include videos with at least this many views.                                                                                                                                                                                                                          |
| `max_views`              | integer | No       | Only include videos with at most this many views.                                                                                                                                                                                                                           |

<Tip>
  **Diminishing returns on slices:** on a representative query, 2 slices yield \~+43% unique items, 3 slices \~+22%, and 4 slices \~+13% — so 4 already saturates TikTok's natural \~480-item dedup ceiling for most queries.
</Tip>

## Example Usage

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://api.vidnavigator.com/v1/tiktok/search" \
    -H "X-API-Key: YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "query": "ai tools",
      "parallel_search_slices": 2,
      "after_datetime": "2024-01-01T00:00:00Z",
      "min_likes": 1000
    }'
  ```

  ```python Python theme={null}
  import requests

  url = "https://api.vidnavigator.com/v1/tiktok/search"
  headers = {
      "X-API-Key": "YOUR_API_KEY",
      "Content-Type": "application/json"
  }
  data = {
      "query": "ai tools",
      "parallel_search_slices": 2,
      "after_datetime": "2024-01-01T00:00:00Z",
      "min_likes": 1000
  }

  response = requests.post(url, headers=headers, json=data)
  task = response.json()
  print("Task ID:", task["data"]["task_id"])
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch('https://api.vidnavigator.com/v1/tiktok/search', {
    method: 'POST',
    headers: {
      'X-API-Key': 'YOUR_API_KEY',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      query: 'ai tools',
      parallel_search_slices: 2,
      after_datetime: '2024-01-01T00:00:00Z',
      min_likes: 1000
    })
  });

  const task = await response.json();
  console.log('Task ID:', task.data.task_id);
  ```
</CodeGroup>

## Success Response (202 Accepted)

```json theme={null}
{
  "status": "success",
  "data": {
    "task_id": "550e8400-e29b-41d4-a716-446655440000",
    "task_status": "processing",
    "query": "ai tools",
    "max_results": 0,
    "parallel_search_slices": 2,
    "filters": {
      "after_datetime": "2024-01-01T00:00:00Z",
      "before_datetime": null,
      "min_likes": 1000,
      "max_likes": null,
      "min_views": null,
      "max_views": null
    },
    "expires_at": "2026-04-26T13:00:00Z",
    "check_status_url": "/v1/tiktok/search/550e8400-e29b-41d4-a716-446655440000",
    "message": "TikTok search task accepted and queued."
  }
}
```

## Next Steps

Poll [`GET /tiktok/search/{task_id}`](/api-reference/endpoint/tiktok-search-result) to retrieve paginated results, or follow the `download_url` for the complete JSON once the task is `completed`.


## OpenAPI

````yaml POST /tiktok/search
openapi: 3.0.3
info:
  title: VidNavigator Developer API
  description: >-
    The VidNavigator Developer API provides programmatic access to video
    analysis, transcription, and search capabilities.


    ## Authentication

    All endpoints require API key authentication via the `X-API-Key` header:

    ```

    X-API-Key: YOUR_API_KEY

    ```


    ## Rate Limits

    Check the documentation for the rate limits for each endpoint.


    ## Error Handling

    The API uses standard HTTP status codes and returns error responses in JSON
    format:

    ```json

    {
      "status": "error",
      "error": "error_type",
      "message": "Human readable error message"
    }

    ```
  version: 1.0.0
  contact:
    name: VidNavigator Support
    url: https://vidnavigator.com/support
    email: support@vidnavigator.com
  license:
    name: Proprietary
    url: https://vidnavigator.com/terms
servers:
  - url: https://api.vidnavigator.com/v1
    description: Production server
security:
  - ApiKeyAuth: []
tags:
  - name: Transcripts
    description: Extract transcripts from online videos
  - name: TikTok
    description: Scrape TikTok profile metadata and per-video stats
  - name: Files
    description: Manage uploaded audio/video files
  - name: Analysis
    description: AI-powered content analysis
  - name: Extraction
    description: >-
      Extract structured data from video and file transcripts using custom
      schemas
  - name: Namespaces
    description: Organize uploaded files into namespaces (folders)
  - name: Search
    description: Search videos and files using AI
  - name: System
    description: System health and information
  - name: Tweet Analysis
    description: Extract structured claims and metadata from X/Twitter tweets
paths:
  /tiktok/search:
    post:
      tags:
        - TikTok
      summary: Submit a TikTok keyword search (async)
      description: >-
        Start an asynchronous TikTok keyword search task and return a `task_id`
        immediately. Poll `GET /tiktok/search/{task_id}` for cursor-paginated
        results. Results are retained for ~1 hour.


        Results are returned sorted by `published_at` descending (newest first)
        across pagination, full retrieval, and the signed `download_url`
        payload.


        **parallel_search_slices billing:** by default (`1`), the search runs a
        single paginated query chain and is naturally capped near 120 items by
        TikTok. Setting `parallel_search_slices` to `2..4` runs that many
        concurrent chains in parallel and dedups by video id, lifting the
        effective ceiling. Cost scales linearly: each additional slice consumes
        up to ~1x the residential pages of a single search, so an N-slice
        request bills up to **Nx the residential pages**.
        `parallel_search_slices` is *not* a time filter — use `after_datetime` /
        `before_datetime` for time windows.


        **Usage disclosure:** This endpoint does NOT accept `include_usage`.
        Billing happens in the background worker after the 202 response is sent,
        so there is nothing to disclose at submit time. Pass
        `include_usage=true` on `GET /tiktok/search/{task_id}` instead — the GET
        endpoint replays the final charges once `task_status=completed`.
      operationId: submitTikTokSearch
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - query
              properties:
                query:
                  type: string
                  minLength: 2
                  description: Keyword phrase to search on TikTok.
                  example: ai tools
                max_results:
                  type: integer
                  minimum: 0
                  default: 0
                  description: >-
                    Optional upper bound on results the background task will try
                    to collect. `0` (the default) or omitted means **unlimited**
                    — pagination only stops at TikTok's `has_more=false` or the
                    upstream page cap. With `parallel_search_slices=1` that
                    naturally yields ~89-120 items (TikTok serves ~10 pages of
                    ~12 items per chain); with `parallel_search_slices=4` up to
                    ~480 unique items. A positive integer caps the merged result
                    count. **No hard server-side cap is enforced** — a caller
                    asking for `3000` will be billed per residential page
                    actually fetched (~10 pages per slice naturally) and receive
                    whatever TikTok delivers.
                parallel_search_slices:
                  type: integer
                  minimum: 1
                  maximum: 4
                  default: 1
                  example: 2
                  description: >-
                    How many concurrent paginated query chains to run and dedup
                    by video id. `1` (the default) is a single chain naturally
                    capped near 120 items. `2..4` runs that many additional
                    chains in parallel, lifting the effective ceiling at the
                    cost of up to **~Nx the residential pages** of a single
                    search. Diminishing returns: 2 slices yield ~+43% unique
                    items, 3 slices ~+22%, 4 slices ~+13% on a representative
                    query, so 4 already saturates TikTok's natural ~480-item
                    dedup ceiling for most queries. `parallel_search_slices` is
                    *not* a time filter — use `after_datetime` /
                    `before_datetime` for time windows.
                after_datetime:
                  type: string
                  description: >-
                    Only include videos published on or after this boundary.
                    Accepts YYYY-MM-DD or ISO datetime with timezone.
                before_datetime:
                  type: string
                  description: >-
                    Only include videos published on or before this boundary.
                    Accepts YYYY-MM-DD or ISO datetime with timezone.
                min_likes:
                  type: integer
                  minimum: 0
                max_likes:
                  type: integer
                  minimum: 0
                min_views:
                  type: integer
                  minimum: 0
                max_views:
                  type: integer
                  minimum: 0
      responses:
        '202':
          description: Task accepted and queued.
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    enum:
                      - success
                  data:
                    type: object
                    properties:
                      task_id:
                        type: string
                      task_status:
                        type: string
                        enum:
                          - processing
                      query:
                        type: string
                      max_results:
                        type: integer
                      parallel_search_slices:
                        type: integer
                        minimum: 1
                        maximum: 4
                        description: Echo of the slice count the task was created with.
                      filters:
                        type: object
                      expires_at:
                        type: string
                        format: date-time
                      check_status_url:
                        type: string
                        example: /v1/tiktok/search/550e8400-e29b-41d4-a716-446655440000
                      message:
                        type: string
        '400':
          $ref: '#/components/responses/BadRequest'
        '500':
          $ref: '#/components/responses/InternalServerError'
components:
  responses:
    BadRequest:
      description: Bad request - invalid parameters
      content:
        application/json:
          schema:
            type: object
            properties:
              status:
                type: string
                enum:
                  - error
              error:
                type: string
              message:
                type: string
    InternalServerError:
      description: Internal server error
      content:
        application/json:
          schema:
            type: object
            properties:
              status:
                type: string
                enum:
                  - error
              error:
                type: string
                enum:
                  - internal_server_error
              message:
                type: string
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key
      description: >-
        API key authentication. Include your VidNavigator API key in the
        X-API-Key header.

````