Skip to content

Add a story

POST
/api/stories
curl --request POST \
--url http://127.0.0.1:8765/api/stories \
--header 'Content-Type: application/json' \
--data '{ "actor": "agent", "answers_questions": [ "Tell me about a time you improved a slow process" ], "company": "Acme", "narrative": { "action": "Moved the runners to Kubernetes and cached the image layers.", "result": "Build time fell 60 percent.", "situation": "Builds took forty minutes and blocked every merge.", "task": "Make the pipeline fast enough to merge several times a day." }, "period": "2023", "raw": "Our builds took forty minutes, so I moved the runners to Kubernetes and cached the layers. It came down to sixteen.", "role": "Staff Engineer", "sources": [ { "job_identity": "https://boards.greenhouse.io/acme/jobs/101", "question_id": "tooling:kubernetes" } ], "tags": [ "ci", "delivery" ], "title": "Cut CI time 60% at Acme" }'

Add a story. Answers 201 with the story. Local only: no model reads it now. 409 story_exists (with the current story in the error) when that id is taken: change it with PUT. 422 personal_info_refused when any text holds an email, phone, link or street address. Example, an agent turns a substantial reply into a story and a later assessment uses it: after the user says yes to “Want me to make this a story?”, POST this route with the request example; then POST /api/assess for a posting that asks for Kubernetes: the story is in that assessment’s prompt, the row’s resume_evidence reads Story bank story:60_acme_ci_cut_time: ..., and GET /api/stories/story:60_acme_ci_cut_time lists that job under jobs with kind used. Stories belong to the user, not to a profile. Each story: story_id, title, company, role, period (rough is fine), raw (the user’s own words, kept as said), narrative ({situation, task, action, result}, loosely STAR, every part optional), tags, answers_questions (the interview questions it answers), sources ([{question_id, job_identity}]: the job question that triggered it), jobs (the postings whose assessment cited it: kind used), written_by (operator | agent), created_at, updated_at, revision (send it back on PUT and DELETE) and the last writes in history. An assessment searches the stories locally for each job and puts only the few that match the posting into its prompt as evidence. 0.1.10.7: the write also queues the background pipeline (tailored resume, assessment against it, Scout ATS score, Scout label) for every job of an active profile whose stored assessment left open a question this answers; at most pipeline.auto_jobs_per_trigger (10) jobs run, the rest wait for an approval (GET /api/pipeline/approvals). The pipeline’s tailoring replaces only a tailored resume the pipeline itself made: one tailored on demand (POST /api/tailored-resumes) or with a line chosen or edited (PUT /api/tailored-resumes/lines) is kept as it is, its updated_at unchanged, and the assessment, the Scout ATS score and the Scout label are made against it. Read what was queued with GET /api/pipeline.

Media typeapplication/json
object
actor

Who writes: recorded as written_by. Also the X-GigAI-Actor header. Without either, a write from the Scout UI (a browser page of this server) is the operator’s and any other loopback write is the agent’s.

string
Allowed values: operator agent
answers_questions

The interview questions this story answers (at most 12).

array
company

Where it happened.

string
narrative

{situation, task, action, result}: loosely STAR, every part an optional string.

object
period

When; rough is fine.

string
raw

The user’s own words, kept as said (at most 16000 characters).

string
role

The role held.

string
sources

[{question_id, job_identity}]: the job question that triggered the story.

array
story_id

The story’s id (story:<words>); omitted = story:<the title's first words>.

string
tags

Tags (lowercase, at most 12).

array
title
required

“Cut CI time 60% at Acme” (at most 200 characters).

string
Example
{
"actor": "agent",
"answers_questions": [
"Tell me about a time you improved a slow process"
],
"company": "Acme",
"narrative": {
"action": "Moved the runners to Kubernetes and cached the image layers.",
"result": "Build time fell 60 percent.",
"situation": "Builds took forty minutes and blocked every merge.",
"task": "Make the pipeline fast enough to merge several times a day."
},
"period": "2023",
"raw": "Our builds took forty minutes, so I moved the runners to Kubernetes and cached the layers. It came down to sixteen.",
"role": "Staff Engineer",
"sources": [
{
"job_identity": "https://boards.greenhouse.io/acme/jobs/101",
"question_id": "tooling:kubernetes"
}
],
"tags": [
"ci",
"delivery"
],
"title": "Cut CI time 60% at Acme"
}

Success.

Media typeapplication/json
object
schema_version
required
Allowed value: scout-stories-response:1
key
additional properties
any
Example
{
"schema_version": "scout-stories-response:1",
"story": {
"answers_questions": [
"Tell me about a time you improved a slow process"
],
"company": "Acme",
"created_at": "2026-10-02T15:00:00.000000Z",
"history": [
{
"action": "added",
"at": "2026-10-02T15:00:00.000000Z",
"by": "agent"
}
],
"jobs": [],
"narrative": {
"action": "Moved the runners to Kubernetes and cached the image layers.",
"result": "Build time fell 60 percent.",
"situation": "Builds took forty minutes and blocked every merge.",
"task": "Make the pipeline fast enough to merge several times a day."
},
"period": "2023",
"raw": "Our builds took forty minutes, so I moved the runners to Kubernetes and cached the layers. It came down to sixteen.",
"revision": 1,
"role": "Staff Engineer",
"sources": [
{
"job_identity": "https://boards.greenhouse.io/acme/jobs/101",
"question_id": "tooling:kubernetes"
}
],
"story_id": "story:60_acme_ci_cut_time",
"tags": [
"ci",
"delivery"
],
"title": "Cut CI time 60% at Acme",
"updated_at": "2026-10-02T15:00:00.000000Z",
"written_by": "agent"
}
}

Forbidden / forbidden_origin: loopback peer and Host 127.0.0.1:<port> or localhost:<port> only (Origin too on writes).

Media typeapplication/json
object
error
required
object
allowed_keys
Array<string>
code
required
string
message
required
string
key
additional properties
any
Examplegenerated
{
"error": {
"allowed_keys": [
"example"
],
"code": "example",
"message": "example"
}
}

Target_unavailable

Media typeapplication/json
object
error
required
object
allowed_keys
Array<string>
code
required
string
message
required
string
key
additional properties
any
Example
{
"error": {
"code": "target_unavailable",
"message": "..."
}
}

Story_exists

Media typeapplication/json
object
error
required
object
allowed_keys
Array<string>
code
required
string
message
required
string
key
additional properties
any
Example
{
"error": {
"code": "story_exists",
"message": "..."
}
}

Unsupported_media_type: writes need Content-Type: application/json.

Media typeapplication/json
object
error
required
object
allowed_keys
Array<string>
code
required
string
message
required
string
key
additional properties
any
Examplegenerated
{
"error": {
"allowed_keys": [
"example"
],
"code": "example",
"message": "example"
}
}

Unknown_key, wrong_type, invalid_value, personal_info_refused

Media typeapplication/json
object
error
required
object
allowed_keys
Array<string>
code
required
string
message
required
string
key
additional properties
any
Example
{
"error": {
"code": "unknown_key",
"message": "..."
}
}