Docs
APIAPI referenceContent

GET /v1/projects/:projectId/content/source-recommendations

List TikTok video and slideshow ids the partner can pass to video-remix or slideshow-remix.

View as Markdown
GET/v1/projects/:projectId/content/source-recommendations
Phase 1stable
Auth
Bearer
Scope
content:read

Returns TikTok ids the partner's end-user can pick from. Two backing modes:

ModeTriggered bySource
Portfolio (default)No keyword query paramPre-discovered posts from the project's content-research pipeline.
Live search?keyword=<string>Real-time TikTok keyword search.

Both modes normalize to the same item shape — partners don't branch on source for rendering. The field is informational only ("from your library" vs "live search results").

Path parameters

  • projectId
    string (uuid)required
    The project.

Query parameters

  • keyword
    stringoptional
    Optional. When omitted, returns portfolio results. When supplied, switches to live search against that term. 1–200 chars.
  • kind
    stringoptional
    Filter by source kind. Default `mixed`.
    One of: video, slideshow, mixed
  • limit
    integeroptional
    Page size. Default 20.
    One of: 1–50
  • cursor
    stringoptional
    Forward-paginate. Currently always `null` in responses; reserved for future use.

Request

terminal
# Portfolio mode (default)
curl "https://api.layers.com/v1/projects/{projectId}/content/source-recommendations?kind=video&limit=20" \
  -H "Authorization: Bearer $LAYERS_API_KEY"

# Live search
curl "https://api.layers.com/v1/projects/{projectId}/content/source-recommendations?keyword=fitness%20app" \
  -H "Authorization: Bearer $LAYERS_API_KEY"
source-recommendations.ts
const res = await fetch(
  `https://api.layers.com/v1/projects/${projectId}/content/source-recommendations?keyword=fitness+app`,
  { headers: { 'Authorization': `Bearer ${process.env.LAYERS_API_KEY}` } },
);
const { items, source } = await res.json();
source_recommendations.py
import os, httpx

r = httpx.get(
    f"https://api.layers.com/v1/projects/{project_id}/content/source-recommendations",
    params={"keyword": "fitness app"},
    headers={"Authorization": f"Bearer {os.environ['LAYERS_API_KEY']}"},
)
items = r.json()["items"]

Responses

200List of TikTok source candidates.
{
  "items": [
    {
      "tiktokId": "7234567890123456789",
      "kind": "video",
      "thumbnailUrl": "https://...",
      "caption": "...",
      "author": { "username": "creator_handle", "displayName": "..." },
      "stats": { "views": 1240000, "likes": 89000, "comments": 4100, "shares": 12000 }
    },
    {
      "tiktokId": "7234567890987654321",
      "kind": "slideshow",
      "thumbnailUrl": "https://...",
      "caption": "...",
      "author": { "username": "creator_handle", "displayName": "..." },
      "stats": { "views": 800000, "likes": 56000, "comments": 1200, "shares": 4400 },
      "imageCount": 7
    }
  ],
  "source": "portfolio",
  "nextCursor": null
}

source is "portfolio" when the response was served from the project's pre-discovered library, "live" when served from a real-time keyword search.

Portfolio mode draws from the project's pre-discovered library (synced posts + previously-generated containers). Fresh projects typically return a small seeded set immediately after creation while the first research sweep runs in the background; the library fills out as posts are synced. Projects that genuinely have no library yet return an empty items array with source: "portfolio" — fall back to a keyword search in that case (or surface the empty state in your UI).

An empty items array always means "nothing matched", never "we could not look". If the upstream source provider is unreachable this endpoint returns PLATFORM_ERROR, so you can treat an empty success as a real answer and retry the error separately.

Errors

CodeWhen
VALIDATIONlimit outside 1–50; kind not in the enum; keyword empty or > 200 chars.
NOT_FOUNDProject id not in this org.
PLATFORM_ERRORThe upstream source provider failed. details.platform is tiktok; details.platformMessage carries the provider's own reason. Retryable with backoff.

See also

On this page