Spaces:
Sleeping
09 - API Reference
Base URL in local dev:
http://127.0.0.1:7860. The Vite dev server athttp://127.0.0.1:5173proxies the same paths.
Authentication
Public app endpoints:
GET /health
POST /turn
POST /turn/stream
POST /feedback
GET /sessions/*
GET /users/*
DELETE /sessions/*
Protected operational endpoints:
/config*
/admin/*
/analytics/*
Protected endpoints require one of:
X-APE-Admin-Token: <APE_ADMIN_TOKEN>
Authorization: Bearer <APE_ADMIN_TOKEN>
If APE_ADMIN_TOKEN is not configured on the server, protected endpoints return
503. If the header is missing or wrong, they return 401.
Core Flow
GET /health
{ "status": "ok" }
POST /turn
Generate one assistant response using the non-streaming path.
Request:
{
"user_id": "alex_retiree",
"session_id": "optional-session-id",
"query": "Compare Roth IRA vs Traditional IRA",
"generate_response": true
}
Response:
{
"response_id": "resp_...",
"session_id": "sess_...",
"assistant_message_id": "msg_...",
"classification": {
"intent": "Comparison",
"topic": "roth_vs_traditional_ira",
"signal": "no_signal"
},
"selection": {
"selected_strategy": "comparison_table",
"strategies_available": [
"standard_llm",
"comparison_table",
"pros_cons_table",
"bullet_contrast"
],
"ucb_at_selection": 1.522,
"policy_version": "v1"
},
"answer": "| Feature | Roth IRA | Traditional IRA | ...",
"rendered_format": "comparison_table",
"timings_ms": {
"total": 2100.4
}
}
POST /turn/stream
Same request body as /turn, but returns Server-Sent Events with
Content-Type: text/event-stream.
Event payloads are JSON objects sent as SSE data: lines.
metadata event:
{
"event": "metadata",
"response_id": "resp_...",
"session_id": "sess_...",
"intent": "Comparison",
"topic": "roth_vs_traditional_ira",
"selected_strategy": "comparison_table",
"candidate_strategies": ["standard_llm", "comparison_table"],
"select_timings_ms": {}
}
delta event:
{ "event": "delta", "text": "partial raw model text" }
done event:
{
"event": "done",
"response_id": "resp_...",
"session_id": "sess_...",
"assistant_message_id": "msg_...",
"answer": "final parsed answer",
"rendered_format": "comparison_table",
"format_compliance": 1,
"selection": {},
"classification": {},
"timings_ms": {}
}
error event:
{ "event": "error", "message": "..." }
Streaming and non-streaming paths both write ape_messages, ape_turn_record,
and pending format compliance signals.
POST /feedback
Append a UI signal to one response. The response may finalize immediately or queue the signal for later finalization.
Request:
{
"response_id": "resp_...",
"user_id": "alex_retiree",
"signal": "copy_save"
}
Possible response when queued:
{
"status": "queued",
"response_id": "resp_..."
}
Possible response when applied:
{
"status": "applied",
"response_id": "resp_...",
"signal": "pattern_engaged_positive",
"reward_category": "weak_positive",
"normalized_reward": 0.5,
"strategy_row_after": {
"strategy": "comparison_table",
"count": 4,
"avg_reward": 0.625,
"cached_ucb": 1.457
}
}
Possible response with no bandit update:
{
"status": "applied_no_bandit_update",
"response_id": "resp_...",
"signal": "thumbs_up",
"reward_category": null,
"normalized_reward": null
}
Possible rejected response:
{
"status": "rejected",
"response_id": "resp_...",
"reason": "already_finalized",
"current_status": "APPLIED"
}
Feedback statuses:
| Status | Meaning |
|---|---|
queued |
Signal buffered; turn remains PENDING |
applied |
Turn finalized and bandit updated |
applied_no_bandit_update |
Turn finalized but no format-relevant reward existed |
rejected |
Missing response, wrong user, already finalized, or race |
skipped |
Unknown signal |
Sessions and History
GET /sessions/{session_id}/messages?user_id=X&limit=200
Returns raw chat messages for one session, scoped to the requesting user.
user_id is required.
GET /sessions/{session_id}/turns?user_id=X&limit=100
Returns ape_turn_record rows for one session, scoped to the requesting user.
user_id is required.
GET /users/{user_id}/sessions?limit=20
Returns recent session summaries for a user.
GET /users/{user_id}/latest-session
Returns:
{ "session_id": "sess_..." }
or:
{ "session_id": null }
GET /users/{user_id}/responses?limit=50
Returns recent turn records for one user.
DELETE /sessions/{session_id}?user_id=X
Deletes one user's messages and response records for that session. Bandit state is preserved.
Config Reads
All config endpoints require admin token.
| Endpoint | Purpose |
|---|---|
GET /config/intents |
List intents |
GET /config/strategies |
List strategies |
GET /config/policies |
List policies |
GET /config/signal-rules |
List signal routing rules |
GET /config/reward-scale |
List reward categories |
GET /config/instructions?strategy_id=X&status=Y |
List instruction versions |
GET /config/offers?status=Y |
List outreach policies |
Config Writes
POST /config/intents
{
"intent_id": "Comparison",
"description": "User wants two or more options compared side by side.",
"changed_by": "admin_user"
}
POST /config/strategies
{
"strategy_id": "comparison_table",
"format_type": "comparison_table",
"changed_by": "admin_user"
}
POST /config/signal-rules
{
"signal_name": "format_change_request",
"format_relevant": true,
"content_relevant": false,
"format_category": "strong_negative",
"content_category": null,
"source": "llm",
"feature_id": 1,
"expected_frequency": "rare",
"evidence_quality": "high",
"consumers": ["bandit", "instruction_quality"],
"changed_by": "admin_user"
}
POST /config/reward-scale
{
"category": "strong_positive",
"normalized_reward": 1.0,
"changed_by": "admin_user"
}
raw_reward is not part of the current request model.
POST /config/policies
{
"domain": "finance",
"intent": "Comparison",
"topic": "_default",
"strategy_id": "comparison_table",
"policy_version": "v1",
"exploration_constant": 1.0,
"changed_by": "admin_user"
}
POST /config/instructions
{
"strategy_id": "comparison_table",
"version": "v2",
"instruction_text": "Format as a markdown table comparing the options.",
"instruction_uri": null,
"activate": true,
"changed_by": "admin_user"
}
POST /config/instructions/activate?strategy_id=X&version=Y&changed_by=admin_user
Activates an existing instruction version.
POST /config/status
{
"entity_type": "strategy",
"entity_id": "comparison_table",
"version": "v1",
"status": "INACTIVE",
"changed_by": "admin_user"
}
version is required for instruction rows and optional for most other entity
types.
POST /config/offers
{
"topic": "retirement_accounts",
"offer_type": "retirement_planning_consultation",
"description": "Schedule a 30-minute planning call",
"min_interest_score": 0.8,
"weight_frequency": 0.4,
"weight_recency": 0.25,
"weight_engagement": 0.25,
"weight_followup": 0.1,
"changed_by": "admin_user"
}
Config Deletes
| Endpoint | Purpose |
|---|---|
DELETE /config/intents/{intent_id} |
Delete an intent |
DELETE /config/strategies/{strategy_id} |
Delete a strategy and its instructions |
DELETE /config/signal-rules/{signal_name} |
Delete a signal rule |
DELETE /config/reward-scale/{category} |
Delete a reward value |
DELETE /config/policies?intent=Y&topic=Z&strategy_id=S |
Delete a policy |
DELETE /config/instructions/{strategy_id}/{version} |
Delete an instruction version |
DELETE /config/offers/{topic} |
Delete an outreach policy |
All deletes are audited.
Admin and Ops
All admin endpoints require admin token.
| Endpoint | Purpose |
|---|---|
DELETE /admin/clear-user/{user_id} |
Remove one user's runtime data |
DELETE /admin/clear-all |
Clear runtime collections while preserving config/audit |
POST /admin/seed |
Seed default config |
GET /admin/db-snapshot?user_id=X&limit=N |
Diagnostic snapshot |
GET /admin/bandit-state?user_id=X&only_pulled=true |
Inspect bandit rows |
DELETE /admin/bandit-state/cell?user_id=X&domain=D&intent=I&topic=T&strategy=S |
Delete one bandit cell or one arm when strategy is supplied |
GET /admin/audit?date=YYYY-MM-DD&limit=N |
Audit log |
There is no /admin/rebuild-bandit endpoint. UCB cache refresh happens during
feedback finalization, and bulk repair should be done with a script if needed.
Analytics
All analytics endpoints require admin token.
| Endpoint | Purpose |
|---|---|
POST /analytics/recompute?days=N |
Rebuild derived collections from ape_turn_record |
GET /analytics/user-interests?user_id=X&limit=K&refresh=bool |
User topic interest |
GET /analytics/topic-users?topic=X&limit=K&min_score=Y |
Users interested in topic |
GET /analytics/trends?days=N&limit=K&refresh=bool |
Trending topics |
GET /analytics/topic-timeseries?topic=X&days=N |
Daily trend for one topic |
GET /analytics/platform-timeseries?days=N |
Daily platform activity |
GET /analytics/topics-timeseries?days=N&top_n=K |
Daily series for top topics |
GET /analytics/user-timeseries?user_id=X&days=N |
Daily user activity |
GET /analytics/offers/{user_id}?domain=Y |
Outreach recommendations |
GET /analytics/customer-health?days=N&cohort_weeks=K |
Retention/satisfaction health |
GET /analytics/rag-quality?days=N&min_turns=K&sample_limit=S |
Content-quality indicators |
GET /analytics/instruction-quality?days=N&min_turns=K&sample_limit=S |
Format/instruction quality |
GET /analytics/strategy-performance?user_id=X&min_pulls=N |
Strategy performance tiers |
GET /analytics/platform-overview?days=N&top_n=K |
Dashboard overview |
GET /analytics/active-users?days=N&min_interest=X&limit=K |
Outreach roster |
GET /analytics/user-profile?user_id=X&domain=Y |
12-facet user profile |
GET /analytics/cognitive-facets?user_id=X&min_interactions=N |
Facets; omit user_id for global |
Status Codes
| Code | Meaning |
|---|---|
200 |
Success |
204 |
Successful delete with no body |
400 |
Invalid request value |
401 |
Protected endpoint missing valid admin token |
404 |
Resource not found |
422 |
FastAPI validation error, such as missing required query param |
500 |
Store/orchestrator not initialized or unexpected server error |
503 |
Protected endpoint called while APE_ADMIN_TOKEN is not configured |
Feedback errors are usually returned as 200 with status: "rejected" or
status: "skipped" so the UI can show clean inline state without treating user
feedback races as transport failures.