Create an agent configuration
const url = 'https://api.harperharbor.com/open/v1/role';const options = { method: 'POST', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, body: '{"roleName":"example","language":"example","cardType":"story","idempotencyKey":"example","origin":"example","visibility":"private"}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url https://api.harperharbor.com/open/v1/role \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --data '{ "roleName": "example", "language": "example", "cardType": "story", "idempotencyKey": "example", "origin": "example", "visibility": "private" }'Creates an agent configuration owned by the bearer account. HarperHarbor defaults to roleVisibility=unlisted: anyone with the ID can use its public presentation and authenticated playback across applications, without community approval. Full instructions and Lorebooks remain author-only. Communities independently control review, listing and discovery. Explicit private configurations remain owner-only; deleted or provider-taken-down configurations are unavailable. Fill content with the document and welcome endpoints. Tenant records storage and application attribution, not a playback boundary. Creates an agent configuration owned by the bearer account. Set visibility to private for author-only access or unlisted for link access; omitted visibility defaults to unlisted. Authorized clients retain their scoped access. Creation does not publish or submit for review. The CLI sends unlisted with --create.
Authorizations
Section titled “Authorizations”Request Bodyrequired
Section titled “Request Bodyrequired”object
Card name; trimmed; must be non-blank.
Card language. Recognized values and aliases are normalized to en, zh-Hant, zh-Hans, ja, ko, all (e.g. zh-TW, zh-CN, jp, kr); any other non-empty string is stored as given and treated as a non-English locale for limits. Defaults to the account language, then zh-Hans. Drives per-field character limits.
Stored as-is as the card’s roleType (not validated). Values understood by validation/quality heuristics: companion, story, game, generator.
Accepted for API symmetry; not used for deduplication on this route.
Self-declared creation source. Values on the provider’s whitelist are stored as creationMethod; anything else falls back to open_api.
Responses
Section titled “Responses”Success
Summary returned by every role write.
object
Role id.
Current visibility. HarperHarbor defaults to unlisted (usable by ID without community listing).
Moderation status.
Always owner on these routes.
Present when a deep patch was applied to a single field.
object
Number of operations applied.
Rune count before.
Rune count after.
Hex SHA-256 of the text before.
Hex SHA-256 of the text after.
Per-field patch summaries keyed by field name; present when fieldPatches were used.
object
object
Number of operations applied.
Rune count before.
Rune count after.
Hex SHA-256 of the text before.
Hex SHA-256 of the text after.
Character counts before/after for the edited field (e.g. roleDetailDesc, roleWelcome).
object
object
Character (rune) count before the write.
Character (rune) count after the write.
Suggested next MCP tool names; informational.
Example
{ "roleVisibility": "private", "reviewStatus": "not_submitted", "accountPermission": "owner"}invalid JSON body, roleName is required (body-level checks; body is {"error": "..."}), or invalid_arguments from the service ({"error": "invalid_arguments", "retryable": false}).
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.
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}permission_denied
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}Unclassified service/database error; {"error": "<string>", "retryable": true}.
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}