Quickstart
Get Threadline running in your project in under 5 minutes.
Installation
Install the SDK from npm, or skip it entirely and call the REST API.
TypeScript
npm install threadline-sdkcURL
# no install required
curl https://app.threadline.to/api/healthAuthentication
Initialize Threadline with your API key from the dashboard. Over HTTP, pass it as a bearer token.
TypeScript
import { Threadline } from "threadline-sdk"
const tl = new Threadline({
apiKey: process.env.THREADLINE_API_KEY!
})cURL
export THREADLINE_API_KEY=tl_live_...
curl https://app.threadline.to/api/context/inject \
-H "Authorization: Bearer $THREADLINE_API_KEY" \
-H "Content-Type: application/json"Context Objects
Context objects are the unit of memory Threadline stores per user — facts, preferences, and conversational history that persist across sessions.
Scopes & Grants
Scopes control which agents can read or write to a user's context. Grants are scoped permissions you issue to specific agents or tools. See Governance for the full model.
Your first run
On a brand-new user the store is empty, so start with update() — write one real exchange, then call inject() and watch the context come back.
TypeScript
// 1. Write first — one real exchange
await tl.update({
userId: "user_42",
userMessage: "I just moved to Lisbon and I prefer short answers.",
agentResponse: "Welcome to Lisbon! I'll keep things brief."
})
// 2. Now inject — the prompt comes back enriched
const { injectedPrompt } = await tl.inject("user_42", "You are a helpful assistant.")
console.log(injectedPrompt)cURL
# 1. Write first
curl -X POST https://app.threadline.to/api/context/update \
-H "Authorization: Bearer $THREADLINE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"userId": "user_42",
"userMessage": "I just moved to Lisbon and I prefer short answers.",
"agentResponse": "Welcome to Lisbon! I will keep things brief."
}'
# 2. Then inject
curl -X POST https://app.threadline.to/api/context/inject \
-H "Authorization: Bearer $THREADLINE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"userId": "user_42",
"basePrompt": "You are a helpful assistant."
}'Expected, not an error. If you call inject() before any update(), you get your basePrompt back unchanged with reason: "empty" and a notice telling you to call update() first. There is simply nothing stored for that user yet.
{
"injectedPrompt": "You are a helpful assistant.",
"reason": "empty",
"notice": "No context stored for this user yet. Call update() first."
}Every reason value is documented on Response reasons.
The loop
Once a user has context, the steady-state loop is: inject before the LLM call, update after it.
TypeScript
const { injectedPrompt } = await tl.inject(userId, basePrompt)
const response = await openai.chat.completions.create({
model: "gpt-4o",
messages: [{ role: "system", content: injectedPrompt }],
})
await tl.update({ userId, userMessage, agentResponse })cURL
# before the LLM call
curl -X POST https://app.threadline.to/api/context/inject \
-H "Authorization: Bearer $THREADLINE_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "userId": "user_42", "basePrompt": "You are a helpful assistant." }'
# after the LLM call
curl -X POST https://app.threadline.to/api/context/update \
-H "Authorization: Bearer $THREADLINE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"userId": "user_42",
"userMessage": "...",
"agentResponse": "..."
}'That's it. Your agent now has persistent context for every user — stored until the user deletes it or the grant is revoked. For the full API reference and SDK options, browse the sidebar.