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:
- Email addresses, phone numbers, postal addresses. Never fetched, never stored, never returned.
bio. Creator bios routinely contain exactly the contact details above, so the field is excluded from the schema rather than filtered afterwards.- Private-account data, and anything behind a login.
- Cross-platform identity matching. We will not tell you that two accounts on two platforms are the same person.
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