# LINGTU AI OpenAPI

- OpenAPI: 3.1.2
- API version: 1.2.0
- Last updated: 2026-08-11
- Base URL: `https://api.ailingtu.com`
- Authentication: `x-api-key: <YOUR_API_KEY>`
- Success condition: HTTP 2xx and response `code === 0`

Machine-readable descriptions: [JSON](/openapi.json) · [YAML](/openapi.yaml) · [operation index](/openapi/operations/index.json)

API keys must remain on the server and must not be included in browser code, logs, or shared files.

## Publishing workflow

1. Query an authorized creator account.
2. Query showcase products with the account `id`.
3. Create a presigned upload, PUT new files to object storage, and confirm them.
4. Create a publishing task with the account `creatorId` and uploaded `fileId`.

## AI generation workflow

See the focused [AI generation workflow](/openapi/workflows/ai-generation.md).

1. Create an image or video schedule with `POST /v1/ai/schedule/create`.
2. Save the returned `scheduleId`.
3. Poll `GET /v1/ai/task/listByScheduleId?scheduleId=...` until the requested tasks complete or explicitly fail.
4. Read the generated image or video URL from the completed task result.

## GET /v1/creatorAccount/pageList

Operation ID: `listCreatorAccounts`

List authorized creator accounts

Returns authorized creator accounts and publishing permissions. Use `id` for product queries and `creatorId` when creating publishing tasks.

| Field | Location | Type | Required | Description |
|---|---|---|---:|---|
| `pageSize` | query | integer | yes | Items per page. |
| `pageNumber` | query | integer | yes | Page number starting at 1. |
| `valid` | query | boolean | no | Return valid authorizations only. |
| `authSource` | query | `TIKTOK_SHOP_CREATOR` \| `TIKTOK_LOGIN_KIT` | no | Authorization source. Use TIKTOK_SHOP_CREATOR for commerce publishing. |
| `usernames` | query | string[] | no | TikTok usernames. Repeat the query parameter for multiple values. |
| `selectionRegion` | query | string | no | Target TikTok Shop region. |
| `hasPhotoPermission` | query | boolean | no | Return accounts with shoppable photo permission only. |

### Success response

```json
{
  "code": 0,
  "data": {
    "list": [
      {
        "id": 12345,
        "creatorId": "2077242233106595840",
        "username": "shop_creator",
        "authSource": "TIKTOK_SHOP_CREATOR",
        "oauthRegion": "USA",
        "registerRegion": "US",
        "selectionRegion": "US",
        "targetMarket": "US",
        "valid": true,
        "tagNames": [
          "top-tier"
        ],
        "permissions": [
          "VIDEO_SHOPPABLE_PERMISSION",
          "PHOTO_SHOPPABLE_PERMISSION_PRODUCT"
        ]
      }
    ],
    "total": 1,
    "pageNumber": 1,
    "pageSize": 200,
    "totalPages": 1
  },
  "message": "success"
}
```

### Important notes

- Photo posts require PHOTO_SHOPPABLE_PERMISSION_PRODUCT in permissions.

### Errors

| HTTP | Meaning |
|---:|---|
| 400 | Invalid request parameters or body. |
| 401 | The API key is missing or invalid. |
| 403 | The API key does not have permission for this operation. |
| 429 | Too many requests. Retry with exponential backoff. |
| 500 | Unexpected server error. Retry transient failures with exponential backoff. |


## GET /v1/creator/tiktokshop/product/listByShowcase

Operation ID: `listTikTokShowcaseProducts`

List creator showcase products

Lists products in a creator showcase. Use `SHOWCASE` as the product source when creating a publishing task.

| Field | Location | Type | Required | Description |
|---|---|---|---:|---|
| `id` | query | integer | yes | Creator account table ID. |
| `origin` | query | `TIKTOK` | yes | Product platform origin. |
| `pageSize` | query | integer | yes | Items per page. |
| `pageToken` | query | string | no | Pagination token from the previous response. |

### Success response

