Find out who is who on social
Resolve a handle, a profile URL or a company domain into one person or organization with every account they run, each link backed by the evidence that found it; then pull one more ring on any node: profiles, posts with metrics over a date range you choose, the brands that paid a creator, an organization's ads and the creators it paid, and labels (category, niches) that rank similar people.
Reading the graph is free. A pull is priced before it runs (pull-estimate names what is already held, so a posts range pays only for its gaps), holds its budget on the credit wallet and is charged what it cost. Fresh data is never pulled twice: profiles and posts for a day, sponsors, ads and labels for a week.
Ask in plain words
- "who is behind this Instagram account"
- "find every account this founder runs"
- "pull this creator's last six months of posts"
- "which brands have paid this creator"
- "find people similar to this creator"
From an agent host (MCP)
Server: https://shapelessai.com/mcp (add it to your host).
identity_search: Find people, accounts and organizations the identity graph already knows, by name or handle, with their labels. Free. Use it before identity_resolve: a known node costs nothing to open. Needs the read scope.identity_node: One node in full: its fields, its edges with evidence, the pulls that fed it (vendor, cost, when), when each expansion was last pulled, the posts date ranges held, and metric history. Free. Needs the read scope.identity_people: Every person the graph holds, with labels, accounts and counts, sorted and filtered; scope mine is what this account tracks and the people one edge from them. Free. Needs the read scope.identity_similar: People like one person, each with the niches and organizations they share and why in one line. basis embedding, or labels with a note when the person has no embedding yet (run identity_expand with labels first). Free. Needs the read scope.identity_library: Every post held for a person or an account, sorted (multiplier is views against the account's own median) and faceted by platform and topic. Free; pull more with identity_expand posts. Needs the read scope.identity_tracked: What this account tracks (me, competitor, reference, watch) and those nodes. With node and role it tracks one or changes its role; with node and remove it stops. A resolve or an expand tracks its node as watch by itself. Free. Needs the read scope to list, write to change.identity_estimate: What identity_expand would cost before it runs, read from the price list and what the graph holds, never a vendor: estimateUsd, capUsd (the most it can spend at these settings), and for posts what the range already holds (alreadyHeld, coveredFrom, coveredTo) so only the gaps are paid for, and its cadenceHours and nextRefreshAt; for creators the priced steps. Engine USD: a paid plan is charged 3x, the free plan 1x. Free. Needs the read scope.identity_resolve: SPENDS CREDIT. Find who a seed is and land them in the identity graph: a person (handle, profile URL, personal site) or an organization (LinkedIn company URL, or a bare domain), then their accounts' profiles and labels. A seed already known opens for $0 unless force. budgetUsd 0.5 to 5 engine USD (default 2) is held on the wallet first; only what the pull cost is charged (holdUsd says what was held). Returns the anchor node, costUsd, the pulls and every node it showed. Needs the write scope.identity_expand: SPENDS CREDIT. Grow one node by one expansion: profile, posts, sponsors, ads, creators, metrics or labels. A fresh expansion answers costUsd 0 unless force. budgetUsd 0.01 to 2 engine USD (default 0.5) is held on the wallet first; only what the pull cost is charged. Price it first with identity_estimate. Needs the write scope.
From code (REST)
Bearer API key with the scope each call names (auth, OpenAPI).
GET /api/identity/search(read scope): Known people, accounts and organizations by name or handle, with their labels. Free. Start here to find a node id before spending anything.GET /api/identity/graph(read scope): The canvas: one node, its first ring and the edges among them (GraphView). Free.GET /api/identity/node/{id}(read scope): One node in full: its fields, edges with evidence, the pulls that fed it (vendor, cost, when), freshness per expansion, coverage windows of posts held, metric history (NodeDetail). Free.GET /api/identity/people(read scope): Every person with labels, accounts and counts, sorted and filtered (PeoplePage). Free.GET /api/identity/facets(read scope): The people list's group-by: {categories, niches, organizations}, each value with how many people carry it. Free.GET /api/identity/similar(read scope): People like one person, each with the niches and organizations they share and awhyin words. basis isembedding, orlabelswith a note when embeddings are missing (run the labels expansion first). Free.GET /api/identity/library(read scope): Every post held for a person or an account, sorted and faceted (LibraryPage). Free; pull more with the posts expansion.GET /api/identity/tracked(read scope): What this account tracks (me, competitor, reference, watch) and those nodes. A resolve or an expand tracks its node as watch by itself.POST /api/identity/tracked(write scope): Track a person, account or organization in a role, or change its role: {node, role, note?}. Free.DELETE /api/identity/tracked(write scope): Stop tracking a node: {node}. Answers {removed}.GET /api/identity/pull-estimate(read scope): The price of a pull before it runs (PullEstimate), read from the store and the price list, never a vendor: the vendor asked first, its unit and list price, the units this node likely takes, estimateUsd and capUsd (the most it can spend at these settings and budget). For posts it names what the range already holds (coveredFrom, coveredTo, alreadyHeld) and prices only the gaps. Free. Engine dollars: a paid plan is charged 3x, the free plan 1x.POST /api/identity/resolve(write scope): Find who a seed is and land them in the graph: a person (handle, profile URL, personal site) or an organization (LinkedIn company URL, or a bare domain no person's account holds). Then their accounts' profiles and labels, inside the same budget. A seed already known opens at once for $0 unless force. Streams NDJSON IdentityGraphEvents; the done event names the anchor node and costUsd. Paid from the credit wallet.POST /api/identity/expand(write scope): Grow one node by one ring: one expansion (profile, posts, sponsors, ads, creators, metrics, labels). A fresh expansion answers done with costUsd 0 unless force; freshness is profile daily, posts daily, sponsors weekly, ads weekly, creators weekly, metrics daily, labels weekly. Streams NDJSON IdentityGraphEvents. Price it first with GET /api/identity/pull-estimate. Paid from the credit wallet.POST /api/identity/post(write scope): Land one post by its link in the library under its author's account (one vendor call); with person: true the author then goes through the resolve door. Streams NDJSON IdentityGraphEvents. Paid from the credit wallet.
The body
POST /api/identity/tracked:
nodestring, required: A person, account or organization id (not an asset).rolestring, required (me,competitor,reference,watch)notestring | null
DELETE /api/identity/tracked:
nodestring, required
POST /api/identity/resolve:
seedstring, required: A handle (@ optional), a profile URL, a personal site, a LinkedIn company URL or a bare domain.kindstring (person,organization): Overrides the guess of what the seed is.budgetUsdnumber: The most the resolve, its profiles and its labels together may spend at engine cost, in USD (0.5 to 5, default 2; outside it is clamped). A key holds it on the credit wallet at its plan's rate before the pull starts and is charged only what the done event's costUsd says.forceboolean: Resolve again even when the seed is known.
POST /api/identity/expand:
nodestring, required: A node id: person:<uuid>, account:<uuid>, organization:<uuid> or asset:<platform>:<postId>. Find one with GET /api/identity/search, or take the anchor a resolve's done event names.expansionstring, required (profile,posts,sponsors,ads,creators,metrics,labels): What to pull. profile: account: its profile fields and avatar. person: every owned account's profile. organization: its website (name, description, the accounts it links), its own accounts' profiles, its LinkedIn company id and logo. posts: account: everything it published, newest first, with metrics. Takes since/until (or sinceMonths) and maxItems. sponsors: account: the brands that paid it (paid-partnership labels, the branded-content library, vendor sponsor data). ads: organization: its ads from the ad libraries (Meta, Google, LinkedIn; TikTok where open). creators: organization: the creators around it, cheapest evidence first: held bios that name it and held posts of its own accounts (free), one posts page of its creator-feature accounts (cents), then a vendor's index of paid creators. Lands paid, partners_with and features edges. metrics: asset: a fresh metric snapshot of one post. labels: person or organization: what it is (category, niches, organizations), read by a language model from what the graph already holds; for a person also the embedding /api/identity/similar ranks by.budgetUsdnumber: The most this pull may spend at engine cost, in USD (0.01 to 2, default 0.5; outside it is clamped). A key holds it on the credit wallet at its plan's rate before the pull starts and is charged only what the done event's costUsd says.sincestring: posts only: the oldest publish date to read (ISO day or instant, at most 10 years back). Default now minus sinceMonths.untilstring: posts only: the newest publish date to read. Default now.sinceMonthsinteger: posts only: sugar for since = now minus this many months.maxItemsinteger: posts only: the most posts one pull lands.forceboolean: Pull again even when fresh or already held. Without it a fresh expansion answers done with costUsd 0, and a posts pull reads only the gaps in what is held.
POST /api/identity/post:
urlstring, required: A link to one post: an Instagram reel or post, a TikTok video, a YouTube video or short, an X status, a Threads post, a LinkedIn post.personboolean: Also resolve the author into a person (the resolve budget range applies).budgetUsdnumber: Engine USD. Without person 0.01 to 2 (default 0.5); with person 0.5 to 5 (default 2). Held on the wallet first.forceboolean
From a terminal (CLI)
shapeless identity searchshapeless identity nodeshapeless identity peopleshapeless identity similarshapeless identity libraryshapeless identity trackedshapeless identity estimateshapeless identity resolveshapeless identity expand
Example
Refusals
| Status | Meaning |
|---|---|
| 404 | No such node. |
| 404 | No such person. |
| 400 | The body is wrong; the message names the field (an unknown expansion, a node id that is not one, since after until). |
| 402 | The wallet cannot hold budgetUsd at this plan's rate: {code, error, holdUsd, budgetUsd, balanceUsd, upgrade}. Lower budgetUsd or top up; nothing was pulled. |
Where else
More in Signal
List a tool on the Shapeless Directory, or search it · Read performance · Pick your reference creators and competitors · Audit a profile · Boost with paid
