Skip to main content
POST https://api.humalike.com/v1/personas/actions/validate
Check one or more personas against deterministic quality gates and get back a structured report. Each persona is run through a schema gate (every field the blueprint declares is present and well-formed) and the blueprint’s constraint gates (the consistency rules a believable member must satisfy, for example that age is at least six years past the year they started). When you send more than one persona, the report also includes batch-level checks — a diversity summary and per-field marginal fidelity. Pass a blueprint to check personas against the exact field set and consistency rules they were generated from. Omit it to run the structural checks alone. Use this to quality-check personas you have — your own, or the personas returned by Personas and Enhance. This endpoint is asynchronous, in the same shape as Personas: the POST returns 200 OK with an id, and you GET the evaluation repository route until the report is ready.

Authorization

Authorization
string
required
Your bearer token: Bearer <token>. See Authentication.

Request body

personas
object[]
required
The personas to check. Each entry is a persona in the shape returned by Personas: persona_id, a flat fields map, system_prompt, and markdown. Must contain at least one persona.
blueprint
object
Optional. The population blueprint the personas were generated from. When present, personas are checked against its field set, its ordered_values, and its constraints, and marginal fidelity is scored against its declared distributions.
Request
{
  "personas": [
    {
      "persona_id": "p_01",
      "fields": {
        "region": "KR",
        "rank": "Diamond",
        "main_role": "jungle",
        "hours_per_week": "34",
        "name": "Mara 'Nocturne' Velez",
        "backstory": "Picked up jungle one long winter and never stopped counting wards."
      },
      "system_prompt": "You are Mara 'Nocturne' Velez, a late-night Diamond jungle main...",
      "markdown": "# Mara 'Nocturne' Velez\n\n_Late-night Diamond jungle main..._"
    }
  ],
  "blueprint": {
    "domain": "lol_player",
    "order": ["region", "rank", "main_role", "hours_per_week"],
    "fields": [
      { "name": "region", "kind": "categorical", "parents": [], "categorical": { "weights": { "NA": 0.5, "KR": 0.5 } } },
      { "name": "rank", "kind": "categorical", "parents": [], "categorical": { "weights": { "Gold": 0.6, "Diamond": 0.4 } }, "ordered_values": ["Gold", "Diamond"] }
    ],
    "constraints": [
      { "name": "hours_nonneg", "lhs": "hours_per_week", "op": ">=", "rhs": "0" }
    ]
  }
}

Start an evaluation

The POST returns 200 OK with an id used with the evaluation repository route.
id
string
The evaluation’s identifier. Use it to poll for the report.
status
string
Always pending in this response — the evaluation has been accepted and queued.
200 OK
{
  "id": "5b91c0a3-f2aa-4fe1-9f2e-59f6a8a05801",
  "status": "pending"
}
The gates run deterministically over the personas you send and make no generation calls, so an evaluation finishes quickly — but it is still asynchronous and polled by id, the same as population generation. A constraint that references a field that is missing or not numeric is reported as not applicable rather than failing.

Poll for the report

GET https://api.humalike.com/v1/personas/repositories/Evaluation/by-id/{id}
Call GET with the returned id until status is succeeded or failed.
id
string
The evaluation’s identifier, the same value you started.
status
string
Where the evaluation is in its lifecycle. One of pending, running, succeeded, or failed. Keep polling on pending and running; stop on succeeded and failed.
result
object
The evaluation report, present only when status is succeeded. Its shape is described under The report below.
error
string
A stable failure category such as provider_error. Present only when status is failed.
A succeeded evaluation means the gates ran to completion — it does not mean the personas passed. Read result.passed for the quality verdict. A failed status means the evaluation itself could not run (for example a malformed request body), not that a persona failed a gate.

The report

When status is succeeded, the poll carries the report under result.
passed
boolean
The overall verdict: true only when every gate on every persona and every batch-level gate passed.
gates
object[]
Batch-level gates not tied to a single persona — for example a diversity floor or a marginal-fidelity check across the whole set.
scorecards
object[]
One scorecard per input persona.
diversity
object
How varied the set is, in the same shape as the population diversity report. Present for multi-persona inputs.
marginals
object[]
Per-field marginal fidelity, in the same shape as the population marginals. Present when a blueprint is supplied and the input holds more than one persona.
When the evaluation succeeds, this report is the value of result:
200 OK (succeeded)
{
  "id": "5b91c0a3-f2aa-4fe1-9f2e-59f6a8a05801",
  "status": "succeeded",
  "result": {
    "passed": true,
    "gates": [
      { "name": "diversity_floor", "passed": true, "score": 0.19, "detail": "mean similarity below threshold" }
    ],
    "scorecards": [
      {
        "persona_id": "p_01",
        "gates": [
          { "name": "schema", "passed": true, "score": null, "detail": "all blueprint fields present" },
          { "name": "hours_nonneg", "passed": true, "score": null, "detail": "hours_per_week=34 >= 0 (0)" }
        ]
      }
    ],
    "diversity": {
      "max_pairwise_similarity": 0.41,
      "mean_pairwise_similarity": 0.19,
      "duplicate_pairs": 0
    }
  }
}
When a persona fails a gate, the evaluation still succeededresult.passed is false and the failing gate carries a detail explaining why:
200 OK (persona failed a gate)
{
  "id": "5b91c0a3-f2aa-4fe1-9f2e-59f6a8a05801",
  "status": "succeeded",
  "result": {
    "passed": false,
    "gates": [],
    "scorecards": [
      {
        "persona_id": "p_02",
        "gates": [
          { "name": "schema", "passed": true, "score": null, "detail": "all blueprint fields present" },
          { "name": "hours_nonneg", "passed": false, "score": null, "detail": "hours_per_week=-3 >= 0 (0)" }
        ]
      }
    ]
  }
}
A succeeded evaluation with result.passed: false is a successful run reporting a quality failure; inspect each scorecards[].gates entry and the batch gates for the ones whose passed is false.

When the evaluation fails

If the evaluation itself cannot run — for example a malformed request body — the poll returns 200 OK with status: "failed" and an error instead of a result:
200 OK (failed)
{
  "id": "5b91c0a3-f2aa-4fe1-9f2e-59f6a8a05801",
  "status": "failed",
  "error": "provider_error"
}
Branch on the poll’s status and error, not on the HTTP status of the poll — a failed evaluation is reported with 200 OK. A persona failing a gate is not a failed evaluation; that is a succeeded evaluation with result.passed: false (see above).

Errors

The POST rejects a bad request before any evaluation starts:
StatusCodeWhen
401UNAUTHORIZEDThe bearer token is missing, invalid, or expired.
402PAYMENT_REQUIREDYour credit balance can’t cover the request. See Credits and billing.
422validation_failedpersonas is missing, empty, or a persona is malformed.
See Errors for the full envelope shape.

Example

Start the evaluation, poll its repository route until it succeeds, then read the report from result.
# Start the evaluation — returns 200 with an id.
curl https://api.humalike.com/v1/personas/actions/validate \
  -H "Authorization: Bearer $HUMALIKE_TOKEN" \
  -H "Content-Type: application/json" \
  -d @population.json

# Poll the evaluation (repeat until status is "succeeded" or "failed").
curl https://api.humalike.com/v1/personas/repositories/Evaluation/by-id/5b91c0a3-f2aa-4fe1-9f2e-59f6a8a05801 \
  -H "Authorization: Bearer $HUMALIKE_TOKEN"

Next

  • Personas — generate a population to validate.
  • Enhance a persona — improve a persona, then re-validate it.
  • Errors — the full error model and how to recover.