GET /v1/profile/posts

A page of a profile's recent posts, newest first, with an opaque cursor. One page is one charge.

This is the original generic endpoint, and it is still supported. It returns one normalized shape across every platform. The product now leads with named APIs (/v1/tiktok/posts and /v1/instagram/posts), which answer in each platform’s own vocabulary. Nothing here is deprecated; the named APIs are simply what the rest of the docs use.

Request

GET /v1/profile/posts
Authorization: Bearer sv_live_…
Parameter Type Required Notes
url string one of Profile URL
platform + username string one of Alternative to url
cursor string no From next_cursor of the previous page
limit int no 1–50, default 20

Cost: per page, regardless of limit: 1 credit on TikTok and X, 4 on Instagram. Fetching 50 in one page costs the same as fetching 10, so use a larger limit when you know you want the volume.

Example

curl https://api.sourcevine.io/v1/profile/posts \
  -H "Authorization: Bearer $SOURCEVINE_API_KEY" \
  --data-urlencode "url=https://www.tiktok.com/@atlas.makes" \
  --data-urlencode "limit=20" -G
{
  "items": [
    {
      "id": "sd_post_1c7be04a92f3d558",
      "platform": "tiktok",
      "resource_type": "post",
      "platform_resource_id": "7042118893001",
      "author": { "platform_resource_id": "6789432100", "username": "atlas.makes" },
      "url": "https://www.tiktok.com/@atlas.makes/video/7042118893001",
      "caption": "the jig that finally worked",
      "media_type": "video",
      "published_at": "2026-08-20T09:00:00Z",
      "metrics": {
        "views": 412000, "likes": 38400, "comments": 921,
        "shares": 2140, "saves": 6630
      }
    }
  ],
  "next_cursor": "eyJvIjoyMH0",
  "availability": { "status": "available", "reason": null },
  "fetched_at": "2026-08-27T09:41:02Z",
  "cache_age_seconds": 0,
  "freshness": "fresh"
}

Paginating

next_cursor is opaque. Do not parse it, construct it, or store it long term. It is null on the last page.

cursor, posts = None, []
while True:
    r = client.get("/v1/profile/posts",
                   params={"url": url, "limit": 50, "cursor": cursor}).json()
    posts += r["items"]
    cursor = r.get("next_cursor")
    if not cursor:
        break

Each iteration is a separate billable page. A profile with 600 posts is 12 pages at limit=50, so 24 credits. Plan for that before you loop over a list of creators.

Notes

  • Newest first, always.
  • Pinned posts may appear out of chronological order on platforms that support pinning. Sort by published_at if strict ordering matters.
  • Depth varies by platform. The available history depends on the platform and resource. Sourcevine returns the history available for that lookup.
  • A cursor can go stale. If the profile posts while you are paginating, a later page may shift. For exact snapshots, record fetched_at per page.

Last updated 4 October 2026