```json
{
  "code": 0,
  "data": {
    "products": [
      {
        "id": "1732280564607717841",
        "title": "Summer Vibes Cord",
        "price": {
          "amount": "19.99",
          "currency": "USD"
        },
        "images": [
          {
            "url": "https://cdn.example.com/product.jpg",
            "width": 800,
            "height": 800
          }
        ]
      }
    ],
    "nextPageToken": "",
    "totalCount": 1
  },
  "message": "success"
}
```

### Important notes

- This endpoint does not accept titleKeyword. Filter by title on the client when needed.

### Errors

| HTTP | Meaning |
|---:|---|
| 400 | Invalid request parameters or body. |
| 401 | The API key is missing or invalid. |
| 403 | The API key does not have permission for this operation. |
| 429 | Too many requests. Retry with exponential backoff. |
| 500 | Unexpected server error. Retry transient failures with exponential backoff. |


## POST /v1/creator/tiktokshop/product/addToShowcase

Operation ID: `addTikTokShowcaseProducts`

Add products to a creator showcase

Adds TikTok Shop products to an authorized creator showcase. Use PRODUCT_ID with 1–20 productIds, or PRODUCT_LINK with productLink. A response with code 0 can still contain data.errors when some products failed to be added. The creator authorization must include creator.showcase.write and creator.video.write.

| Field | Location | Type | Required | Description |
|---|---|---|---:|---|
| `id` | body | integer | yes | Creator account id |
| `addType` | body | PRODUCT_ID \| PRODUCT_LINK | yes | How products are identified |
| `productIds` | body | string[] | conditional | Required for PRODUCT_ID; 1–20 product IDs |
| `productLink` | body | string(uri) | conditional | Required for PRODUCT_LINK |

### Request example: Add by product IDs

```json
{
  "id": 12345,
  "addType": "PRODUCT_ID",
  "productIds": [
    "1732280564607717841",
    "1732280564607717842"
  ]
}
```

### Request example: Add by product link

```json
{
  "id": 12345,
  "addType": "PRODUCT_LINK",
  "productLink": "https://shop.tiktok.com/view/product/1732280564607717841"
}
```

### Success response: All products added

```json
{
  "code": 0,
  "data": {},
  "message": "success",
  "timestamp": 1786406400000
}
```

### Success response: Some products failed

```json
{
  "code": 0,
  "data": {
    "errors": [
      {
        "code": 16001001,
        "message": "Product is unavailable for this creator",
        "detail": {
          "productId": "1732280564607717842"
        }
      }
    ]
  },
  "message": "success",
  "timestamp": 1786406400000
}
```

### Success response: Creator authorization expired

```json
{
  "code": 40101,
  "data": {},
  "message": "授权过期，请重新授权",
  "timestamp": 1786406400000
}
```

### Important notes

- Required scopes: creator.showcase.write and creator.video.write.
- A request can contain at most 20 product IDs.
- Check data.errors even when code is 0; entries identify products that failed.
- An expired creator authorization returns the business error “授权过期，请重新授权”.

### Errors

| HTTP | Meaning |
|---:|---|
| 400 | Invalid request parameters or body. |
| 401 | The API key is missing or invalid. |
| 403 | The API key does not have permission for this operation. |
| 429 | Too many requests. Retry with exponential backoff. |
| 500 | Unexpected server error. Retry transient failures with exponential backoff. |


## POST /v1/file/presign

Operation ID: `createFileUpload`

Create a presigned file upload

Returns a file ID and a presigned object-storage URL. When `isNew` is false, skip PUT and confirmation. When `isNew` is true, PUT the raw file bytes to `uploadUrl` with the same Content-Type, without the x-api-key header, then confirm the upload.

| Field | Location | Type | Required | Description |
|---|---|---|---:|---|
| `fileName` | body | string | yes | File name including extension |
| `contentType` | body | string | yes | File MIME type |
| `size` | body | integer | yes | File size in bytes |
| `hash` | body | string | yes | SHA-256 of the UTF-8 encoded lowercase hex representation of the file bytes |

### Request example

```json
{
  "fileName": "video.mp4",
  "contentType": "video/mp4",
  "size": 12345678,
  "hash": "3786a02b..."
}
```

### Success response

