Resources
This guide is for AI agent runtimes (OpenClaw, Hermes, custom desktop agents, and any third-party integration) that consume Soulidity Souls on a human user's behalf. It covers API key auth, the search / access endpoints, the pre-check pattern for issuing or extending SoulGrants, and the auto-grant rules that fire when an owner appends content.
A Soulidity agent is a member record of kind agent, bound to one Sui wallet and registered under a human user's account. Agents authenticate to the API with an API key, and to the Move layer as the holder of SoulGrant objects (or KindPaidEntry rows) issued to their wallet address.
API keys live on the agent member record and are bcrypt-hashed at rest. They start with the sk- prefix and are shown only during the desktop companion link / rotation flow. Pass them in the Authorization: Bearer <key> header. Endpoints under /api/agent/* require a valid key.
// Use as bearer token
GET /api/agent/souls/search?limit=20
Authorization: Bearer sk-...
// Rotate from the linked desktop companion
POST /api/desktop/me/agent-key/rotate
Authorization: Bearer dtk_...
{ "rotationId": "<client-generated-id>" }Treat the key as a long-lived secret; rotate on compromise. Lost keys cannot be recovered — only rotated, which invalidates the previously committed key after the desktop flow completes.
q, tag, limit, and offset.(KIND_SOUL_DOC, "soul", 0) when fields are omitted.Each Soul has one grant slot per grantee. Issuing a second grant to the same grantee supersedes the first — the new scope_mask fully replaces the old one (no union). This is a behavior change from the early protocol design where issuing a partial scope would silently combine with existing scopes.
The practical consequence: if you (or your tooling) submit a fresh grant TX without first looking up the agent's existing scope, you may unintentionally remove scopes the user already granted. Always pre-check.
The endpoint below computes existing | added for a list of (soulOnChainId, granteeAddress) pairs. Call it before signing a grant TX that's meant to extend rather than overwrite.
POST /api/souls/grant-merge-masks
{
"items": [
{
"soulOnChainId": "0x...",
"granteeAddress": "0x...",
"addedScopeMask": 4 // SCOPE_SKILLS
}
]
}
→ {
"items": [
{
"soulOnChainId": "0x...",
"granteeAddress": "0x...",
"addedScopeMask": 4,
"existingScopeMask": 2, // pre-existing SCOPE_MEMORY
"mergedScopeMask": 6, // memory | skills
"isNewGrantee": false,
"currentCapacity": 16,
"activeGrantCount": 3,
"requiredCapacity": 16
}
]
}Use the returned mergedScopeMask and capacity fields to build the actual grant PTB with buildIssueGrantTx or buildBatchIssueGrantsTx. The SDK does not perform this pre-check implicitly; call the endpoint before signing when your intent is to preserve existing scopes.
When a Soul owner uploads a non-public version of any content kind, the web app issues scope-matched SoulGranttop-ups automatically. The rule for each agent in the owner's active set:
default_grant_scope_mask from the KindRegistry — call it needed.scope_mask & needed == needed, skip — already covered.merged = existing | needed via grant-merge-masks, then issue a supersede TX with merged.Agents do not need to do anything to trigger auto-grant — it happens server-side after the owner's append. But agents should treat fresh grant events as the signal to invalidate caches and re-resolve Seal sessions.
Public versions (under public slot_read_mode_mask) are not auto-granted — they are readable without a grant. The auto-grant flow only covers slots whose read mode requires a grant or paid entry.
SEAL_DENIED. The agent should re-query /api/souls/[id] for the new owner and surface a re-authorize prompt to the user.txDigest. Replaying the same digest returns the cached response, so retries are safe.seal_approve_content_paid_access failures as transient unless three sequential attempts fail.Two integration patterns are common: