API Reference

pref0 learns user preferences from conversations. Send your agent's chat history to /track after each session. Query learned preferences from /profiles before your agent responds. The more conversations you send, the better it gets.

Base URL

https://api.pref0.com

Authentication

All /v1 endpoints require a Bearer token in the Authorization header. Your API key is scoped to your organization. All users within your org share the same key.

Header
Authorization: Bearer pref0_sk_...

Returns 401 if the key is missing, malformed, or invalid.

How learning works

pref0 isn't a key-value store. It extracts preferences from natural conversation, especially from corrections, and compounds them over time.

What pref0 extracts from a single conversation

Example conversation
user:     Set up a new React project for me
assistant: Here's a new project using npm and JavaScript...
user:     Use pnpm, not npm. And TypeScript, not JavaScript.
assistant: Updated! Here's the project using pnpm and TypeScript...
user:     Also deploy it to Vercel
assistant: Done. Here's the Vercel config...
What pref0 learns
preferences: [
  { key: "package_manager",    value: "pnpm",       confidence: 0.70 },  // explicit correction
  { key: "language",           value: "typescript",  confidence: 0.70 },  // explicit correction
  { key: "deploy_target",      value: "vercel",      confidence: 0.40 }   // implied preference
]

patterns: [
  { pattern: "prefers explicit tooling choices", confidence: 0.30 }
]

Notice the confidence difference: “Use pnpm, not npm” is an explicit correction (0.70), while “deploy it to Vercel” is an implied preference (0.40). Corrections are the highest-signal data.

How preferences compound over time

The same preference showing up across multiple conversations increases its confidence. This is how pref0 distinguishes a one-off request from a genuine learned preference.

Confidence over sessions
Session 1:  "Use TypeScript, not JavaScript"    → language: typescript (0.70)
Session 4:  "Write it in TS please"              → language: typescript (0.85)
Session 7:  user writes TypeScript in code block  → language: typescript (1.00)

The preference is now fully learned. Your agent
should always default to TypeScript for this user.
Signal typeStarting scoreExample
Explicit correction0.70“Use Tailwind, not Bootstrap”
Implied preference0.40“Deploy it to Vercel”
Behavioral pattern0.30User consistently asks for shorter responses
Each repeated signal+0.15Same preference in a different conversation

Scores are capped at 1.0. We recommend filtering to preferences with confidence >= 0.5 when injecting into system prompts. This ensures only genuinely learned preferences affect behavior.

POST/v1/track

Send a conversation so pref0 can learn from it. pref0 analyzes the messages to find corrections (“use X instead of Y”), explicit instructions (“always use metric”), and implied preferences. Extracted preferences are merged into the user's existing profile. If pref0 has seen this preference before, its confidence goes up.

Request body

userIdstringrequired

Your identifier for the user. Preferences are learned and stored per userId within your org.

messagesarrayrequired

Array of message objects. Each must have role (string) and content (string). Extra fields like tool_call_id are allowed and ignored. At least 1 message required.

Example: user corrects the agent
curl -X POST https://api.pref0.com/v1/track \
  -H "Authorization: Bearer pref0_sk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "userId": "user_abc123",
    "messages": [
      { "role": "user", "content": "Help me set up a new API project" },
      { "role": "assistant", "content": "Here is a new Express project using JavaScript and npm..." },
      { "role": "user", "content": "Use TypeScript, not JavaScript. And use pnpm." },
      { "role": "assistant", "content": "Updated! Here is the project with TypeScript and pnpm..." },
      { "role": "user", "content": "Add a Dockerfile too, we always deploy with Docker" },
      { "role": "assistant", "content": "Here is the Dockerfile..." }
    ]
  }'
Response 200
{
  "preferencesExtracted": 3,
  "patternsExtracted": 1
}

From this conversation, pref0 learns three preferences: language → typescript (0.70, explicit correction), package_manager → pnpm (0.70, explicit correction), and deployment → docker (0.40, implied). If this user has corrected to TypeScript before, that preference is now reinforced.

GET/v1/profiles/:userId

