Sessions
Add Message
Add a message to a session conversation
POST
/
api
/
v1
/
sessions
/
{session_id}
/
messages
Add Message
curl --request POST \
--url https://api.example.com/api/v1/sessions/{session_id}/messages \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <x-api-key>' \
--data '
{
"role": "<string>",
"content": "<string>",
"parts": [
{
"type": "<string>",
"text": "<string>",
"uri": "<string>",
"context_type": "<string>",
"abstract": "<string>",
"tool_id": "<string>",
"tool_name": "<string>",
"skill_uri": "<string>",
"tool_input": {},
"tool_output": "<string>",
"tool_status": "<string>"
}
]
}
'import requests
url = "https://api.example.com/api/v1/sessions/{session_id}/messages"
payload = {
"role": "<string>",
"content": "<string>",
"parts": [
{
"type": "<string>",
"text": "<string>",
"uri": "<string>",
"context_type": "<string>",
"abstract": "<string>",
"tool_id": "<string>",
"tool_name": "<string>",
"skill_uri": "<string>",
"tool_input": {},
"tool_output": "<string>",
"tool_status": "<string>"
}
]
}
headers = {
"X-API-Key": "<x-api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-API-Key': '<x-api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
role: '<string>',
content: '<string>',
parts: [
{
type: '<string>',
text: '<string>',
uri: '<string>',
context_type: '<string>',
abstract: '<string>',
tool_id: '<string>',
tool_name: '<string>',
skill_uri: '<string>',
tool_input: {},
tool_output: '<string>',
tool_status: '<string>'
}
]
})
};
fetch('https://api.example.com/api/v1/sessions/{session_id}/messages', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.example.com/api/v1/sessions/{session_id}/messages",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'role' => '<string>',
'content' => '<string>',
'parts' => [
[
'type' => '<string>',
'text' => '<string>',
'uri' => '<string>',
'context_type' => '<string>',
'abstract' => '<string>',
'tool_id' => '<string>',
'tool_name' => '<string>',
'skill_uri' => '<string>',
'tool_input' => [
],
'tool_output' => '<string>',
'tool_status' => '<string>'
]
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-Key: <x-api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.example.com/api/v1/sessions/{session_id}/messages"
payload := strings.NewReader("{\n \"role\": \"<string>\",\n \"content\": \"<string>\",\n \"parts\": [\n {\n \"type\": \"<string>\",\n \"text\": \"<string>\",\n \"uri\": \"<string>\",\n \"context_type\": \"<string>\",\n \"abstract\": \"<string>\",\n \"tool_id\": \"<string>\",\n \"tool_name\": \"<string>\",\n \"skill_uri\": \"<string>\",\n \"tool_input\": {},\n \"tool_output\": \"<string>\",\n \"tool_status\": \"<string>\"\n }\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-API-Key", "<x-api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.example.com/api/v1/sessions/{session_id}/messages")
.header("X-API-Key", "<x-api-key>")
.header("Content-Type", "application/json")
.body("{\n \"role\": \"<string>\",\n \"content\": \"<string>\",\n \"parts\": [\n {\n \"type\": \"<string>\",\n \"text\": \"<string>\",\n \"uri\": \"<string>\",\n \"context_type\": \"<string>\",\n \"abstract\": \"<string>\",\n \"tool_id\": \"<string>\",\n \"tool_name\": \"<string>\",\n \"skill_uri\": \"<string>\",\n \"tool_input\": {},\n \"tool_output\": \"<string>\",\n \"tool_status\": \"<string>\"\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/api/v1/sessions/{session_id}/messages")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-API-Key"] = '<x-api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"role\": \"<string>\",\n \"content\": \"<string>\",\n \"parts\": [\n {\n \"type\": \"<string>\",\n \"text\": \"<string>\",\n \"uri\": \"<string>\",\n \"context_type\": \"<string>\",\n \"abstract\": \"<string>\",\n \"tool_id\": \"<string>\",\n \"tool_name\": \"<string>\",\n \"skill_uri\": \"<string>\",\n \"tool_input\": {},\n \"tool_output\": \"<string>\",\n \"tool_status\": \"<string>\"\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"status": "<string>",
"result": {
"session_id": "<string>",
"message_count": 123
},
"time": 123
}Add user or assistant messages to track conversation flow. Supports both simple text messages and structured messages with multiple parts (text, context references, tool calls).
Request
Path Parameters
string
required
The session ID to add the message to
Headers
string
required
Your OpenViking API key for authentication
string
default:"application/json"
Must be
application/jsonBody Parameters
string
required
Message role:
user or assistantstring
Simple text content (backward compatible mode). Mutually exclusive with
parts.array
Array of message parts for structured messages (text, context, tool). If both For text parts:For context parts:For tool parts:
content and parts are provided, parts takes precedence.string
required
Part type:
text, context, or toolstring
required
Text content
string
required
Viking URI of the context (e.g.,
viking://resources/docs/auth/)string
default:"memory"
Type of context:
memory, resource, or skillstring
Brief description of the context
string
Unique tool call identifier
string
Name of the tool being called
string
URI of the skill providing the tool
object
Input parameters for the tool
string
Tool execution output
string
default:"pending"
Execution status:
pending, running, completed, or errorResponse
string
Response status (
ok or error)number
Request processing time in seconds
Examples
Simple Text Message
# Add user message
curl -X POST http://localhost:1933/api/v1/sessions/a1b2c3d4/messages \
-H "Content-Type: application/json" \
-H "X-API-Key: your-api-key" \
-d '{
"role": "user",
"content": "How do I authenticate users?"
}'
import openviking as ov
from openviking.message import TextPart
client = ov.OpenViking(path="./my_data")
client.initialize()
# Get or create session
session = client.session(session_id="a1b2c3d4")
# Add user message
session.add_message("user", [
TextPart(text="How do I authenticate users?")
])
# Add assistant response
session.add_message("assistant", [
TextPart(text="You can use OAuth 2.0 for authentication...")
])
print(f"Total messages: {len(session.messages)}")
import requests
response = requests.post(
"http://localhost:1933/api/v1/sessions/a1b2c3d4/messages",
headers={
"Content-Type": "application/json",
"X-API-Key": "your-api-key"
},
json={
"role": "user",
"content": "How do I authenticate users?"
}
)
result = response.json()
print(f"Message count: {result['result']['message_count']}")
Message with Context Reference
curl -X POST http://localhost:1933/api/v1/sessions/a1b2c3d4/messages \
-H "Content-Type: application/json" \
-H "X-API-Key: your-api-key" \
-d '{
"role": "assistant",
"parts": [
{
"type": "text",
"text": "Based on the authentication guide..."
},
{
"type": "context",
"uri": "viking://resources/docs/auth/",
"context_type": "resource",
"abstract": "OAuth 2.0 implementation guide"
}
]
}'
from openviking.message import TextPart, ContextPart
# Search for relevant context
results = client.search("authentication guide", session=session)
# Add assistant message with context reference
session.add_message("assistant", [
TextPart(text="Based on the authentication guide..."),
ContextPart(
uri=results.resources[0].uri,
context_type="resource",
abstract=results.resources[0].abstract
)
])
# Track actually used contexts
session.used(contexts=[results.resources[0].uri])
Message with Tool Call
curl -X POST http://localhost:1933/api/v1/sessions/a1b2c3d4/messages \
-H "Content-Type: application/json" \
-H "X-API-Key: your-api-key" \
-d '{
"role": "assistant",
"parts": [
{
"type": "text",
"text": "Let me search for that information..."
},
{
"type": "tool",
"tool_id": "call_123",
"tool_name": "search_web",
"skill_uri": "viking://skills/search-web/",
"tool_input": {"query": "OAuth best practices"},
"tool_output": "Found 5 results...",
"tool_status": "completed"
}
]
}'
from openviking.message import TextPart, ToolPart
# Add message with tool call
session.add_message("assistant", [
TextPart(text="Let me search for that..."),
ToolPart(
tool_id="call_123",
tool_name="search_web",
skill_uri="viking://skills/search-web/",
tool_input={"query": "OAuth best practices"},
tool_output="Found 5 results...",
tool_status="completed"
)
])
Response Example
{
"status": "ok",
"result": {
"session_id": "a1b2c3d4",
"message_count": 3
},
"time": 0.1
}
Message Roles
- user - Messages from the end user
- assistant - Messages from the AI assistant
Part Types
Text Part
Simple text content:TextPart(text="Your message here")
Context Part
Reference to a resource, memory, or skill:ContextPart(
uri="viking://resources/docs/auth/",
context_type="resource", # "resource", "memory", or "skill"
abstract="Brief description"
)
Tool Part
Tool execution record:ToolPart(
tool_id="call_123",
tool_name="search_web",
skill_uri="viking://skills/search-web/",
tool_input={"query": "search term"},
tool_output="Results...",
tool_status="completed" # "pending", "running", "completed", "error"
)
Best Practices
Always Track Context Usage
# Search for context
results = client.search(query, session=session)
# Add message with context
session.add_message("assistant", [
TextPart(text="Based on the docs..."),
ContextPart(uri=results.resources[0].uri, context_type="resource")
])
# Mark context as actually used
session.used(contexts=[results.resources[0].uri])
Structure Messages Properly
Use parts for rich messages instead of mixing everything into text:# Good: Structured with parts
session.add_message("assistant", [
TextPart(text="Here's the solution:"),
ContextPart(uri="viking://resources/solution.md", context_type="resource")
])
# Avoid: Mixing URIs in text
session.add_message("assistant", [
TextPart(text="See viking://resources/solution.md for details")
])
Related Endpoints
- Create Session - Create a new session
- Get Session - Retrieve session and messages
- Commit Session - Archive messages and extract memories
⌘I
Add Message
curl --request POST \
--url https://api.example.com/api/v1/sessions/{session_id}/messages \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <x-api-key>' \
--data '
{
"role": "<string>",
"content": "<string>",
"parts": [
{
"type": "<string>",
"text": "<string>",
"uri": "<string>",
"context_type": "<string>",
"abstract": "<string>",
"tool_id": "<string>",
"tool_name": "<string>",
"skill_uri": "<string>",
"tool_input": {},
"tool_output": "<string>",
"tool_status": "<string>"
}
]
}
'import requests
url = "https://api.example.com/api/v1/sessions/{session_id}/messages"
payload = {
"role": "<string>",
"content": "<string>",
"parts": [
{
"type": "<string>",
"text": "<string>",
"uri": "<string>",
"context_type": "<string>",
"abstract": "<string>",
"tool_id": "<string>",
"tool_name": "<string>",
"skill_uri": "<string>",
"tool_input": {},
"tool_output": "<string>",
"tool_status": "<string>"
}
]
}
headers = {
"X-API-Key": "<x-api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-API-Key': '<x-api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
role: '<string>',
content: '<string>',
parts: [
{
type: '<string>',
text: '<string>',
uri: '<string>',
context_type: '<string>',
abstract: '<string>',
tool_id: '<string>',
tool_name: '<string>',
skill_uri: '<string>',
tool_input: {},
tool_output: '<string>',
tool_status: '<string>'
}
]
})
};
fetch('https://api.example.com/api/v1/sessions/{session_id}/messages', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.example.com/api/v1/sessions/{session_id}/messages",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'role' => '<string>',
'content' => '<string>',
'parts' => [
[
'type' => '<string>',
'text' => '<string>',
'uri' => '<string>',
'context_type' => '<string>',
'abstract' => '<string>',
'tool_id' => '<string>',
'tool_name' => '<string>',
'skill_uri' => '<string>',
'tool_input' => [
],
'tool_output' => '<string>',
'tool_status' => '<string>'
]
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-Key: <x-api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.example.com/api/v1/sessions/{session_id}/messages"
payload := strings.NewReader("{\n \"role\": \"<string>\",\n \"content\": \"<string>\",\n \"parts\": [\n {\n \"type\": \"<string>\",\n \"text\": \"<string>\",\n \"uri\": \"<string>\",\n \"context_type\": \"<string>\",\n \"abstract\": \"<string>\",\n \"tool_id\": \"<string>\",\n \"tool_name\": \"<string>\",\n \"skill_uri\": \"<string>\",\n \"tool_input\": {},\n \"tool_output\": \"<string>\",\n \"tool_status\": \"<string>\"\n }\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-API-Key", "<x-api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.example.com/api/v1/sessions/{session_id}/messages")
.header("X-API-Key", "<x-api-key>")
.header("Content-Type", "application/json")
.body("{\n \"role\": \"<string>\",\n \"content\": \"<string>\",\n \"parts\": [\n {\n \"type\": \"<string>\",\n \"text\": \"<string>\",\n \"uri\": \"<string>\",\n \"context_type\": \"<string>\",\n \"abstract\": \"<string>\",\n \"tool_id\": \"<string>\",\n \"tool_name\": \"<string>\",\n \"skill_uri\": \"<string>\",\n \"tool_input\": {},\n \"tool_output\": \"<string>\",\n \"tool_status\": \"<string>\"\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/api/v1/sessions/{session_id}/messages")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-API-Key"] = '<x-api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"role\": \"<string>\",\n \"content\": \"<string>\",\n \"parts\": [\n {\n \"type\": \"<string>\",\n \"text\": \"<string>\",\n \"uri\": \"<string>\",\n \"context_type\": \"<string>\",\n \"abstract\": \"<string>\",\n \"tool_id\": \"<string>\",\n \"tool_name\": \"<string>\",\n \"skill_uri\": \"<string>\",\n \"tool_input\": {},\n \"tool_output\": \"<string>\",\n \"tool_status\": \"<string>\"\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"status": "<string>",
"result": {
"session_id": "<string>",
"message_count": 123
},
"time": 123
}