```json
{
  "code": 0,
  "data": {
    "fileId": 591,
    "uploadUrl": "https://object-storage.example.com/presigned-url",
    "url": "https://cdn.ailingtu.com/media/video.mp4",
    "isNew": true,
    "expiresAt": "2026-07-29T12:00:00Z"
  },
  "message": "success"
}
```

### Important notes

- When isNew is true, PUT the raw file to uploadUrl with the same Content-Type, then call confirm.
- Do not send x-api-key to the object-storage PUT URL.

### Errors

| HTTP | Meaning |
|---:|---|
| 400 | Invalid request parameters or body. |
| 401 | The API key is missing or invalid. |
| 403 | The API key does not have permission for this operation. |
| 429 | Too many requests. Retry with exponential backoff. |
| 500 | Unexpected server error. Retry transient failures with exponential backoff. |


## POST /v1/file/confirm

Operation ID: `confirmFileUpload`

Confirm a file upload

Call only after a new file is successfully uploaded to its presigned URL. Deduplicated files do not require confirmation.

| Field | Location | Type | Required | Description |
|---|---|---|---:|---|
| `fileId` | body | integer \| string | yes | File ID returned by the presign endpoint |

### Request example

```json
{
  "fileId": 591
}
```

### Success response

```json
{
  "code": 0,
  "data": {
    "fileId": 591,
    "confirmed": true
  },
  "message": "success"
}
```

### Errors

| HTTP | Meaning |
|---:|---|
| 400 | Invalid request parameters or body. |
| 401 | The API key is missing or invalid. |
| 403 | The API key does not have permission for this operation. |
| 429 | Too many requests. Retry with exponential backoff. |
| 500 | Unexpected server error. Retry transient failures with exponential backoff. |


## POST /v1/creator/post/create

Operation ID: `createCreatorPost`

Create a creator publishing task

Creates a TikTok Shop commerce video or photo publishing task. A successful response means the task was accepted, not that TikTok publishing has completed.

| Field | Location | Type | Required | Description |
|---|---|---|---:|---|
| `businessId` | body | string | yes | Video fileId; first image fileId for photo posts |
| `businessType` | body | FILE | yes | Use FILE for uploaded media |
| `creatorId` | body | string | yes | creatorId returned by the creator endpoint |
| `title` | body | string | yes | Post caption, up to 4,000 characters |
| `platform` | body | TIKTOK_SHOP | yes | Use TIKTOK_SHOP for commerce posts |
| `mediaType` | body | VIDEO \| PHOTO | yes | Explicitly select video or photo |
| `scheduledAt` | body | integer | no | Unix epoch in milliseconds |
| `scheduledTz` | body | string | no | IANA timezone |
| `oauthRegion` | body | string | no | Creator OAuth authorization region |
| `coverFileId` | body | integer \| string | no | Custom video cover file ID; pass together with tiktokShop.coverUri and omit for photo posts |
| `tiktokShop` | body | object | conditional | Required for VIDEO; contains product, cover, pre-check, music, and AI label options |
| `tiktokShop.preCheck` | body | boolean | no | Whether to submit a pre-check before publishing; defaults to false |
| `tiktokShop.isAiGenerated` | body | boolean | no | Whether to label the video as AI-generated; TikTok adds an AI-generated label when true |
| `tiktokShop.coverUri` | body | string | no | URI returned by the cover upload endpoint; pass coverFileId with it |
| `tiktokShop.coverTimestampMs` | body | integer | no | Video timestamp in milliseconds to use as the cover frame; omit when coverUri is present |
| `tiktokShop.musicInfo` | body | object | no | Video background music; omit when no music is needed |
| `tiktokShop.musicInfo.id` | body | string | conditional | Music ID, required when musicInfo is provided |
| `tiktokShop.productInfo.productId` | body | string | conditional | Required for VIDEO; product ID returned by the product endpoint |
| `tiktokShop.productInfo.title` | body | string | conditional | Required for VIDEO; product anchor title, up to 30 characters |
| `tiktokShop.productInfo.source` | body | SHOP \| SHOWCASE | conditional | Required for VIDEO; SHOP for shop products or SHOWCASE for showcase products |
| `tiktokShopPhoto` | body | object | conditional | Required for PHOTO |
| `tiktokShopPhoto.postType` | body | MULTI_PHOTO_ONE_ANCHOR | conditional | Use MULTI_PHOTO_ONE_ANCHOR for PHOTO |
| `tiktokShopPhoto.businessIds` | body | string[] | conditional | Required for PHOTO; 1–15 image fileIds in final display order |
| `tiktokShopPhoto.productLinks[0].productId` | body | string | conditional | Required for PHOTO; product ID for the single product anchor |
| `tiktokShopPhoto.productLinks[0].title` | body | string | conditional | Required for PHOTO; product anchor title, up to 30 characters |
| `tiktokShopPhoto.productLinks[0].source` | body | SHOP \| SHOWCASE | conditional | Required for PHOTO; product source |
| `tiktokShopPhoto.musicInfo` | body | object | no | Photo post background music; omit when no music is needed |
| `tiktokShopPhoto.musicInfo.id` | body | string | conditional | Music ID, required when musicInfo is provided |

