Conversations
Server-side conversation state for the Responses API. Create a conversation, append items, reference it by id. The model loads the history; you never resend it.
Endpoints
| Method | Path | Description |
|---|---|---|
| POST | /:project_id/v1/conversations | Create a conversation |
| GET | /:project_id/v1/conversations | List conversations |
| GET | /:project_id/v1/conversations/{id} | Get a conversation |
| POST | /:project_id/v1/conversations/{id} | Update a conversation |
| DELETE | /:project_id/v1/conversations/{id} | Delete a conversation |
| POST | /:project_id/v1/conversations/{id}/items | Add an item |
| GET | /:project_id/v1/conversations/{id}/items | List items |
| GET | /:project_id/v1/conversations/{id}/items/{item_id} | Get an item |
| DELETE | /:project_id/v1/conversations/{id}/items/{item_id} | Delete an item |
All paths are relative to your project base URL:
https://api.erebine.ai/proj_ABC123. Each conversation belongs to
one workspace of the project; see Workspace Scope.
Workspace Scope
A conversation belongs to the workspace its create request resolved to: the
workspace named in the X-Workspace-Id header, else the only
workspace of an API key confined to one, else the project's default workspace.
Every other request resolves its workspace the same way and reaches only that
workspace's conversations and their items. A conversation in another workspace
answers 404, exactly as a missing one does.
- An API key confined to some of the project's workspaces reaches only those.
Naming another returns
403 Forbidden(workspace_not_allowed), and a key confined to several workspaces must name one. See Authentication & Security. - The project's default workspace is never an
operational workspace:
making one the default is refused with
400 Bad Request(operational_default_forbidden). In a project with no default workspace, a key that belongs to a user must name a workspace; a request that names none returns403 Forbidden(workspace_required). A key with no user behind it reaches every conversation of the project there. - Conversations created before conversations recorded their workspace belong to none. Only a key with no user behind it and no workspace list reaches them, whichever workspace the request names. A confined key never does, and neither does a key that belongs to a user: nothing shows such a conversation lies in a workspace that user can read.
- The
conversationparameter of the Responses API follows the same rule; see Responses API Integration.
Quick Start
Create a conversation, add a system prompt, then use it with the Responses API:
curl -X POST https://api.erebine.ai/proj_ABC123/v1/conversations \
-H "Authorization: Bearer ere_myproject_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"metadata": {"title": "Weather assistant"},
"items": [
{
"type": "message",
"role": "system",
"content": "You are a helpful weather assistant."
}
]
}'
# Returns: {"id": "conv_abc123", ...}
curl -X POST https://api.erebine.ai/proj_ABC123/v1/conversations/conv_abc123/items \
-H "Authorization: Bearer ere_myproject_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"type": "message",
"role": "user",
"content": "What is the weather in Paris?"
}'
# Responses API uses endpoint-scoped path
curl -X POST https://api.erebine.ai/proj_ABC123/my-endpoint/v1/responses \
-H "Authorization: Bearer ere_myproject_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"model": "llama-3.1-8b",
"input": "What is the weather in Paris?",
"conversation": {"id": "conv_abc123"}
}'
The Responses API automatically loads all conversation items as context and appends the model's response to the conversation.
Lifecycle
The two surfaces meet at the conversation id; the model writes back into the same store you read from.
flowchart LR
Create["POST /v1/conversations
conv_abc123"]
AddUser["POST .../items
user message"]
Respond["POST /v1/responses
conversation: {id: ...}"]
LoadCtx["Server loads items
as prior context"]
Generate["Model generates"]
AutoAppend["Server appends
assistant + function_call items"]
Harvest["Client reads new items
for call_id, content, ..."]
Create --> AddUser
AddUser --> Respond
Respond --> LoadCtx
LoadCtx --> Generate
Generate --> AutoAppend
AutoAppend --> Harvest
Harvest -.-> AddUser
Manage Conversations
Create Conversation
POST /:project_id/v1/conversations
| Parameter | Type | Description |
|---|---|---|
| metadataoptional | object | Up to 16 key-value pairs. Keys max 64 characters, values max 512 characters. |
| itemsoptional | array | Initial items to add (max 20). Useful for seeding system prompts or conversation history. |
Response
{
"id": "conv_abc123def456",
"object": "conversation",
"created_at": 1709000000,
"updated_at": 1709000000,
"metadata": {"title": "Weather assistant"}
}
List Conversations
GET /:project_id/v1/conversations
Returns a paginated list of conversations. Use cursor-based pagination with after and limit parameters.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| limitoptional | integer | Maximum conversations to return (1-100, default 20). |
| afteroptional | string | Cursor for pagination. Pass the last_id from the previous page to get the next page. |
curl "https://api.erebine.ai/proj_ABC123/v1/conversations?limit=10" \
-H "Authorization: Bearer ere_myproject_your_api_key"
Response
{
"object": "list",
"data": [
{
"id": "conv_abc123def456",
"object": "conversation",
"created_at": 1709000000,
"updated_at": 1709000100,
"metadata": {"title": "Weather assistant"}
}
],
"first_id": "conv_abc123def456",
"last_id": "conv_abc123def456",
"has_more": false
}
Get Conversation
GET /:project_id/v1/conversations/{conversation_id}
curl https://api.erebine.ai/proj_ABC123/v1/conversations/conv_abc123 \
-H "Authorization: Bearer ere_myproject_your_api_key"
Update Conversation
POST /:project_id/v1/conversations/{conversation_id}
Updates the conversation metadata. The new metadata replaces the existing metadata entirely.
curl -X POST https://api.erebine.ai/proj_ABC123/v1/conversations/conv_abc123 \
-H "Authorization: Bearer ere_myproject_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"metadata": {"title": "Updated title", "category": "support"}
}'
Delete Conversation
DELETE /:project_id/v1/conversations/{conversation_id}
Soft-deletes the conversation. It is excluded from list queries but retained for auditing.
curl -X DELETE https://api.erebine.ai/proj_ABC123/v1/conversations/conv_abc123 \
-H "Authorization: Bearer ere_myproject_your_api_key"
Response
{
"id": "conv_abc123def456",
"object": "conversation",
"deleted": true
}
Manage Items
Add Item
POST /:project_id/v1/conversations/{conversation_id}/items
| Parameter | Type | Description |
|---|---|---|
| typerequired | string | Item type: "message", "function_call", or "function_call_output". |
| roleconditional | string | Required (non-null) for message type. By convention one of "user", "assistant", "system", or "tool"; the server stores the value as-is and does not currently reject other strings, but downstream consumers (including the Responses API) expect the conventional values. |
| contentrequired | string | Text content of the item. Required at decode time for every item type. For function_call items the call's semantic payload is in arguments; supply an empty string or a short label for content. |
| call_idrecommended | string | Recommended for function_call and function_call_output items. Links a function call to its output so the Responses API can pair them in subsequent turns. Not enforced by the server today, but omitting it will break tool-result correlation. |
| namerecommended | string | Function name. Recommended for function_call items. Not enforced by the server today, but the model will not be able to resolve the tool without it. |
| argumentsrecommended | string | Serialized JSON arguments. Recommended for function_call items. Not enforced by the server today. |
For function_call_output items, the call_id must
match the one the model chose; harvest it from the conversation rather than
inventing it. See Multi-Turn with Function Calling
below for the harvest pattern.
Message Item
curl -X POST https://api.erebine.ai/proj_ABC123/v1/conversations/conv_abc123/items \
-H "Authorization: Bearer ere_myproject_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"type": "message",
"role": "user",
"content": "Hello, how are you?"
}'
Response
{
"id": "item_xyz789abcdef",
"object": "conversation.item",
"type": "message",
"role": "user",
"content": "Hello, how are you?",
"call_id": null,
"name": null,
"arguments": null,
"sequence_number": 1,
"created_at": 1709000100
}
Function Call Output Item
curl -X POST https://api.erebine.ai/proj_ABC123/v1/conversations/conv_abc123/items \
-H "Authorization: Bearer ere_myproject_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"type": "function_call_output",
"call_id": "call_abc123",
"content": "{\"temperature\": 18, \"condition\": \"sunny\"}"
}'
List Items
GET /:project_id/v1/conversations/{conversation_id}/items
Returns items ordered by sequence number (ascending). Supports cursor-based pagination with after and limit parameters.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| limitoptional | integer | Maximum items to return (1-100, default 20). |
| afteroptional | string | Cursor for pagination. Pass the last_id from the previous page. |
curl "https://api.erebine.ai/proj_ABC123/v1/conversations/conv_abc123/items?limit=50" \
-H "Authorization: Bearer ere_myproject_your_api_key"
Response
{
"object": "list",
"data": [
{
"id": "item_xyz789abcdef",
"object": "conversation.item",
"type": "message",
"role": "user",
"content": null,
"call_id": null,
"name": null,
"arguments": null,
"sequence_number": 0,
"created_at": 1709000100
}
],
"first_id": "item_xyz789abcdef",
"last_id": "item_xyz789abcdef",
"has_more": false
}
Note: The content field is null
in list responses for efficiency. Use the Get Item endpoint to retrieve full
content for a specific item.
Get Item
GET /:project_id/v1/conversations/{conversation_id}/items/{item_id}
Returns the item with full content loaded from tiered storage.
curl https://api.erebine.ai/proj_ABC123/v1/conversations/conv_abc123/items/item_xyz789 \
-H "Authorization: Bearer ere_myproject_your_api_key"
Delete Item
DELETE /:project_id/v1/conversations/{conversation_id}/items/{item_id}
Soft-deletes the item. It is excluded from future conversation context but the sequence number gap is preserved.
curl -X DELETE https://api.erebine.ai/proj_ABC123/v1/conversations/conv_abc123/items/item_xyz789 \
-H "Authorization: Bearer ere_myproject_your_api_key"
Response
{
"id": "item_xyz789abcdef",
"object": "conversation.item",
"deleted": true
}
Delete response shape. Both delete endpoints
return the resource type in object
("conversation" or "conversation.item"),
not a synthetic ".deleted" suffix. Match on the
deleted: true flag, not on the object string.
Responses API Integration
Pass a conversation parameter when creating a response on the
Responses API to use the conversation's items
as context. The model's output is automatically appended to the conversation.
curl -X POST https://api.erebine.ai/proj_ABC123/my-endpoint/v1/responses \
-H "Authorization: Bearer ere_myproject_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"model": "llama-3.1-8b",
"input": "What is the weather in Paris?",
"conversation": {"id": "conv_abc123"}
}'
Note that conversations are mounted at the project (at /:project_id/v1/conversations)
while the Responses API is endpoint-scoped (at /:project_id/:endpoint_slug/v1/responses).
The response request must resolve to the workspace the conversation belongs to (the
ws_ path prefix, the X-Workspace-Id header, the key's only
workspace, or the project's default workspace); otherwise it returns
400 invalid_conversation, as for a conversation that does not exist. See
Workspace Scope.
How It Works
- The conversation's active items are loaded and prepended to the input as context, oldest-first, up to 2000 items per request.
- The model generates a response using that history plus the new input.
- The model's output items (messages, function calls) are automatically appended to the conversation.
- The conversation's
updated_attimestamp is refreshed.
The history is not trimmed to fit. If the loaded
conversation plus the new input exceeds the model's context window, the
request returns 400 context_length_exceeded under the default
truncation: "disabled". Erebine does not drop your oldest
turns and answer from a shortened conversation. The same applies to the
2000-item load bound: a conversation with more than 2000 items cannot be
replayed in one request, so under "disabled" it returns
400 context_length_exceeded rather than an answer built from
part of it. Send truncation: "auto" to have middle items
dropped to fit -- which also selects the most recent 2000 items -- or
branch the conversation. The context-window check applies only when the
model's context length is resolvable; the item bound always applies.
Use one prior-context source, not both.
conversation and previous_response_id are
mutually exclusive. A request carrying both returns
400 invalid_request_error (code invalid_request,
param conversation); neither source is applied. Use
conversation for explicit state management and
previous_response_id for simple response chaining.
Storage Tiers
Conversation content is stored using the platform's standard two-tier storage architecture. For details on storage tiers, encryption, retention, and billing, see Storage.
Conversation Storage Limits
| Limit | Value |
|---|---|
| Max items per conversation | 100 |
| Max individual item size | 1 MB |
| Max metadata keys per conversation | 16 |
| Max metadata key length | 64 characters |
| Max metadata value length | 512 characters |
| Max total metadata size | 16 KB |
Error Handling
| HTTP Status | Error Code | Description |
|---|---|---|
| 400 | invalid_request |
Missing or invalid parameters (e.g., missing role for message items). |
| 400 | invalid_request |
Initial items array exceeds 20 items. |
| 401 | authentication_error |
Invalid or missing API key. |
| 403 | workspace_not_allowed |
The request names a workspace outside the API key's workspace list, or a key confined to several workspaces names none. See Workspace Scope. |
| 403 | workspace_not_in_project |
The X-Workspace-Id header does not name a workspace of the project. |
| 403 | workspace_required |
The project has no default workspace and the request, made with a key that belongs to a user, names none. See Workspace Scope. |
| 404 | not_found |
Conversation or item not found, or the conversation belongs to another workspace than the one the request resolves to. |
| 429 | rate_limit_exceeded |
Too many requests. Check the Retry-After header. |
Examples
Python (requests)
import requests
headers = {
"Authorization": "Bearer ere_myproject_your_api_key",
"Content-Type": "application/json"
}
base = "https://api.erebine.ai/proj_ABC123/v1"
# Create a conversation with a system prompt
conv = requests.post(f"{base}/conversations", headers=headers, json={
"metadata": {"title": "Demo chat"},
"items": [{
"type": "message",
"role": "system",
"content": "You are a helpful assistant."
}]
}).json()
print(f"Created conversation: {conv['id']}")
# Add a user message
requests.post(
f"{base}/conversations/{conv['id']}/items",
headers=headers,
json={
"type": "message",
"role": "user",
"content": "What is the capital of France?"
}
)
# List conversations
convs = requests.get(f"{base}/conversations?limit=10", headers=headers).json()
for c in convs["data"]:
print(f"Conversation: {c['id']}")
# List items in a conversation
items = requests.get(
f"{base}/conversations/{conv['id']}/items?limit=50",
headers=headers
).json()
for item in items["data"]:
print(f"[{item['role']}] {item['content']}")
# Delete a conversation
requests.delete(f"{base}/conversations/{conv['id']}", headers=headers)
Node.js (fetch)
const base = "https://api.erebine.ai/proj_ABC123/v1";
const headers = {
"Authorization": "Bearer ere_myproject_your_api_key",
"Content-Type": "application/json"
};
// Create a conversation with a system prompt
const convRes = await fetch(`${base}/conversations`, {
method: "POST",
headers,
body: JSON.stringify({
metadata: { title: "Demo chat" },
items: [{
type: "message",
role: "system",
content: "You are a helpful assistant."
}]
})
});
const conv = await convRes.json();
console.log(`Created conversation: ${conv.id}`);
// Add a user message
await fetch(`${base}/conversations/${conv.id}/items`, {
method: "POST",
headers,
body: JSON.stringify({
type: "message",
role: "user",
content: "What is the capital of France?"
})
});
// List conversations
const listRes = await fetch(`${base}/conversations?limit=10`, { headers });
const list = await listRes.json();
list.data.forEach(c => console.log(`Conversation: ${c.id}`));
// List items in a conversation
const itemsRes = await fetch(
`${base}/conversations/${conv.id}/items?limit=50`,
{ headers }
);
const items = await itemsRes.json();
items.data.forEach(item => console.log(`[${item.role}] ${item.content}`));
// Delete a conversation
await fetch(`${base}/conversations/${conv.id}`, {
method: "DELETE",
headers
});
Multi-Turn with Function Calling (curl)
When the Responses API decides to call a tool, it auto-appends a
function_call item to the conversation. That appended item
carries the call_id the model chose; you must read it from
the conversation before posting the matching function_call_output.
Do not invent or hardcode call_id values.
# 1. Create conversation
curl -X POST https://api.erebine.ai/proj_ABC123/v1/conversations \
-H "Authorization: Bearer ere_myproject_your_api_key" \
-H "Content-Type: application/json" \
-d '{"metadata": {"title": "Tool demo"}}'
# Returns: {"id": "conv_abc123", ...}
# 2. Generate response with tools (auto-appends a function_call item to the conversation)
curl -X POST https://api.erebine.ai/proj_ABC123/my-endpoint/v1/responses \
-H "Authorization: Bearer ere_myproject_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"model": "llama-3.1-8b",
"input": "What is the weather in Paris?",
"conversation": {"id": "conv_abc123"},
"tools": [{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get weather for a city",
"parameters": {"type": "object", "properties": {"city": {"type": "string"}}, "required": ["city"]}
}
}]
}'
# 3. Harvest the assistant's call_id from the conversation.
# The Responses API auto-appended a function_call item; list the conversation
# items and pick the most recent function_call entry. Its call_id is the value
# the model chose and is the only value that will correlate with the output.
ASSISTANT_CALL_ID=$(curl -s \
"https://api.erebine.ai/proj_ABC123/v1/conversations/conv_abc123/items?limit=100" \
-H "Authorization: Bearer ere_myproject_your_api_key" \
| jq -r '[.data[] | select(.type == "function_call")] | last | .call_id')
echo "captured call_id: $ASSISTANT_CALL_ID"
# 4. Post the function output using the captured call_id (NOT a hardcoded one)
curl -X POST https://api.erebine.ai/proj_ABC123/v1/conversations/conv_abc123/items \
-H "Authorization: Bearer ere_myproject_your_api_key" \
-H "Content-Type: application/json" \
-d "{
\"type\": \"function_call_output\",
\"call_id\": \"$ASSISTANT_CALL_ID\",
\"content\": \"{\\\"temperature\\\": 18, \\\"condition\\\": \\\"sunny\\\"}\"
}"
# 5. Continue with the function result in context
curl -X POST https://api.erebine.ai/proj_ABC123/my-endpoint/v1/responses \
-H "Authorization: Bearer ere_myproject_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"model": "llama-3.1-8b",
"input": "Great, now summarize the weather.",
"conversation": {"id": "conv_abc123"}
}'
Note on the list response. List Items returns
content: null for efficiency. call_id,
name, type, and sequence_number
are populated in the list response, so harvesting the call_id
does not require a follow-up Get Item call. If you also need the function
arguments payload, fetch the specific item by id.