Directory
One account or channel
/data-api/v2/directory/{platform}/{id}- Scope
- directory:read
- Freshness
- catalog read
- Group
- Directory
- Platforms
- 7 of 7
What this endpoint answers
A single catalog record by handle or by platform id. Use ?include= to fold growth history, the top known followers, engagement and lookalike accounts into the same call instead of making four.
This is a catalog read: it is served from the CRM Solid database in milliseconds, costs one budget unit, and reports how old the reading is in meta.cache_age_s. It needs the directory:read scope (Directory): Read the account and channel catalog across all seven platforms.
Good to know
- notable_followers is always null and is kept only so existing clients do not break on a missing key. It was previously computed on every read by ranking an account's entire in-degree, which exceeded the query timeout on well connected accounts and made this endpoint fail for exactly the accounts people look up most. Ask for ?include=followers instead.
- ?include=followers ranks the largest accounts within a SAMPLE of the inbound edges we hold, not across an account's real follower list, which we do not have. The sample is bounded so the call cannot time out.
- include=engagement is X-only: xdir_account_engagement is the only engagement table in the catalog. The full engagement surface is under /insights.
- include=similar matches on audience band (0.4x to 2.5x) and language, ranked by closeness in audience. It is not a content-similarity model.
- A handle that has been reused resolves to the largest account holding it.
Parameters
Every value the call accepts, with the example the spec ships so the request runs as written.
| Name | In | Required | Example | What it does |
|---|---|---|---|---|
platform | path | required | x | Which catalog to read. |
id | path | required | elonmusk | Handle (case-insensitive, with or without @) or platform id. X, Instagram and TikTok accept the numeric user id, YouTube accepts the channel id, Bluesky accept… |
include | query | optional | growth,similar | Comma-separated extras. growth = last 30 daily points. followers = the largest accounts within a sample of the inbound edges we hold, up to 10. engagement = he… |
Call it
Authenticate with a bearer token or the x-api-key header. Keys are server-to-server credentials. Never embed one in front-end code - call the API from your own backend and forward the result.
curl "https://crmsolid.com/data-api/v2/directory/x/elonmusk" \
-H "Authorization: Bearer psk_live_..."
const res = await fetch("https://crmsolid.com/data-api/v2/directory/x/elonmusk", {
headers: {
Authorization: `Bearer ${process.env.CRM_SOLID_DATA_API_KEY}`,
},
});
if (!res.ok) {
const { error } = await res.json();
throw new Error(`${error.code}: ${error.message} (${error.request_id})`);
}
const { data, meta } = await res.json();
import os
import requests
res = requests.get(
"https://crmsolid.com/data-api/v2/directory/x/elonmusk",
headers={"Authorization": f"Bearer {os.environ['CRM_SOLID_DATA_API_KEY']}"},
timeout=30,
)
res.raise_for_status()
payload = res.json()
data, meta = payload["data"], payload["meta"]
Keys look like psk_live_... for production keys, psk_test_... for test keys and are minted in the panel.
What comes back
Success is { data, meta }. Failure is { error: { code, message, request_id } }. The body below is the spec's own example: the values in it are illustrative readings, not live numbers.
- Platform
- x
- Object
- account
- Record user id
- 44196397
- Record username
- elonmusk
- Record name
- Elon Musk
- Record followers count
- 221,384,902
- Record following count
- 1,102
- Record statuses count
- 79,431
- Record media count
- 4,612
- Record favourites count
- 152,889
- Record is verified
- no
- Record is blue verified
- yes
- Record is automated
- no
- Record photo url
- https://pbs.twimg.com/profile_images/1936002956/elon_400x400.jpg
- Record banner url
- https://pbs.twimg.com/profile_banners/44196397/1739948056/1500x500
- Record account created at
- 6/2/2009, 8:12:29 PM
- Record language
- en
- Record country
- US
- Record category
- technology
- Record citation score
- 41,882
- Record tier
- S
- Record status
- active
- Record is nsfw
- no
- Record last seen
- 8/22/2026, 10:14:07 PM
- Record weekly growth
- 412,004
- Growth
- 1 items
- Similar
- 1 items
{
"data": {
"platform": "x",
"object": "account",
"record": {
"user_id": "44196397",
"username": "elonmusk",
"name": "Elon Musk",
"description": "",
"followers_count": 221384902,
"following_count": 1102,
"statuses_count": 79431,
"media_count": 4612,
"favourites_count": 152889,
"url": null,
"is_verified": false,
"is_blue_verified": true,
"verified_type": null,
"is_automated": false,
"location": "",
"photo_url": "https://pbs.twimg.com/profile_images/1936002956/elon_400x400.jpg",
"banner_url": "https://pbs.twimg.com/profile_banners/44196397/1739948056/1500x500",
"account_created_at": "2009-06-02T20:12:29+00:00",
"language": "en",
"country": "US",
"category": "technology",
"citation_score": 41882,
"tier": "S",
"status": "active",
"is_nsfw": false,
"last_seen": "2026-08-22T22:14:07+00:00",
"weekly_growth": 412004,
"notable_followers": null
},
"growth": [
{
"day": "2026-08-21",
"value": 221309004,
"delta": 41221
}
],
"similar": [
{
"user_id": "10228272",
"username": "YouTube",
"name": "YouTube",
"followers_count": 78112004,
"language": "en",
"country": "US",
"category": "technology"
}
]
},
"meta": {
"request_id": "req_9f2c41a8b3d5",
"generated_at": "2026-08-23T09:14:02.317Z",
"took_ms": 42
}
}
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.
When it fails
GET /directory/{platform}/{id} documents 8 failure statuses. Branch on error.code, which is stable and enumerated; message is prose and may change.
- 401Unauthorized
unauthorized | invalid_keyNo key was presented, or the key is unknown, revoked or expired.
- 402PaymentRequired
payment_required | subscription_inactiveThe 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.
Carries X-Plan, X-Plan-Limit, X-Plan-Overage, X-Plan-Period-End, X-Plan-Remaining.
- 403Forbidden
forbidden_scope | forbidden_ipThe 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.
- 404NotFound
not_foundThe addressed resource does not exist.
- 422InvalidRequest
invalid_requestA parameter is malformed, out of range or mutually exclusive with another. `details` names the offending fields.
- 429RateLimited
rate_limited | quota_exceededEither 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.
Carries Retry-After, X-Quota-Limit, X-Quota-Remaining, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-Request-Id.
- 500InternalError
internal_errorSomething failed on our side. Internals are never leaked; quote the request id.
- 503Unavailable
upstream_timeout | upstream_error | not_configuredThe 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.
Every response carries X-Request-Id and meta.request_id. Quote it in support requests.
Coverage and limits
This endpoint covers X, Instagram, TikTok, YouTube, Telegram, Bluesky, LinkedIn. Rate limits come from the tier on your key.
| Tier | Requests a minute | Requests a day | Live reads a minute |
|---|---|---|---|
| free | 30 | 1,000 | 5 |
| standard | 120 | 25,000 | 20 |
| pro | 600 | 250,000 | 60 |
| unlimited | 6,000 | 10,000,000 | 600 |
This call only draws on the ordinary per-minute and per-day columns. Every response reports where you stand in X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset and the X-Plan headers.
Start calling it
A key takes a minute to mint in the panel, no card. The reference covers authentication, the envelope, scopes, rate limits and every error code in one page.
Reference path: /data-api/reference/directory-get