t
TasteOS
/api/public/v1
Surfaces

TasteOS API

Base URL: /api/public/v1. JSON in, JSON out. CORS open.

GET
/api/public/v1
API index / discovery
GET
/api/public/v1/domains
List domains + scoring dimensions
GET
/api/public/v1/profiles
List profiles
POST
/api/public/v1/profiles
Create profile
{ "type":"personal", "name":"...", "attributes":{ ... } }
GET
/api/public/v1/profiles/:id
Profile + attributes + blocklist
GET
/api/public/v1/options?domain=culture
List options (filter by domain slug)
POST
/api/public/v1/options
Add option
{ "domain_slug":"tools", "title":"...", "signals":[...], "attributes":{...} }
POST
/api/public/v1/score
Score one option (no persist)
{ "profile_id":"...", "option_id":"..." }
POST
/api/public/v1/recommend
Generate recommendations
{ "profile_id":"...", "domain":"culture", "limit":5 }
GET
/api/public/v1/recommendations?profile_id=&domain=
List stored recommendations
GET
/api/public/v1/recommendations/:id/explain
Per-dimension scores + explanation
POST
/api/public/v1/feedback
Log feedback
{ "profile_id":"...", "recommendation_id":"...", "action":"saved" }

Recommendation output schema

Every item returned by /recommend follows this shape.

{
  "recommendation_id": "uuid",
  "profile_id": "uuid",
  "domain_id": "uuid",
  "recommended_option": "uuid",
  "fit_score": 88,
  "confidence_score": 82,
  "explanation": {
    "why_fits": ["..."],
    "why_may_not": ["..."]
  },
  "matched_signals": ["..."],
  "risks": ["..."],
  "access_path": "...",
  "cost_or_friction": "...",
  "timing_reason": "...",
  "alternatives_considered": [],
  "source_ids": [],
  "created_at": "2026-06-02T00:00:00Z"
}