Skip to content

Validate an owned role and report limits

GET
/open/v1/role/validate
curl --request GET \
--url 'https://api.harperharbor.com/open/v1/role/validate?roleId=example' \
--header 'Authorization: Bearer <token>'

Runs the pre-publish validation on a card owned by the bearer and returns blockers (missing roleName/roleWelcome/roleDetailDesc, fields over their character limit, HTML/XMLV3 markup problems in the opening), warnings (missing avatar/background, quality heuristics), suggested fixes, quality dimensions and a token-budget report whose limits block lists the hard per-field character limits for this card’s language. Clients should read limits from here rather than hard-coding them. status is blocker when any blocker exists, warning when only warnings exist, else pass.

roleId
required
string

Role id.

Validation report.

Media typeapplication/json
object
status
required

Overall result.

string
Allowed values: pass warning blocker
score
required

1 for pass, 0.7 for warning, 0 for blocker.

number
blockers
required

Problems that prevent publishing (English sentences).

Array<string>
warnings
required
Array<string>
suggestedFixes
required
Array<string>
qualityDimensions
Array<object>
object
key
required
string
label
required
string
status
required
string
Allowed values: pass warning
score
required
number
warnings
Array<string>
suggestedFixes
Array<string>
tokenBudget
object
roleDescChars
required
integer
roleReadmeChars

Characters in roleReadme. Not part of totalChars or estimatedTokens, because the detail introduction is never sent to the model.

integer
roleDetailDescChars
required
integer
roleWelcomeChars
required
integer
customInstructionsChars
required
integer
roleOutputContractChars
required
integer
totalChars
required

Desc + detail + welcome characters.

integer
estimatedTokens
required

Estimated prompt tokens for the card text.

integer
welcomeToDetailRatio
number
profile
required

Size profile label derived from total characters.

string
limits
required

Hard per-field character limits for this card’s language. Non-English cards: 500 / 10000 / 8000 / (500 for zh-Hant and zh-Hans, else 1500) / 2000. English cards: 2500 / 50000 / 10000 / 1500 / 2000.

object
roleDescMaxChars
required
integer
roleDetailDescMaxChars
required
integer
roleWelcomeMaxChars
required
integer
customInstructionsMaxChars
required
integer
roleOutputContractMaxChars
required
integer
roleReadmeMaxChars

Limit for roleReadme: 20000 (English cards 40000).

integer
guidance
Array<string>
nextRecommendedTools
required
Array<string>
Example
{
"status": "pass",
"qualityDimensions": [
{
"status": "pass"
}
]
}

roleId is required.

Media typeapplication/json
object
error
required

Error code (snake_case) or, for legacy handlers, a free-text/localized message.

string
message

Human-readable sentence. Present only on middleware errors and /me, /me/wallet.

string
retryable

Whether retrying may succeed. Present only on middleware errors, /me, /me/wallet and service/share routes.

boolean
required_context_tier

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.

integer
>= 1 <= 5
required_context_tokens

The token budget of required_context_tier for the selected model, for display.

integer
constant_lore_trim_fits

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.

boolean
credits_needed

Only on insufficient_credits: the credits this turn needs before it can start. Absent when the refusal came without an estimate.

integer
credits_available

Only on insufficient_credits: the credits the wallet could set aside for it.

integer
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.

Media typeapplication/json
object
error
required

Error code (snake_case) or, for legacy handlers, a free-text/localized message.

string
message

Human-readable sentence. Present only on middleware errors and /me, /me/wallet.

string
retryable

Whether retrying may succeed. Present only on middleware errors, /me, /me/wallet and service/share routes.

boolean
required_context_tier

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.

integer
>= 1 <= 5
required_context_tokens

The token budget of required_context_tier for the selected model, for display.

integer
constant_lore_trim_fits

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.

boolean
credits_needed

Only on insufficient_credits: the credits this turn needs before it can start. Absent when the refusal came without an estimate.

integer
credits_available

Only on insufficient_credits: the credits the wallet could set aside for it.

integer
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.

Media typeapplication/json
object
error
required

Error code (snake_case) or, for legacy handlers, a free-text/localized message.

string
message

Human-readable sentence. Present only on middleware errors and /me, /me/wallet.

string
retryable

Whether retrying may succeed. Present only on middleware errors, /me, /me/wallet and service/share routes.

boolean
required_context_tier

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.

integer
>= 1 <= 5
required_context_tokens

The token budget of required_context_tier for the selected model, for display.

integer
constant_lore_trim_fits

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.

boolean
credits_needed

Only on insufficient_credits: the credits this turn needs before it can start. Absent when the refusal came without an estimate.

integer
credits_available

Only on insufficient_credits: the credits the wallet could set aside for it.

integer
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
}

record not found or another unclassified error; retryable: true.

Media typeapplication/json
object
error
required

Error code (snake_case) or, for legacy handlers, a free-text/localized message.

string
message

Human-readable sentence. Present only on middleware errors and /me, /me/wallet.

string
retryable

Whether retrying may succeed. Present only on middleware errors, /me, /me/wallet and service/share routes.

boolean
required_context_tier

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.

integer
>= 1 <= 5
required_context_tokens

The token budget of required_context_tier for the selected model, for display.

integer
constant_lore_trim_fits

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.

boolean
credits_needed

Only on insufficient_credits: the credits this turn needs before it can start. Absent when the refusal came without an estimate.

integer
credits_available

Only on insufficient_credits: the credits the wallet could set aside for it.

integer
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
}