Retrieve the learned preference profile for a user. Returns preferences with confidence scores (how strongly pref0 has learned this) and behavioral patterns. Call this before your agent responds and inject high-confidence preferences into the system prompt.

Path parameters

userIdstringrequired

The user identifier used when tracking conversations.

Example request
curl https://api.pref0.com/v1/profiles/user_abc123 \
  -H "Authorization: Bearer pref0_sk_..."
Response 200
{
  "userId": "user_abc123",
  "preferences": [
    {
      "key": "language",
      "value": "typescript",
      "confidence": 0.85
    },
    {
      "key": "package_manager",
      "value": "pnpm",
      "confidence": 0.85
    },
    {
      "key": "css_framework",
      "value": "tailwind",
      "confidence": 0.70
    },
    {
      "key": "deployment",
      "value": "docker",
      "confidence": 0.55
    },
    {
      "key": "response_format",
      "value": "concise_bullet_points",
      "confidence": 0.40
    }
  ],
  "patterns": [
    {
      "pattern": "prefers explicit tooling choices over defaults",
      "confidence": 0.45
    }
  ]
}

This user has been correcting their agent for a while. Language and package manager are high-confidence learned preferences (seen in multiple sessions). CSS framework was corrected once. Response format is still low confidence, pref0 noticed it but hasn't seen it enough to be sure. Returns empty arrays if no profile exists yet.

DELETE/v1/profiles/:userId

Reset a user's learned preferences. Deletes the entire profile. The next /track call will start learning from scratch. Use for preference resets or GDPR data deletion.

Path parameters

userIdstringrequired

The user identifier to delete.

Example request
curl -X DELETE https://api.pref0.com/v1/profiles/user_abc123 \
  -H "Authorization: Bearer pref0_sk_..."
Response 204
(no content)
GET/v1/usage

Get your organization's API usage stats. Tracks total /track requests (each conversation your agent learns from).

Example request
curl https://api.pref0.com/v1/usage \
  -H "Authorization: Bearer pref0_sk_..."
Response 200
{
  "orgId": "org_xyz",
  "requestCount": 1482,
  "lastRequestAt": "2026-02-06T14:32:00.000Z"
}

Errors

pref0 uses standard HTTP status codes. All error responses return JSON with an error field.

StatusMeaning
400Validation error. Check the details array for specifics.
401Missing or invalid API key.
500Internal server error.
Error response
{
  "error": "Validation error",
  "details": [
    {
      "code": "too_small",
      "minimum": 1,
      "path": ["messages"],
      "message": "Array must contain at least 1 element(s)"
    }
  ]
}

Quick start

Two integration points: track conversations after they end (so pref0 can learn), and query preferences before your agent responds (so it can use what it has learned).

TypeScript
const PREF0_API = "https://api.pref0.com";
const PREF0_KEY = process.env.PREF0_API_KEY;

// After a conversation ends, send it so pref0 can learn
async function trackConversation(userId: string, messages: any[]) {
  await fetch(`${PREF0_API}/v1/track`, {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${PREF0_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ userId, messages }),
  });
}

// Before your agent responds, fetch what pref0 has learned
async function getLearnedPreferences(userId: string) {
  const res = await fetch(`${PREF0_API}/v1/profiles/${userId}`, {
    headers: { "Authorization": `Bearer ${PREF0_KEY}` },
  });
  return res.json();
}

// Inject learned preferences into the system prompt
async function buildSystemPrompt(userId: string, basePrompt: string) {
  const profile = await getLearnedPreferences(userId);

  // Only use high-confidence learned preferences
  const learned = profile.preferences
    .filter((p: any) => p.confidence >= 0.5)
    .map((p: any) => `- ${p.key}: ${p.value} (confidence: ${p.confidence})`)
    .join("\n");

  if (!learned) return basePrompt;

  return `${basePrompt}

## Learned user preferences
The following preferences have been learned from this user's
previous conversations. Follow them unless explicitly told otherwise:
${learned}`;
}

That's it. Every conversation your agent has now contributes to a smarter next one. Corrections like “use Tailwind, not Bootstrap” get captured automatically and injected into future sessions. The user never has to repeat themselves.