Shapeless Identity
Resolve a handle or a domain into the person or organization behind it, pull their posts, sponsors and ads one ring at a time, and price every pull before it runs.
Shapeless Identity is one graph of who is who on social. A person owns accounts, works at or runs organizations, and publishes assets (posts, reels, ads). Every link carries the evidence that found it, and every fact the pull (one vendor call, with its cost) that produced it. The graph is shared: a person someone already resolved opens for free.
Three verbs: resolve a seed into a node, expand a node by one ring, read what is held.
Resolve: who is this?
A seed is a handle, a profile URL, a personal site, a LinkedIn company URL or a bare domain
(shapelessai.com). kind: "person" | "organization" overrides the guess. The resolve finds the
person and their accounts, then reads those accounts' profiles and labels the person, all inside
one budget. A seed the graph already knows answers at once with costUsd: 0; force: true runs it
again.
Expand: one more ring
| Expansion | On | Pulls |
|---|---|---|
profile | account, person, organization | Profile fields and avatar; for a person every account's; for an organization its site, its own accounts, its LinkedIn id and logo. |
posts | account | What it published, newest first, with metrics. |
sponsors | account | The brands that paid it: paid-partnership labels, the branded-content library. |
ads | organization | Its ads from the Meta, Google and LinkedIn ad libraries (TikTok where open). |
creators | organization | The creators around it: paid ones, partners, and the ones its accounts feature. |
metrics | asset | A fresh snapshot of one post's numbers. |
labels | person, organization | What it is (category, niches), read by a model from what the graph holds; for a person also what similar ranks by. |
The controls
| Field | Range | What it does |
|---|---|---|
budgetUsd | resolve 0.5 to 5 (default 2); expand 0.01 to 2 (default 0.5) | The most the pull may spend, at engine cost. Outside the range it is clamped. |
since, until | ISO days, at most 10 years back | posts: the publish-date range to read. until defaults to now. |
sinceMonths | 1 to 36 (default 12) | posts: shorthand for since = now minus this many months. |
maxItems | 25 to 1000 (default 300) | posts: the most posts one pull lands. |
force | true / false | Pull even when fresh, and the whole posts range rather than only its gaps. |
kind | person / organization | resolve: what the seed is. |
A posts pull remembers the date ranges it read. The next one reads only the gaps, forward or
backward, unless force.
Freshness. An expansion pulled recently answers done with costUsd: 0 unless force:
profiles and metrics are fresh for a day; sponsors, ads, creators and labels for a week. Posts follow
the account's own rhythm: half the median gap between its newest posts, held to 6 hours to 7 days
(a day until three posts are held). pull-estimate says when (nextRefreshAt). A posts pull that
names since or until skips the age check and reads only the unread gaps.
Cost before you click
pull-estimate prices a pull before it runs, from the price list and what the graph already
holds, never a vendor: estimateUsd, capUsd (the most it can spend at these settings), and for
posts alreadyHeld, coveredFrom, coveredTo and the priced gaps. For creators it lists
steps, cheapest first: the bios and posts the graph already holds (free), one posts page of the
brand's creator-feature account, then a vendor's index of paid creators, each priced. Free.
A resolve or an expand holds its budget on your credit wallet first (X-Identity-Hold-Usd says how
much), and settles at what the done event's costUsd says, charged like every other run: engine
cost on the free plan, three times it on a paid plan. The rest comes back. A wallet that cannot
hold the budget is a 402 naming holdUsd and balanceUsd, before anything is pulled; lower
budgetUsd or top up. A pull you abort, or one that ends in error, pays only for the vendor
calls that already ran. A done says where the money went (breakdown: modelUsd for the
model's turns, vendorUsd for the vendors' calls); a resolve's error also carries costUsd,
breakdown and stoppedBy (budget, steps, refusal, stuck, abort, error or undelivered).
The stream
A resolve, an expand and POST /api/identity/post answer application/x-ndjson, one event per
line, as it happens:
It ends with exactly one done (the anchor node and the bill) or one error. A pull repeats per
id as it moves from running to ok. The CLI prints each line as it lands; the MCP tools
identity_resolve and identity_expand return the anchor, the cost, the pulls and every node seen.
Read
All free, read scope:
| Method | Path | Answers |
|---|---|---|
| GET | /api/identity/search?q=&limit= | Known people, accounts and organizations, with labels. Search before you resolve. |
| GET | /api/identity/node/[id] | One node: fields, edges with evidence, pulls, freshness, posts coverage, metric history. |
| GET | /api/identity/graph?anchor= | A node, its first ring and the edges among them. |
| GET | /api/identity/people?q=&sort=&category=&niche=&scope=&limit= | Everyone, sorted updated, followers, assets or name. scope=mine is what you track and one edge out. |
| GET | /api/identity/facets?scope= | Categories, niches and organizations with counts. |
| GET | /api/identity/similar?anchor=person:<id>&limit=&scope= | People like one person, each with a why. |
| GET | /api/identity/library?anchor=&sort=&platform=&limit=&offset= | Posts held, sorted newest, views, multiplier (against the account's own median) or likes. |
| GET/POST/DELETE | /api/identity/tracked | What you track as me, competitor, reference or watch (POST and DELETE cost write). A resolve or an expand tracks its node as watch. |
Node ids are person:<uuid>, account:<uuid>, organization:<uuid> and
asset:<platform>:<postId>. Every route and schema is in the
OpenAPI document; the MCP tools are identity_search, identity_node,
identity_people, identity_similar, identity_library, identity_tracked, identity_estimate,
identity_resolve and identity_expand.
