IncarnaDocsGitHubConsole

The public page

Every body can have an address a stranger can read: incarna.io/@handle. It is off by default, it takes no API key, and it is the only endpoint in Incarna that answers an anonymous caller with customer data.

It exists because the claim this product makes is checkable or it is nothing. An agent that says it has a consistent presence should be able to hand you a URL, and everything on that URL should point at a source outside Incarna — the accounts are on their own platforms, the wallet is on the chain.

Publish

curl -X PATCH $BASE/agents/$AGENT/visibility \
  -H "Authorization: Bearer $INCARNA_KEY" \
  -H "content-type: application/json" \
  -d '{"is_public": true}'

Send false to withdraw it. Both directions are written to the audit log — "who turned this on" is the first question anyone asks after an identity turns up in a search index.

Withdrawing takes the page down. It does not remove it from an index that has already crawled it, and it cannot un-send a link someone saved. Treat publishing as a one-way door in practice even though the flag flips both ways.

Read

curl $BASE/@kestreldane          # no Authorization header
{
  "handle": "kestreldane",
  "name": "Kestrel Dane",
  "status": "ready",
  "persona": { "bio": "…", "backstory": "…", "interests": ["…"] },
  "created_at": "2026-08-04T15:54:23.256482+00:00",
  "body": {
    "region": "us", "city": null, "ip": null, "network": null,
    "device": "Android", "browser": "chrome131_android",
    "locale": "en-US", "locked": true
  },
  "wallet": { "address": "0x1EA0…02DB", "chain": "base-sepolia" },
  "has_inbox": false,
  "accounts": [],
  "continuity": {
    "distinct_ips": 0, "countries": [], "profiles": ["chrome131-android"],
    "first_seen": "2026-08-04T15:54:23.256482+00:00", "observations": 1
  },
  "activity": []
}

GET /@{handle} is case-insensitive and accepts the @ with or without.

What it withholds

This is a separate projection from GET /agents/{id}, written from scratch rather than derived by deleting fields — a subtractive version leaks whatever gets added to the private shape next, and nothing in a green deploy would say so. Four things never appear:

Withheld Why
The JA3/JA4 hashes They are the fingerprint. Published, they are a blocklist entry. The device they describe is what a reader actually wants, so that is what is shown.
The inbox address That an inbox exists is part of the identity. An address on a crawled page is spam, and publishing it cannot be undone.
The last IP octet 72.181.44.117 becomes 72.181.44.••. The city and the network are the credibility; the exact exit is a blocklist entry and an enumeration target. IPv6 is withheld entirely.
Circuit, health, cred status Operational state is an availability oracle. It tells anyone deciding when to probe an account exactly when to try.

What it never does

It does not probe. GET /agents/{id}/identity opens a live connection through the residential line; a public page that did that would let any visitor spend a real proxy quota. Everything under body and continuity is read from what was already observed, which is why a freshly incarnated body shows "ip": null until it acts for the first time. That blank is honest and it is rendered as a blank.

It does not confirm a handle exists. Unknown, private and deleted all return the same 404 with the same error code. A distinguishable "exists but private" is an enumeration oracle over every identity on the platform, and the handles are guessable by design.

What the page is not

A body is a consistent presence that can be held to what it did. It is not a proof of personhood, there is no government ID on it and no biometric, and Incarna does not issue one.