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.
https://api.pref0.comAll /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.
Authorization: Bearer pref0_sk_...Returns 401 if the key is missing, malformed, or invalid.
pref0 isn't a key-value store. It extracts preferences from natural conversation, especially from corrections, and compounds them over time.
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...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.
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.
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 type | Starting score | Example |
|---|---|---|
| Explicit correction | 0.70 | “Use Tailwind, not Bootstrap” |
| Implied preference | 0.40 | “Deploy it to Vercel” |
| Behavioral pattern | 0.30 | User consistently asks for shorter responses |
| Each repeated signal | +0.15 | Same 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.
/v1/trackSend 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.
userIdstringrequiredYour identifier for the user. Preferences are learned and stored per userId within your org.
messagesarrayrequiredArray 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.
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..." }
]
}'{
"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.
/v1/profiles/:userIdRetrieve 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.
userIdstringrequiredThe user identifier used when tracking conversations.
curl https://api.pref0.com/v1/profiles/user_abc123 \
-H "Authorization: Bearer pref0_sk_..."{
"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.
/v1/profiles/:userIdReset 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.
userIdstringrequiredThe user identifier to delete.
curl -X DELETE https://api.pref0.com/v1/profiles/user_abc123 \
-H "Authorization: Bearer pref0_sk_..."(no content)/v1/usageGet your organization's API usage stats. Tracks total /track requests (each conversation your agent learns from).
curl https://api.pref0.com/v1/usage \
-H "Authorization: Bearer pref0_sk_..."{
"orgId": "org_xyz",
"requestCount": 1482,
"lastRequestAt": "2026-02-06T14:32:00.000Z"
}pref0 uses standard HTTP status codes. All error responses return JSON with an error field.
| Status | Meaning |
|---|---|
| 400 | Validation error. Check the details array for specifics. |
| 401 | Missing or invalid API key. |
| 500 | Internal server error. |
{
"error": "Validation error",
"details": [
{
"code": "too_small",
"minimum": 1,
"path": ["messages"],
"message": "Array must contain at least 1 element(s)"
}
]
}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).
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.