Read an agent configuration presentation
const url = 'https://api.harperharbor.com/open/v1/role/detail?roleId=example';const options = {method: 'GET', headers: {language: 'zh-Hant', 'X-XMLV3-Feature-Level': '1'}};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request GET \ --url 'https://api.harperharbor.com/open/v1/role/detail?roleId=example' \ --header 'X-XMLV3-Feature-Level: 1' \ --header 'language: zh-Hant'Guest-readable for public or unlisted configurations by ID across application tenants. Explicit private configurations require the author with role.read; invalid bearer tokens are rejected. Only the author with role.read receives model-facing instructions, translated private definitions and other private author fields. Other callers receive presentation fields only. Deleted or provider-taken-down configurations are unavailable to players; authorized authors can inspect their own taken-down configuration. Community review does not gate this endpoint.
Parameters
Section titled “Parameters”Query Parameters
Section titled “Query Parameters”Role id (characterRoleId). A missing or unknown id yields 400 with record not found.
Header Parameters
Section titled “Header Parameters”Viewer language. Selects the asset host used in roleAvatar/roleBackground and the locale used for commentNum.
Client XMLV3 renderer feature level; reflected in xmlV3Compatibility.clientFeatureLevel.
Responses
Section titled “Responses”Role card.
object
Present only on world cards. Viewers get each member’s id, name, avatar and profile plus maxSpeakers; the author also gets description, lorebookId, sex and strictness.
object
Members that may reply in one turn; default 2.
How far the world honours outcomes the player declares.
object
Stable member id; used by mention and by the speaker blocks.
Https URL, optional.
Short public side note everyone in the world knows; shown to viewers.
Private full definition; only this member’s own turns see it. Author only in responses.
A Lorebook the author owns, recalled only for this member. Author only in responses.
Numeric row id (not the public role id).
Public role id used as roleId everywhere.
Player name the author chose for the card (empty when unset).
Opening message.
URL slug, may be null.
Short intro.
Detail introduction in Markdown, shown on the card’s public page like a README (base language). Empty string when the author wrote none. Readable by anyone who can see the card; never sent to the model during chat. Render it as sanitized Markdown.
Detail introduction, English translation (present only when that translation exists).
Detail introduction, Japanese translation (present only when that translation exists).
Detail introduction, Korean translation (present only when that translation exists).
HarperHarbor: compatibility alias for the portrait background of the agent configuration; no independent avatar is stored.
Optional landscape (16:9) background URL. The chat page uses it on wide screens and falls back to roleBackground; keep important elements in the central 75%.
Optional share image URL (1.91:1, 1200×630) used as the link-preview og:image. Empty string when unset; callers fall back to another image.
Private definition; empty string for non-owners on /role/detail.
HarperHarbor defaults to unlisted (usable by ID without community listing).
Whether the definition is shown publicly (private/public).
Creation state (RoleStateWaitCreate, RoleStateCreating, RoleStateComplete).
Card type (e.g. story, companion, game, generator).
Conversation count (server substitutes the real count).
Output contract; empty string for non-owners on /role/detail.
Platform scope (all for cards created through this API).
Card language (zh-Hant, zh-Hans, en, ja, ko, all).
Set when the card first passed review.
Bumped on any row update, including counters.
Last author content edit.
recommended / normal / demoted.
Moderation status; pending corresponds to roleVisibility=waitReview.
Reason when rejected / sent to review.
Attached theme id; empty for default rendering.
Only for AI-generated cards.
E.g. open_api, mcp, manual, ai_summarize, import, clone.
System classification tag; empty string on /role/detail, omitted on /role/mine items when empty.
What {{char}} expands to in prompts when it should differ from roleName. Empty string means roleName is used.
Character Card V3 provenance kept for export and never used in prompts. Absent or null when the card has none.
object
Original author credit.
Card version string as written by the author.
Source URLs or identifiers.
Language code → creator notes in that language.
object
Unix seconds.
Unix seconds.
Parsed tag list ([] when the stored value is not valid JSON).
Platform tag as stored in roleTag.
object
Icon identifier; empty for tags written through this API.
Tag text.
Tag kind; tags written through this API use 2.
Always empty.
Echo of roleSpeech when it matches a known voice, else empty.
Parsed example dialogue ([] when not valid JSON). Item shape follows what the write routes store.
object
Speaker; assistant is accepted and stored as ai.
Line text; trimmed; must be non-blank.
object
From the X-XMLV3-Feature-Level header (default 1).
Minimum renderer level this card needs.
Latest renderer level known to the server.
Author nickname.
Author avatar URL.
Public numeric author id.
Whether the viewer follows the author (false for guests).
Whether the viewer follows this role (false for guests).
Alternate AI openings the player can choose before the first turn.
Player-side first-line options; a client fills the input with the chosen line rather than replacing the opening.
Whether a published custom preview page exists (see /role/preview-page).
Recommended landing surface when the card is opened.
Whether the role home page should show the comments tab.
Whether the viewer has a current conversation with this role (false for guests or on lookup error).
Approved top-level comment count for the viewer language (0 on error).
Theme attached to the card (present only when themeId is non-empty and the theme engine is enabled).
object
Theme style payload as stored (string).
Theme preview data as stored (string).
Author only; absent when the card has none.
object
Popularity of this card, summed across all published versions of the work. Each paid use by someone other than the author adds heat, weighted by the model’s price and never less than the credits charged. Heat only increases. Staging versions are not counted.
Example
{ "roleSex": "man", "roleVisibility": "private", "reviewStatus": "", "talkExample": [ { "roleType": "ai" } ], "xmlV3Compatibility": { "state": "supported" }, "roleEntry": "chat", "responseDefaults": { "agency": "protect", "style": "default", "perspective": "card", "length": "auto", "lengthTarget": "200", "pace": "natural" }}record not found (unknown roleId) or a database error string. Body is {"error": "<raw error string>"} (no message/retryable).
object
Error code (snake_case) or, for legacy handlers, a free-text/localized message.
Human-readable sentence. Present only on middleware errors and /me, /me/wallet.
Whether retrying may succeed. Present only on middleware errors, /me, /me/wallet and service/share routes.
Only on a first-turn context_capacity_exceeded: the smallest context tier that fits the whole card with room to talk. Save it as context in player settings and resend. Absent when no tier fits.
The token budget of required_context_tier for the selected model, for display.
Only on a first-turn context_capacity_exceeded: whether saving trimConstantLore=true lets the card play at the current tier. Absent on mid-conversation capacity errors.
Only on insufficient_credits: the credits this turn needs before it can start. Absent when the refusal came without an estimate.
Only on insufficient_credits: the credits the wallet could set aside for it.
Examplegenerated
{ "error": "example", "message": "example", "retryable": true, "required_context_tier": 1, "required_context_tokens": 1, "constant_lore_trim_fits": true, "credits_needed": 1, "credits_available": 1}unauthorized — an Authorization header was sent but the bearer is invalid (guest access only applies when the header is absent).
object
Error code (snake_case) or, for legacy handlers, a free-text/localized message.
Human-readable sentence. Present only on middleware errors and /me, /me/wallet.
Whether retrying may succeed. Present only on middleware errors, /me, /me/wallet and service/share routes.
Only on a first-turn context_capacity_exceeded: the smallest context tier that fits the whole card with room to talk. Save it as context in player settings and resend. Absent when no tier fits.
The token budget of required_context_tier for the selected model, for display.
Only on a first-turn context_capacity_exceeded: whether saving trimConstantLore=true lets the card play at the current tier. Absent on mid-conversation capacity errors.
Only on insufficient_credits: the credits this turn needs before it can start. Absent when the refusal came without an estimate.
Only on insufficient_credits: the credits the wallet could set aside for it.
Examplegenerated
{ "error": "example", "message": "example", "retryable": true, "required_context_tier": 1, "required_context_tokens": 1, "constant_lore_trim_fits": true, "credits_needed": 1, "credits_available": 1}..`) cannot call this route.
object
Error code (snake_case) or, for legacy handlers, a free-text/localized message.
Human-readable sentence. Present only on middleware errors and /me, /me/wallet.
Whether retrying may succeed. Present only on middleware errors, /me, /me/wallet and service/share routes.
Only on a first-turn context_capacity_exceeded: the smallest context tier that fits the whole card with room to talk. Save it as context in player settings and resend. Absent when no tier fits.
The token budget of required_context_tier for the selected model, for display.
Only on a first-turn context_capacity_exceeded: whether saving trimConstantLore=true lets the card play at the current tier. Absent on mid-conversation capacity errors.
Only on insufficient_credits: the credits this turn needs before it can start. Absent when the refusal came without an estimate.
Only on insufficient_credits: the credits the wallet could set aside for it.
Examplegenerated
{ "error": "example", "message": "example", "retryable": true, "required_context_tier": 1, "required_context_tokens": 1, "constant_lore_trim_fits": true, "credits_needed": 1, "credits_available": 1}