### Request example: TikTok Shop commerce video

```json
{
  "businessId": "591",
  "businessType": "FILE",
  "creatorId": "2077242233106595840",
  "title": "Summer Sale 2026 #summer",
  "platform": "TIKTOK_SHOP",
  "mediaType": "VIDEO",
  "scheduledAt": 1784896665989,
  "scheduledTz": "America/New_York",
  "oauthRegion": "USA",
  "tiktokShop": {
    "preCheck": false,
    "isAiGenerated": true,
    "coverTimestampMs": 1500,
    "musicInfo": {
      "id": "7567668059796720391",
      "title": "original sound",
      "author": "Ivan",
      "duration": "15"
    },
    "productInfo": {
      "productId": "1732280564607717841",
      "title": "Summer Vibes Cord",
      "source": "SHOP"
    }
  }
}
```

### Request example: TikTok Shop commerce photo post

```json
{
  "businessId": "591",
  "businessType": "FILE",
  "creatorId": "2077242233106595840",
  "title": "Summer Sale 2026 #summer",
  "platform": "TIKTOK_SHOP",
  "mediaType": "PHOTO",
  "scheduledAt": 1784896665989,
  "scheduledTz": "America/New_York",
  "oauthRegion": "USA",
  "tiktokShopPhoto": {
    "postType": "MULTI_PHOTO_ONE_ANCHOR",
    "businessIds": [
      "591",
      "592"
    ],
    "productLinks": [
      {
        "productId": "1732280564607717841",
        "title": "Summer Vibes Cord",
        "source": "SHOP"
      }
    ],
    "musicInfo": {
      "id": "7567668059796720391",
      "title": "original sound",
      "author": "Ivan",
      "duration": "15"
    }
  }
}
```

### Success response

```json
{
  "code": 0,
  "data": {
    "id": 100,
    "postId": "post_xxx",
    "platform": "TIKTOK_SHOP",
    "title": "Summer Sale 2026 #summer",
    "videoUrl": "https://cdn.ailingtu.com/media/video.mp4",
    "status": "SCHEDULED"
  },
  "message": "success"
}
```

### Important notes

- For a video cover, use tiktokShop.coverTimestampMs for a frame or pass coverFileId together with tiktokShop.coverUri for a custom cover; do not mix the two methods.
- Photo posts support 1–15 images and one product; businessId must equal businessIds[0], and the first image is the cover.
- Persist postId and status, then verify the final state in publishing records.

### Errors

| HTTP | Meaning |
|---:|---|
| 400 | Invalid request parameters or body. |
| 401 | The API key is missing or invalid. |
| 403 | The API key does not have permission for this operation. |
| 429 | Too many requests. Retry with exponential backoff. |
| 500 | Unexpected server error. Retry transient failures with exponential backoff. |


## POST /v1/ai/schedule/create

Operation ID: `createAiGenerationSchedule`

Create an AI media generation schedule

Creates one or more AI image or video generation tasks. Use the returned scheduleId to query task status and generated assets. Keep polling the same schedule until every requested output succeeds or explicitly fails.

| Field | Location | Type | Required | Description |
|---|---|---|---:|---|
| `taskId` | body | string | no | Caller-generated task identifier; an 8-character lowercase alphanumeric value is recommended |
| `type` | body | IMAGE_GENERATION \| VIDEO_GENERATION | yes | Media generation type |
| `params.prompt` | body | string | yes | Image or video generation prompt |
| `params.model` | body | gpt-image-2 \| nano-banana-2 \| nano-banana-2-2k \| nano-banana-2-4k \| seedream5.0-lite \| gemini-omni-video \| veo3.1-lite-extend \| veo3.1-extend \| grok-imagine-1.5 \| seedance2.0-mini \| seedance2.0 \| seedance2.0-fast | yes | Select one of the image or video models listed below, matching type |
| `params.aspectRatio` | body | string | conditional | Required for images, for example 1:1 or 9:16 |
| `params.seconds` | body | integer | conditional | Video duration; allowed values depend on the model |
| `params.size` | body | string | conditional | Video dimensions, for example 720x1280 |
| `params.inputReference` | body | string(uri) | no | One remote reference image URL, primarily for video generation |
| `params.inputReferences` | body | string(uri)[] | no | Ordered remote reference image URLs; data URLs are not supported |
| `params.watermark` | body | boolean | no | Whether to add a video watermark; defaults to false |
| `nums` | body | integer | yes | Number of outputs; use 1 unless multiple results are needed |
| `businessId` | body | string | no | Optional related business object ID |
| `businessType` | body | MERCHANT_SKU \| AI_PURCHASE_TASK | no | Related business object type |
| `promptId` | body | string | no | Saved prompt ID |
| `execAt` | body | string(date-time) | no | ISO 8601 execution time; omit to create immediately |
| `name` | body | string | no | Display name for the generation schedule |

### Request example: Generate an image

```json
{
  "taskId": "img8a1b2",
  "type": "IMAGE_GENERATION",
  "params": {
    "prompt": "A clean product hero image on a bright studio background",
    "model": "gpt-image-2",
    "aspectRatio": "1:1",
    "inputReferences": [
      "https://static.ailingtu.com/ai-images/product-reference.jpg"
    ]
  },
  "nums": 1,
  "name": "Product hero image"
}
```

### Request example: Generate a video

```json
{
  "taskId": "vid8c3d4",
  "type": "VIDEO_GENERATION",
  "params": {
    "prompt": "A clean 10-second product reveal video with a slow camera push-in",
    "model": "gemini-omni-video",
    "seconds": 10,
    "size": "720x1280",
    "inputReferences": [
      "https://static.ailingtu.com/ai-images/product-reference.jpg"
    ],
    "watermark": false
  },
  "nums": 1,
  "name": "Product reveal video"
}
```

### Success response

```json
{
  "code": 0,
  "data": {
    "scheduleId": "schedule_01k1example",
    "taskIds": [
      "task_01k1example"
    ]
  },
  "message": "success"
}
```

### Important notes

- Image models: gpt-image-2, nano-banana-2, nano-banana-2-2k, nano-banana-2-4k, seedream5.0-lite.
- Video models: gemini-omni-video, veo3.1-lite-extend, veo3.1-extend, grok-imagine-1.5, seedance2.0-mini, seedance2.0, seedance2.0-fast.
- Video durations: gemini-omni-video supports 6/8/10s; veo3.1-lite-extend and veo3.1-extend are fixed at 8s; grok-imagine-1.5 supports 6/10/15/20/25/30s; seedance2.0-mini, seedance2.0, and seedance2.0-fast support 4/8/10/12/15s.
- For images, use IMAGE_GENERATION with params.aspectRatio. For videos, use VIDEO_GENERATION with params.seconds and params.size.
- References must be accessible http/https URLs. Upload local files before passing their URLs.
- scheduleId and taskId are different. Query the same scheduleId after creation and do not recreate a task only because polling was interrupted.

### Related operations

- [GET /v1/ai/task/listByScheduleId](/openapi/operations/listAiTasksByScheduleId.md)

### Errors

| HTTP | Meaning |
|---:|---|
| 400 | Invalid request parameters or body. |
| 401 | The API key is missing or invalid. |
| 403 | The API key does not have permission for this operation. |
| 429 | Too many requests. Retry with exponential backoff. |
| 500 | Unexpected server error. Retry transient failures with exponential backoff. |


