LIFELINE engine

The right help, for this moment.

Matches a need to reviewed resources: songs, verses, prayers, devotionals, teaching and stories.

Match a need to resources

Funded account or a bound service bearer120 calls / hour per accountusually 10–40s for a free-text need; ~1s for structured fields only; hard budget 270s (a slow upstream returns a retryable 504)

A need in plain words or structured fields → ranked resources.

  • · A need that reads as a crisis, abuse or something for an admin comes back in `routing` with no resources; an ask to add a resource comes back as resource_submission.
  • · A request with free-text language returns a retryable 503 when it can't be read right now; enum-only fields (category / tracks / tone) still work.
  • · deliveryVisibility private: don't tie it to the person in a public room.
  • · A named title that isn't in the catalog returns an empty list.

Request body

FieldTypeMeaning
needstring (3–500)The need in the person's words. Required unless you give structured fields.
categorystring | nullworship_song · christian_song · support_song · scripture_verse · guided_prayer · journal_prompt · bible_study_plan · teaching_video · testimony_video. null = any medium. Overrides the interpreter.
tracksstring[]Struggle roots: anger · despair · fear_doubt · harmful_habit · sexual_habit · friend_support · faith_foundation.
topicsstring[]Short topic words (anxiety, grief, birthday…).
toneenergizing | comforting | reverent | nullSong tone. Overrides the interpreter.
title / creatorstringA named ask ("play X by Y"). Exact-identity lookups never fall back to a generic pick.
surfaceweb | discord_public | discord_dm | partnerWhere it will be shown. On Discord, a row blocked for embedding comes back as a plain link (direct ask) or is excluded (inline). Default web.
contextdirect_request | inline_placementdirect_request: a person asked — the LLM reranker judges fit. inline_placement: auto-embedding inside a support flow — deterministic and narrow (never a worship song in the practical lane). Default direct_request.
limit1–8How many picks to return. Default 3.
excludeResourceKeys / tryDifferentstring[] / boolean"Show me another": pass the previous tryDifferent.excludeResourceKeys back and set tryDifferent true.

Response

FieldTypeMeaning
routing{ kind, fromClassifier, signals[], childSafetyAlerts, submission, message }How the safety classifier routed a free-text need: resource (served); support / admin_review / child_safety (NOT served — the message says what Shepherd would do instead; resources is empty); resource_submission (an ask to ADD a resource — not served either; submission carries the named title / creator / url for the submission workflow). not_checked for an enum-only request (no caller language).
resources[]Resource[]Ranked picks: resourceKey, category, title, creator, blurb (user-facing), sourceUrl, embedUrl, thumbnailUrl, durationSeconds, topics, journeyTracks, deliveryVisibility (public / private — private means the bot DMs it rather than posting in a channel), spiritualDepth (reviewed 0 secular · ~0.5 approachable christian · ~0.9 worship, null when unreviewed), placementSafety (the served row's placement-safety facts verbatim — spiritualDepth, placementFitStored, legacySafety{introOutreachSafe, initialOutreachSafe, supportEnrichmentSafe, practicalEnrichmentSafe} — or null when the catalog service does not report them; a lane-aware consumer applies the bot's export predicate itself), rank, score, matchReasons, verse (verses only: the card Shepherd renders — reference, line (our SHEP translation, else the public-domain WEB text), fullText (WEB), attribution, sourceLabel, art{url, alt} (clean VerseArt, or null while pending), readUrl (our /verse reader); null when the row has no reference).
interpretationobjectsource (classifier / llm / caller), model, query (the fields the serve ran with), proposed (what the interpreter suggested before your overrides), engine (what the engine itself understood).
rankedBy / whyThese"llm_rerank" | "deterministic" | null / string | nullllm_rerank with the reranker's one-paragraph reasoning, or deterministic (identity lookups, inline placement, or a reranker outage). BOTH are null on a routing-only response (a need the safety classifier routed away is never ranked, because it is never served).
retryKind / relaxedMatchexact | same_artist | wandered_fresh | recycled / booleanHow a "show me another" was satisfied and whether the requested identity was relaxed.
tryDifferent.excludeResourceKeys / queuestring[] / string[]What to exclude on the next ask, and the reranker's ranked tail below the shown picks.
dedupe"fresh" | "in_flight" | "cached" | "undeduped"Which dedupe path this call took (identical requests from YOUR account share one run, so a double-tap or retry is not charged twice): fresh ran it, in_flight joined one already running, cached got a recent result back, undeduped means the dedupe layer was degraded and this call ran on its own. Nothing is ever shared across accounts.

Try it

Sign in with a funded account to send.

POST /api/public/lifeline/match
Response
// the response will appear here

Call it from your code

server-to-server (service bearer)
curl -sS -X POST 'https://<your-shepherd-host>/api/public/lifeline/match' \
  -H 'Authorization: Bearer $SHEPHERD_API_KEY' \
  -H 'content-type: application/json' \
  --data-binary @- <<'JSON'
{
  "need": "something for when I'm scared at night and can't sleep",
  "surface": "web"
}
JSON

Never ship the service key to a browser.

Versions

Every response from every Shepherd engine — a result, an estimate, a refusal or an error — says which versions produced it, under the same three headers on every engine. A JSON object body carries the same three as `versions: { api, engine, engines }`.

Response headers

FieldTypeMeaning
X-API-Versionrequiredv<N>The API version: the request/response contract, the same for every engine ("v1"). It changes only for a breaking change to that contract.
X-Engine-Versionrequired<engine>-engine/<line>-v<N>The responding engine's version ("truth-engine/research-v32", "verse-engine/card-v1"). The number goes up whenever the engine's behaviour changes: its prompts, its models, its retrieval or its rules.
X-Engine-VersionsrequiredJSON objectThe versions of the engines this response's own work called, by engine name ({"lifeline": "lifeline-engine/match-v1", "truth": "truth-engine/research-v32"} from a FORMATION study; {} when it called none — a refusal before any work, or a result served from a recent identical run).
  • · Read as a label, a version is the engine's name, its number and the API's: "VERSE v3 · API v1". The example results on every engine page are labelled this way, with the versions each was captured under.
  • · A result stored for later (a TRUTH read, a FORMATION study's reviews) keeps the version that produced it; the headers name the versions answering now.
  • · TRUTH's assessment endpoints return the frozen assessment contract, which carries its own provenance.truth_engine_version, so there the versions are in the headers only. The open contract endpoint runs the deterministic stub and answers as truth-engine/stub-v0.