Normalized schema

Every field you can receive, what it means, and what is deliberately absent. Same keys on every platform, with explicit nulls where a platform reports nothing.

The shape

Every object carries identity, then payload, then provenance. Identity and provenance are identical across platforms and resource types; only the middle changes.

{
  "id": "sd_prof_3f9a2c81b4e07d15",
  "platform": "tiktok",
  "resource_type": "profile",
  "platform_resource_id": "7042118893001",

  "…": "resource-specific fields",

  "availability": { "status": "available", "reason": null },
  "source_timestamp": "2026-08-27T09:41:02Z",
  "fetched_at": "2026-08-27T09:41:44Z",
  "cache_age_seconds": 312,
  "freshness": "cached"
}

id is ours and stable: it is derived from the platform and the platform’s own id, so it survives us changing anything underneath. platform_resource_id is the platform’s, exposed so you can always get back to the source.

Profile

Field Type Notes
username string Handle as the platform spells it
display_name string | null
avatar_url string | null Hotlink at your own risk; these expire
verified boolean
url string Canonical profile URL
metrics.followers int | null
metrics.following int | null null on YouTube — not reported
metrics.posts int | null
metrics.likes int | null Lifetime likes where the platform reports them
metrics.views int | null null on TikTok and Instagram

Post

Field Type Notes
author.platform_resource_id string | null Identity only
author.username string | null
url string Canonical post URL
caption string | null Contact details are redacted — see below
media_type string | null video, image
published_at string | null ISO-8601
metrics.views int | null
metrics.likes int | null
metrics.comments int | null
metrics.shares int | null
metrics.saves int | null

Two rules about metrics

null means “this platform does not report it”. It never means zero. If you treat null as zero in a chart, you will draw a cliff that did not happen.

The same key does not mean the same measurement. A TikTok view is counted differently from a YouTube view, which is counted differently again from an Instagram view. We put them in the same place because that makes your code simpler; we do not claim they are comparable, and you should not sum them across platforms.

What is deliberately absent

These are not missing. They are excluded, and they will not be added:

caption stays, because it is content rather than a contact field — but email addresses, phone numbers and messenger handles inside it are redacted before the object is stored or returned.

Versioning

The schema is versioned in the path (/v1), independently of any upstream provider’s versions. Additive changes — a new optional field — can happen within v1. Removing or repurposing a field cannot.

Last updated 27 August 2026