SocialLens
docs

API documentation

Public social media profile data as JSON, one schema for every platform. One key, 100 free requests a day for 14 days, and you only pay for what the API actually delivered.

1. Quickstart

From account to first response in 3 steps.

1
Create an accountAt /login, with e-mail or Google. No card. The trial starts right away: 100 requests a day for 14 days.
2
Generate a keyAt /keys, click "Generate new key". It starts with sk_live_ and is shown only once: copy it immediately.
3
Make the first callPaste the key into the command below and run it. /v1/ping is free and only confirms the key works.
curl
curl "https://api.sociallens.dev/v1/ping" \
  -H "Authorization: Bearer sk_live_YOUR_KEY"

Expected response: {"ok":true,"user_id":123}. From there, swap /v1/ping for the endpoint you need.

curl
curl "https://api.sociallens.dev/v1/profile?username=exemplo&platform=tiktok" \
  -H "Authorization: Bearer sk_live_YOUR_KEY"

2. Authentication

Every call to /v1/* carries the key in the Authorization header, Bearer format. The key never goes in the URL, so it never leaks into proxy logs or browser history.

header
Authorization: Bearer sk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Getting a key

Signed in, open /keys and generate a key with a name (e.g. "production", "staging"). You can have up to 10 active keys at once, one per environment or app. We store only the hash: a lost key cannot be recovered, only replaced.

Revoking

Same screen, "Revoke". The key stops working instantly and any call using it gets 401 invalid_token. Revoking does not affect your credits or your other keys.

A missing, wrong or revoked key always gets the same body:

401
{ "error": "invalid_token", "message": "API key missing, invalid or revoked." }

3. Endpoints

Base URL: https://api.sociallens.dev. Every response is UTF-8 JSON. The schema is the same for all platforms: change platform and the fields stay the same.

Public profile

GET/v1/profile1 credit per request

Reads a user's public profile and returns normalized counters and identity.

ParameterTypeDescription
usernamerequiredstringPublic username. A leading @ is accepted and ignored. Letters, digits, dot, _ and -, up to 80 characters.
platformrequiredstringOne of: tiktok, instagram, youtube.

Example request

curl
curl "https://api.sociallens.dev/v1/profile?username=exemplo&platform=tiktok" \
  -H "Authorization: Bearer sk_live_YOUR_KEY"

Example response 200

json
{
  "username":   "exemplo",
  "platform":   "tiktok",
  "nickname":   "Exemplo Oficial",
  "verified":   true,
  "followers":  1284310,
  "following":  212,
  "likes":      48210933,
  "videos":     431,
  "bio":        "Content creator. Contact in bio.",
  "avatar":     "https://.../avatar.jpg",
  "fetched_at": "2026-11-07T12:02:15Z",
  "credits":    { "source": "paid", "charged": 1, "balance": 7999 }
}

Response fields

FieldTypeMeaning
usernamestringUsername as the platform shows it, without @.
platformstringPlatform queried, same as the parameter sent.
nicknamestring | nullDisplay name. null if the platform has none.
verifiedbooleanVerified by the platform.
followersintegerFollowers (subscribers on YouTube). Always an integer, never "1.2M".
followingintegerHow many accounts the profile follows. 0 when the platform does not expose it.
likesintegerTotal likes received (TikTok) or total views (YouTube). 0 when unavailable.
videosintegerNumber of publications: videos, posts or uploads depending on the platform.
biostring | nullBio text, unformatted.
avatarstring | nullProfile picture URL. May expire; download it if you need to keep it.
fetched_atstringWhen the data was read, ISO 8601 UTC. We never serve cache without saying so.
credits.sourcestringpaid (taken from paid balance) or trial (taken from the daily trial quota).
credits.chargedintegerCredits charged for this call.
credits.trialobjectOnly when source is trial: used_today, limit_per_day, resets_at, days_left.
credits.balanceintegerYour balance after this call, so you can monitor without an extra request.

During the beta the response may include an extra informational note field. Ignore it in your parser; it goes away in the stable version.

Followers of a profile (paginated)

GET/v1/followers1 credit per page

Lists a profile's public followers, one page per call. For the next page, repeat the call with the previous next_cursor. Each page costs 1 credit regardless of how many followers it contains.

ParameterTypeDescription
usernamerequiredstringPublic username of the profile. @ accepted and ignored.
platformrequiredstringOne of: tiktok, instagram, youtube.
cursoroptionalstringThe next_cursor from the previous page. Omit on the first call.
curl
curl "https://api.sociallens.dev/v1/followers?username=exemplo&platform=tiktok" \
  -H "Authorization: Bearer sk_live_YOUR_KEY"
json · 200
{
  "username":    "exemplo",
  "platform":    "tiktok",
  "followers": [
    { "username": "exemplo_um",   "nickname": "Exemplo Um",   "verified": false, "avatar": "https://..." },
    { "username": "exemplo_dois", "nickname": "Exemplo Dois", "verified": true,  "avatar": "https://..." }
  ],
  "next_cursor": "c2VndWludGU6MjA",
  "fetched_at":  "2026-11-07T12:02:15Z",
  "credits":     { "source": "paid", "charged": 1, "balance": 7998 }
}
FieldTypeMeaning
username, platformstringThe profile queried, same as sent.
followers[]arrayFollowers on this page. Each item has username, nickname (string or null), verified (boolean) and avatar (URL or null).
next_cursorstring | nullPass it back as cursor for the next page. null when the list is over.
fetched_at, creditsSame as /v1/profile.

Fake follower estimate

GET/v1/bot-estimate5 credits per request

Estimates the percentage of fake or bot followers of a profile from a sample of its followers. Costs more than a simple read because it analyzes several profiles per call. Ideal for vetting an influencer before a campaign, or for audit tools.

ParameterTypeDescription
usernamerequiredstringPublic username of the profile.
platformrequiredstringOne of: tiktok, instagram, youtube.
curl
curl "https://api.sociallens.dev/v1/bot-estimate?username=exemplo&platform=tiktok" \
  -H "Authorization: Bearer sk_live_YOUR_KEY"
json · 200
{
  "username":       "exemplo",
  "platform":       "tiktok",
  "bot_score":      23,
  "classification": "low",
  "sample_size":    200,
  "fetched_at":     "2026-11-07T12:02:15Z",
  "credits":        { "source": "paid", "charged": 5, "balance": 7993 }
}
FieldTypeMeaning
bot_scoreinteger 0..100Estimated percentage of fake or bot followers.
classificationstringlow (below 30), medium (30 to 59) or high (60 or more).
sample_sizeintegerHow many followers were analyzed to reach the score.
fetched_at, creditsSame as /v1/profile.

Ping (key check)

GET/v1/pingfree

Consumes no credit and does not count toward the data rate limit. Returns {"ok":true,"user_id":N} when the key is valid.

Coming next

  • GET /v1/posts: latest posts of a profile with views, likes and comments.

4. Credits and cost

  • Cost per endpoint, shown next to each one on this page and returned in credits.charged: /v1/profile 1, /v1/followers 1 per page, /v1/bot-estimate 5. On the trial, each call deducts its cost from the daily quota.
  • Free trial on sign-up: 100 requests a day for 14 days, no card. The daily counter resets at midnight UTC (resets_at gives the exact time). Over the day: 402 daily_trial_limit. After the 14 days: 402 trial_expired.
  • Paid credits never expire and have no daily limit. When you have a paid balance it is used first; the trial only kicks in when the paid balance is zero. Packs: Starter US$ 19 = 8,000 · Pro US$ 79 = 40,000 · Scale US$ 299 = 180,000. Buy at /credits; details at /pricing.
  • The credits block of every response says where the request came from (source: "paid" or "trial") and, on the trial, how much of the day is used.
You never pay for failures. If the source is down or blocks the read, the API answers 502 source_unavailable and the charged credit is refunded automatically in the same transaction. Input errors (400), invalid key (401), no balance (402) and rate limiting (429) charge nothing either. Only a 200 is charged.
Never charged400, 401, 402, 429, 502. Any response that is not a 200.
ChargedOnly the 200, exactly the value in credits.charged.

Every refund is recorded in your statement with the same reference as the charge, so it can be audited.

5. Rate limit

Each key is limited to 60 requests per minute on data endpoints. The limit is per key, not per account: two keys, two limits.

Over the limit, the API answers 429 rate_limited, charges nothing, and tells you how long to wait:

429
HTTP/1.1 429 Too Many Requests
Retry-After: 41

{
  "error": "rate_limited",
  "message": "Too many requests. Wait and try again.",
  "retry_after": 41,
  "limit_per_min": 60
}

The Retry-After header and the retry_after field give the seconds until the window opens again. Sleep that long and retry; no exponential backoff needed. Need more volume? Reach us at /contact.

6. Errors

Every error has the same shape, always JSON: {"error": "<code>", "message": "..."}. The code is stable (use it in your switch); the message is for humans and may change.

HTTPerrorWhen it happensCharged?
400bad_requestMissing or invalid parameter (empty username, platform not in the list) or unknown endpoint.No
401invalid_tokenAuthorization header missing, wrong or revoked key.No
402no_creditsInsufficient paid balance and no trial. Includes current balance.No
402daily_trial_limitHit the 100 requests of the day on the trial. Includes resets_at (midnight UTC). Buying a pack unblocks it immediately.No
402trial_expiredThe 14 trial days are over and there is no paid balance. Upgrade at /credits.No
429rate_limitedMore than 60 req/min on this key. Includes retry_after.No
502source_unavailableThe platform did not respond or blocked the read. Credit refunded. Retry in a few seconds.No (refunded)

Non-existent or private profiles are being defined together with the reading engine and will get their own code before the stable version. Until then they fall under source_unavailable, never charged.

7. Code examples

The same call in three languages. Replace sk_live_YOUR_KEY with your key. In production, read the key from an environment variable; do not hardcode it.

bash
curl "https://api.sociallens.dev/v1/profile?username=exemplo&platform=tiktok" \
  -H "Authorization: Bearer sk_live_YOUR_KEY"
python · requests
import os, time, requests

API_KEY = os.environ.get("SOCIALDATA_KEY", "sk_live_YOUR_KEY")
BASE = "https://api.sociallens.dev"

def profile(username, platform="tiktok"):
    r = requests.get(
        f"{BASE}/v1/profile",
        params={"username": username, "platform": platform},
        headers={"Authorization": f"Bearer {API_KEY}"},
        timeout=15,
    )
    if r.status_code == 429:
        time.sleep(int(r.headers.get("Retry-After", 5)))
        return profile(username, platform)
    data = r.json()
    if r.status_code != 200:
        raise RuntimeError(f"{data['error']}: {data['message']}")
    return data

p = profile("exemplo")
print(p["followers"], "followers · balance", p["credits"]["balance"])
node · fetch
const API_KEY = process.env.SOCIALDATA_KEY ?? "sk_live_YOUR_KEY";
const BASE = "https://api.sociallens.dev";

async function profile(username, platform = "tiktok") {
  const url = `${BASE}/v1/profile?` + new URLSearchParams({ username, platform });
  const res = await fetch(url, { headers: { Authorization: `Bearer ${API_KEY}` } });
  if (res.status === 429) {
    const wait = Number(res.headers.get("Retry-After") ?? 5);
    await new Promise(r => setTimeout(r, wait * 1000));
    return profile(username, platform);
  }
  const data = await res.json();
  if (!res.ok) throw new Error(`${data.error}: ${data.message}`);
  return data;
}

const p = await profile("exemplo");
console.log(p.followers, "followers · balance", p.credits.balance);