## GET /v1/ai/task/listByScheduleId

Operation ID: `listAiTasksByScheduleId`

List AI generation tasks by schedule ID

Returns AI image or video generation tasks for one schedule. Poll this endpoint until the requested tasks reach a terminal status and expose their generated asset URLs.

| Field | Location | Type | Required | Description |
|---|---|---|---:|---|
| `scheduleId` | query | string | yes | Schedule ID returned by the schedule creation endpoint. |

### Success response

```json
{
  "code": 0,
  "data": {
    "list": [
      {
        "taskId": "task_01k1example",
        "scheduleId": "schedule_01k1example",
        "type": "VIDEO_GENERATION",
        "status": "COMPLETED",
        "model": "gemini-omni-video",
        "params": {
          "prompt": "A clean 10-second product reveal video with a slow camera push-in",
          "model": "gemini-omni-video",
          "seconds": 10,
          "size": "720x1280"
        },
        "result": {
          "url": "https://static.ailingtu.com/ai-videos/result.mp4",
          "thumbnailUrl": "https://static.ailingtu.com/ai-images/cover.jpg"
        },
        "customResult": {
          "videoUrl": "https://static.ailingtu.com/ai-videos/result.mp4",
          "coverUrl": "https://static.ailingtu.com/ai-images/cover.jpg"
        },
        "createdAt": "2026-08-10T10:00:00Z"
      }
    ],
    "total": 1,
    "pageNumber": 1,
    "pageSize": 20,
    "totalPages": 1
  },
  "message": "success"
}
```

### Important notes

- Waiting states include WAITING_SUBMIT, SUBMITTING, PENDING, and PROCESSING. COMPLETED is successful.
- Retry only after an explicit failure, cancellation, or expiration. A network or polling-process error does not mean generation failed.
- For videos, prefer customResult.videoUrl or result.url. Images usually use result.url or resultUrl.

### Related operations

- [POST /v1/ai/schedule/create](/openapi/operations/createAiGenerationSchedule.md)

### Errors

| HTTP | Meaning |
|---:|---|
| 400 | Invalid request parameters or body. |
| 401 | The API key is missing or invalid. |
| 403 | The API key does not have permission for this operation. |
| 429 | Too many requests. Retry with exponential backoff. |
| 500 | Unexpected server error. Retry transient failures with exponential backoff. |


## POST /v1/material/fetch

Operation ID: `fetchPublicVideoData`

Fetch public video data

Fetches public video views and engagement metrics. Supported sources include TikTok, Instagram, Douyin, Xiaohongshu, WeChat Channels, and YouTube.

| Field | Location | Type | Required | Description |
|---|---|---|---:|---|
| `videoUrl` | body | string(uri) | yes | Public http/https URL of the content |

### Request example

```json
{
  "videoUrl": "https://www.tiktok.com/@creator/video/7123456789012345678"
}
```

### Success response

```json
{
  "code": 0,
  "data": {
    "videoId": "7624922739500993822",
    "uniqueId": "creator",
    "playCount": 2109422,
    "diggCount": 143027,
    "commentCount": 1320,
    "shareCount": 36150,
    "collectCount": 17710,
    "coverUrl": "https://cdn.example.com/cover.jpg",
    "videoDesc": "caption #tag",
    "releaseAt": 1775315687
  },
  "message": "success"
}
```

### Errors

| HTTP | Meaning |
|---:|---|
| 400 | Invalid request parameters or body. |
| 401 | The API key is missing or invalid. |
| 403 | The API key does not have permission for this operation. |
| 404 | The public work does not exist or has been deleted. |
| 429 | Too many requests. Retry with exponential backoff. |
| 500 | Unexpected server error. Retry transient failures with exponential backoff. |


## Retry guidance

- Retry network timeouts, HTTP 408, 429, and 5xx responses with exponential backoff.
- Do not blindly retry parameter, permission, or authorization errors.
- Before retrying an object-storage PUT, confirm that the presigned URL is still valid.
- If creating a publishing task times out, check publishing records before creating another task to avoid duplicates.
