Data API
API reference
Every endpoint with the exact response it returns. One key, one base URL, one envelope, and a real example body on every row.
- Base URL
- https://pinlyx.com/data-api/v2
- Version
- 2.0.0
- Endpoints
- 127
- Platforms
- 7
How a call works
Four things to know before the first request. Everything further down is detail on one of them.
- 01
Get a key
Minted in the panel in a minute, no card. A key carries the scopes your plan allows and a rate tier, and it is a server-to-server credential.
- 02
Pick catalog or live
Most endpoints read our own catalog: fast, cached, one budget unit. Live endpoints go to the platform now, cost more, and say so with a Live badge.
- 03
Read the envelope
Success is always data plus meta. Failure is always an error object with a stable code. The shape never changes between endpoints.
- 04
Watch the headers
Every response tells you where you stand: burst and daily limits from your tier, plan budget from what you bought. Nothing runs out silently.
Authentication
Every request needs a key. Send it as a bearer token, or as x-api-key if that suits your client better. Keys are minted in the panel and are server-to-server credentials: anyone who opens devtools on a page that carries one has your whole quota.
# Preferred: bearer token
curl https://pinlyx.com/data-api/v2/accounts/instagram/nasa \
-H "Authorization: Bearer psk_live_..."
# Equivalent: plain header
curl https://pinlyx.com/data-api/v2/accounts/instagram/nasa \
-H "x-api-key: psk_live_..."
psk_live_... for production keys, psk_test_... for test keysKeys are server-to-server credentials. Never embed one in front-end code - call the API from your own backend and forward the result.
Anatomy of a response
A real answer from GET /accounts/{platform}/{handle}, exactly as the API returns it. data is the answer. meta is the receipt: who served it, how long it took and how old the number is.
{
"data": {
"platform": "instagram",
"handle": "nasa",
"checked_at": "2026-08-30T09:14:02.113Z",
"exists": true,
"evidence": "catalog",
"identity": {
"id": "528817151",
"handle": "nasa",
"name": "NASA",
"avatar_url": "https://scontent.cdninstagram.com/v/t51.2885-19/...",
"url": "https://www.instagram.com/nasa/",
"object": "account"
},
"audience": {
"count": 104443318,
"metric": "followers",
"precision": "exact"
},
"flags": {
"verified": true,
"private": false,
"nsfw": false
},
"created_at": null,
"catalog": {
"state": "present",
"status": "active",
"tier": "a",
"category": "science",
"language": "en",
"country": null,
"last_seen": "2026-08-30T04:02:11.000Z",
"data_age_s": 18711,
"directory_url": "/best-instagram-accounts/nasa",
"metrics": {
"engagement_rate": 0.4213,
"avg_likes": 402118,
"avg_comments": 2904,
"posts_analyzed": 12,
"citation_score": 91
}
}
},
"meta": {
"request_id": "req_9f2c41a8b3d5",
"generated_at": "2026-08-23T09:14:02.317Z",
"took_ms": 42
}
}
The data block
Shaped per endpoint and documented on every row below. On the account endpoints every count is a number or null, and null means not measured, never zero.
The meta block
request_idstringrequiredUnique id for this request. Quote it in a support ticket.
generated_atstringrequiredServer time the response was produced.
took_msintegerrequiredMilliseconds spent server-side.
pagePageoptionalsourcestringoptionalWhich backend served the payload, for endpoints with more than one.
cache_age_sintegeroptionalAge of the underlying data in seconds. 0 for live reads.
The error envelope
Failure never carries data. Branch on error.code, which is stable and enumerated; message is prose and may change. details appears on invalid_request and names the offending fields.
{
"error": {
"code": "invalid_request",
"message": "One or more parameters are invalid.",
"details": {
"limit": "Must be between 1 and 500."
},
"request_id": "req_9f2c41a8b3d5"
}
}
Catalog or live
The one decision you make per call: read what our crawlers already hold, or ask the platform this second.
Catalog reads
- Served from our own database: one index probe, milliseconds.
- Costs one budget unit and counts only against your tier’s burst and daily limits.
- meta.cache_age_s says how old the reading is, so freshness is a check in code, not a guess.
- 45 of 127 endpoints.
Live reads
- Go to the platform at request time and return cache_age_s = 0.
- Metered against a separate live-per-minute bucket and cost more than one budget unit; the multiplier is on every plan.
- 15 of them also spend upstream credits per call, and carry a Spends credits badge.
- 45 endpoints in all, each carrying a Live badge on its row below.
Pagination
List endpoints take ?limit= (up to 500) and ?cursor=. Follow meta.page.next_cursor until it is null; a short page is not the end. Cursors are opaque and signed, so paging stays consistent while rows are being inserted, and a hand-written cursor is rejected.
{
"data": [
"..."
],
"meta": {
"request_id": "req_9f2c41a8b3d5",
"page": {
"limit": 50,
"next_cursor": "eyJrIjoiMTczNDU2IiwiZCI6ImEifQ",
"count": 50
}
}
}
meta.page
limitintegerrequiredRows requested. Default 50, maximum 500.
next_cursorstringrequiredPass as ?cursor= to fetch the next page. null means the result set is exhausted, and it is the only reliable stop condition.
countintegerrequiredRows in this page.
totalintegeroptionalTotal matching rows. Present only when counting is cheap; never assume it is there.
Scopes
A key carries a set of scopes and each endpoint declares exactly one. A plan is the ceiling: asking for a scope your plan does not include is refused when the key is created, not on the first call.
directory:readRead the account and channel catalog across all seven platforms.
scrape:liveSensitiveRead from the platform itself rather than from the catalog: a profile or channel on any of the seven platforms, and on X the whole content layer - timelines, posts, replies, quotes, threads, followers, search, lists and communities.
insights:readEngagement rates, top posts, viral patterns, cohort benchmarks.
research:readFindings, runs and events from the autonomous research engine.
leads:readSensitiveLinkedIn company and contact data, and X follower-graph exports.
tools:useSensitiveRun the analysis tools: valuation, follower audit, scoring, and more.
Sensitive scopes are not on a new key by default, and every call under them is audited.
Rate limits and plan budget
Two buckets apply at once: a burst ceiling per minute and a quota per day, both from the tier your plan grants. Endpoints that reach a platform live are capped separately, so paging the catalog fast never starves the fetchers.
| Tier | Per minute | Per day | Live per minute |
|---|---|---|---|
| free | 30 | 1,000 | 5 |
| standard | 120 | 25,000 | 20 |
| pro | 600 | 250,000 | 60 |
| unlimited | 6,000 | 10,000,000 | 600 |
Tier ceilings are engineering limits. What you bought is separate and reported in its own header family, X-Plan-*, which is absent entirely on a key that is not attached to a subscription. 429 quota_exceeded clears on a clock; 402 payment_required does not, it clears when you fund the overage or renew.
Limit headers
X-RateLimit-LimitRequests allowed in the current one-minute window.
X-RateLimit-RemainingRequests left in the current one-minute window.
X-RateLimit-ResetUnix seconds at which the current window resets.
X-Quota-LimitRequests allowed today, from your tier.
X-Quota-RemainingRequests left in today's quota.
Retry-AfterSeconds to wait before retrying.
X-Request-IdUnique id for this request, echoed in meta.request_id.
Plan headers
X-PlanPlan id behind the key.
X-Plan-LimitRequests included in the current billing period.
X-Plan-RemainingIncluded requests left in the current billing period.
X-Plan-OverageRequests served beyond the included allowance so far this period.
X-Plan-Period-EndWhen the current billing period ends, ISO 8601.
Error codes
Eight HTTP statuses, fourteen codes, and that is the complete set. Branch on the code: the status alone is not enough to know what to do.
| Status | Codes | When | What to do |
|---|---|---|---|
| 401 | unauthorizedinvalid_key | No key was presented, or the key is unknown, revoked or expired. | Check the key and the header name. A revoked or expired key needs a new one from the panel. |
| 402 | payment_requiredsubscription_inactive | The key is valid but the plan behind it cannot serve the call: the included requests are spent and overage is switched off, capped or unfunded (payment_required), or the billing period lapsed and was not renewed (subscription_inactive). Retrying does not help; paying does. The X-Plan-* headers on this response say how far past the line you are. | Fund the overage or renew the period in the panel. Retrying does not help. |
| 403 | forbidden_scopeforbidden_ip | The key is valid but not allowed to make this call: it lacks the scope, or the request came from an address outside the key's allowlist. | Ask for the scope when you create the key, or add the caller’s address to the key’s allowlist. |
| 404 | not_found | The addressed resource does not exist. | Check the handle or id. An account we have not indexed is not a 404 on the account endpoints; read catalog.state instead. |
| 422 | invalid_request | A parameter is malformed, out of range or mutually exclusive with another. `details` names the offending fields. | Read error.details: it names each bad parameter and the range it should be in. |
| 429 | rate_limitedquota_exceeded | Either the burst ceiling for the current minute or the daily quota is spent. Distinguish with the code: rate_limited clears within the minute, quota_exceeded does not clear until 00:00 UTC. | Wait Retry-After seconds. rate_limited clears within the minute; quota_exceeded at 00:00 UTC. |
| 500 | internal_error | Something failed on our side. Internals are never leaked; quote the request id. | Retry once, then contact support with the request_id. |
| 503 | upstream_timeoutupstream_errornot_configured | The request could not be served right now. BRANCH ON error.code, not on the status: 'upstream_timeout' means a source was too slow (this is what a catalog query hitting its 15-second statement timeout returns, so it is reachable from any endpoint that reads the corpus, not only the live-scrape ones) and the same call is worth retrying with backoff - narrowing it with a smaller limit, a filtered scope or a less popular account makes it far less likely; 'upstream_error' means a source was unreachable, so back off further; 'not_configured' means the capability has no backing service in this deployment, and retrying will never help. | Retry with backoff on upstream_timeout and upstream_error; a narrower query helps. not_configured never clears. |
Endpoints
Grouped the way the API groups them. Open a row for its parameters, a copy-ready request and the response it returns.
Accounts5
Check one account, on any of the seven platforms, in one shape: does it exist, how big is it, is it verified, when was it created, is it in our catalog and how stale is that reading. The catalog checks are index probes and cost nothing; add /live to read the platform itself.
Directory9
The account and channel catalog the crawlers maintain across X, Instagram, TikTok, YouTube, Telegram and Bluesky. Reads are served from our own Postgres, so they are fast, cheap and bounded only by your tier.
X25
The raw X (Twitter) surface, read live: profiles, timelines, followers and following, single posts with their replies, quotes, reposts and full threads, advanced search, list timelines and community feeds. Where Insights answers how an account is performing off our own catalog, this group answers what X says right now - and it is the one place the post layer itself is published rather than measured. Every call spends a slot on a finite scraper pool, so it is metered as a live call and paginated with cursors rather than offsets.
People2
Cross-catalog people search: one handle looked up in every catalog at once, or accounts matched by audience size, engagement, language and category across platforms.
Live scrape5
On-demand reads that skip the catalog and fetch from the source right now. Slower and separately metered, because every call costs upstream work. Reach for these when you need one handle fresh, not for bulk enrichment.
Insights32
Derived engagement intelligence: engagement rates, top and viral posts, posting patterns and cohort benchmarks computed over the post layer.
Trends2
Discovery rather than lookup: who gained or lost the most audience on a given day, ranked from the same daily series the growth history is built on. The catalog answers questions about a handle you already have; this answers the question you ask before you have one.
Identity5
The same entity seen from more than one place: the social accounts a company publishes, the company behind a handle, and the several usernames a Telegram channel can hold at once. Every other surface here describes an account you already identified; this one closes the loop between an organisation and its presence.
Graph4
The X follow graph: audience overlap between two accounts, lookalike accounts by shared audience, and an account's followers ranked by their own influence.
Watch10
Webhooks. Register a destination, prove you control it, watch accounts for audience change, and read or replay every delivery.
Research4
Findings, runs and events from the autonomous research engine, which decides on its own which pools to expand and reports what it learned.
Tools18
The analysis tools behind the public free-tool pages, callable directly: valuation, follower audit, scoring and the rest. Metered like a live call, because each run costs compute or an upstream fetch.
Leads6
B2B lead data: LinkedIn companies and decision makers, plus X follower-graph exports. Sensitive by nature, separately scoped, and never granted by default.
Start on the free plan
A hundred requests, one key, no card. Enough to check the data is the data you need before any money moves.