Skip to main content

BuddyPro Owner API — OpenAI-Compatible V1 Endpoint

OpenAI-compatible access to your BuddyPro instance, designed for owner and team member integrations — connecting your services, automations, and internal tools to BuddyPro. This endpoint accepts requests structured like the OpenAI Chat Completions API and returns responses in the same format, with BuddyPro-specific extensions in message (e.g., image, audio).

BuddyPro End User API coming soon

A separate API for end-users is planned for future release, allowing them to generate their own API keys that work directly with their personal profiles. See Privacy & Data Access for details.

Overview

PropertyValue
PathPOST /v1/chat/completions
AuthAuthorization: Bearer bapi_... header
FormatOpenAI Chat Completions compatible
StreamingNot supported yet

Persistent Memory & Conversation History

Unlike stateless LLM APIs, BuddyPro maintains long-term memory and full conversation history for the profile tied to each API key. Every API request is treated exactly like a message sent in Telegram — it is saved to the profile's chat history, contributes to BuddyPro's memory about that user, and influences future responses.

This means:

  • Conversations are cumulative. BuddyPro remembers everything said through the API, just as it remembers Telegram conversations. You do not need to (and should not) send conversation history — just send the current message.
  • Memory builds over time. BuddyPro learns preferences, facts, and context from API interactions, the same way it does from Telegram chats.
  • Stateless mode available. Set x_buddy_saveToHistory: false to make a request that doesn't persist anything — no chat history, no memory updates, no profile changes. See Stateless Mode.
warning

Do not send conversation history in the messages array. Send only the current user message. BuddyPro stores and manages conversation context server-side.

Privacy & Data Access

danger

The Owner API should NOT be used to create profiles for real people using test users. People expect private conversations and often share private or sensitive information. It is not a privacy-safe consumer-facing solution. The BuddyPro Owner API does not protect end-user data from the instance owner. The owner can access conversation history and memories of test accounts.

All API keys in the Owner API are generated by the BuddyPro instance owner or a team member. The owner has full access to any testing profiles created on their instance — they can switch to any test account via /test in Telegram, read its conversation history, and see everything BuddyPro remembers about that profile.

What this means in practice:

Don't build an integration with profiles for end-users on the BuddyPro Owner API, where users would chat with BuddyPro through your API key (e.g., a website chatbot), and each user would get a separate test profile — the BuddyPro instance owner could:

  • Switch to any of those test profiles
  • Ask BuddyPro: "Tell me everything you know about me"
  • Read the full conversation history and all stored memories for that profile

The owner knows the API key and the user identifiers, so there is nothing preventing them from accessing any profile created as a test user.

  • Internal automations and agents (e.g., CI/CD bots, monitoring alerts, internal tools)
  • Service-to-service integrations where the profile owner is also the API consumer
  • Prototyping and development with test users
  • Using test users in your integrations to avoid your integrations influencing your personal message history and memory
  • Scenarios where all API users are the same organization and aware of data visibility
  • Stateless Q&A (x_buddy_saveToHistory: false) — safe for any use case since nothing persists

What NOT to use the Owner API for

  • Building consumer-facing products with separate profiles for real end-users created as test users
  • Creating profiles for real people using test accounts
  • Any scenario where end-users expect their conversations to be private from the instance owner

The upcoming BuddyPro End User API

A future BuddyPro End User API will solve this by allowing end-users to generate their own API keys that work directly with their personal BuddyPro profile. In the End User API model:

  • The API key is generated by and known only to the end-user, not the instance owner
  • The instance owner cannot access the user's conversation history or memory
  • End-users have full data ownership over their profile

Until the End User API is available, do not use the Owner API as a substitute for privacy-safe consumer access. For use cases needing privacy now, use x_buddy_saveToHistory: false (stateless mode) — nothing is stored, so there is nothing for the owner to access.

Authentication

Getting an API Key

info

By default, API conversations use the profile that generated the API key — messages are saved to its conversation history and contribute to its memory, even though they don't appear in Telegram. Use /test in Telegram before generating the key to bind it to a test account instead of your personal profile, so API interactions don't mix with your personal chat history. Your real owner or team member profile also has management commands that agents could misuse. Use the user field to create additional isolated profiles. See User Isolation.

Send this command to your BuddyPro bot in Telegram, preferably on a testing account:

/generateApiKey:my-app

You'll receive a key starting with bapi_.

API Key Management

CommandDescription
/generateApiKey:{name}Create a new API key
/invalidateApiKey:{name}Revoke a key by name or raw key
/getApiStatsList all active keys and usage

Authenticating Requests

Pass your API key via the Authorization header:

Authorization: Bearer bapi_xxxxxxxxxxxx

Endpoint

POST https://api.buddypro.ai/v1/chat/completions
Authorization: Bearer bapi_xxxxxxxxxxxx
Content-Type: application/json

Request

Content Input

Standard OpenAI messages array. BuddyPro extracts the last user message for processing.

warning

Only one user message is allowed. BuddyPro manages conversation history server-side — do not send conversation turns. System and assistant messages are ignored.

Text only (string content):

{
"messages": [
{ "role": "user", "content": "Hello, how are you?" }
]
}

Multimodal (array content):

{
"messages": [
{
"role": "user",
"content": [
{ "type": "text", "text": "Describe this image" },
{ "type": "image_url", "image_url": { "url": "https://example.com/photo.jpg" } }
]
}
]
}

Content Part Types

When using array content inside messages[].content:

Text

{ "type": "text", "text": "What is the weather today?" }

Max 50,000 characters per text part.

Image (image_url)

{ "type": "image_url", "image_url": { "url": "https://example.com/photo.jpg" } }

Supported URL types:

  • HTTPS URL — must be publicly accessible
  • Data URIdata:image/png;base64,iVBORw0KGgo...

Max 5 images per request. Max 40 MB per remote download.

Audio Input (input_audio)

{
"type": "input_audio",
"input_audio": {
"data": "<base64>",
"format": "mp3"
}
}

Fields:

FieldTypeDescription
datastringBase64-encoded audio data or URL
formatstringAudio format: mp3, wav, ogg, aac, flac
type"url" | "base64"Optional data type hint. Default: base64

Audio via URL:

{
"type": "input_audio",
"input_audio": {
"data": "https://example.com/audio.mp3",
"type": "url",
"format": "mp3"
}
}

Audio Output (TTS via Modalities)

To request TTS audio output, use the OpenAI-style modalities and audio fields:

{
"modalities": ["text", "audio"],
"audio": { "format": "mp3" },
"messages": [
{
"role": "user",
"content": [
{ "type": "input_audio", "input_audio": { "data": "<base64>", "format": "mp3" } }
]
}
]
}
  • When modalities includes "audio", TTS is enabled
  • audio.format defaults to "mp3" if omitted
  • TTS only applies when audio input is present in the request
  • audio.voice is accepted but ignored — voice is set by the bot owner

Request Fields Reference

FieldTypeRequiredDescription
messagesarrayYesOpenAI-format messages. Must contain exactly 1 user message.
modalities["text"] | ["text", "audio"]Output types. Include "audio" to enable TTS
audioobjectAudio config: { "format": "mp3"|"wav" }
userstringCustom user identifier for an isolated test profile. When omitted, requests use the key's profile. See User Isolation
x_buddy_saveToHistorybooleanWhen false, nothing is saved to chat history, memory, or profile. Default: true. See Stateless Mode
x_buddy_systemPromptstringCustom system prompt text (max 50,000 chars). See Custom System Prompt
x_buddy_systemPromptModestringSystem prompt mode: "replace" or "add". Default: "add"

Client Request ID

Provide via the X-Client-Request-Id HTTP header:

curl -X POST https://api.buddypro.ai/v1/chat/completions \
-H "Authorization: Bearer bapi_xxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-H "X-Client-Request-Id: my-app_req-42" \
-d '{
"messages": [
{ "role": "user", "content": "Hello!" }
]
}'

Max 64 characters, alphanumeric + hyphens + underscores only.

User Isolation

By default, API requests use the profile that generated the API key. Conversations are stored in that profile's message history and contribute to its memory. If the key was generated after running /test in Telegram, it is bound to that test account — not to the owner's personal profile.

To create isolated test profiles, use the user field. Each unique user value creates a fully separate profile with its own chat history, long-term memory, and settings.

Modes:

ModeHow to activateBehavior
Key profile (default)Omit userUses the profile that generated the API key (message history, settings, memory)
Named userSet user to a custom identifierCreates a separate isolated profile per user value — useful for creating specialized profiles with specific memory or chat history
StatelessSet x_buddy_saveToHistory: falseNothing is persisted. Can be combined with either mode above

Named user example:

{
"user": "test-user-joe",
"messages": [
{ "role": "user", "content": "Hello!" }
]
}

Each unique user value creates a fully isolated conversation context with its own:

  • Chat history
  • Long-term memory
  • User profile and settings

Use this when you want to simulate multiple user profiles with different data or use cases through a single API key.

warning

Named test user profiles are not private from the API key owner. The owner can access any test profile via /test in Telegram. Do not use the user field to create profiles for real people with the expectation of privacy. Instead, wait for End-User API release coming soon. See Privacy & Data Access for details.

Validation rules for user:

  • Alphanumeric characters, hyphens, underscores, and dots only (a-z, A-Z, 0-9, -, _, .)
  • Cannot be a purely numeric value (e.g., 123456789) — to prevent conflict with real user IDs
  • Max 128 characters
  • No spaces

Stateless Mode

Set x_buddy_saveToHistory: false to make a request that does not persist anything. In stateless mode:

  • Nothing is saved to chat history
  • No updates to Pinecone long-term memory
  • No profile updates or preference learning
  • The AI still responds normally using existing context

This is useful for:

  • Pure Q&A interactions where you don't want to pollute the profile's history
  • Privacy-sensitive use cases where you need to ensure nothing is stored
  • Testing and prototyping without affecting the profile

Stateless mode can be combined with any isolation mode (default, named user, or owner profile).

Example — stateless Q&A:

{
"x_buddy_saveToHistory": false,
"messages": [
{ "role": "user", "content": "What is the best way to build a profitable sales funnel?" }
]
}

Example — stateless with named user:

{
"user": "test-user-joe",
"x_buddy_saveToHistory": false,
"messages": [
{ "role": "user", "content": "Based on what you know about me, write me 10 ideas to improve my business." }
]
}

Custom System Prompt

Override or extend your BuddyPro system prompt per request using x_buddy_systemPrompt and x_buddy_systemPromptMode.

ModeBehavior
"replace"Completely replaces your system prompt
"add" (default)Appends to the existing system prompt

Replace mode — custom persona:

{
"x_buddy_systemPrompt": "You are now an email writing assistant. Your response must always be an email draft based on the user's request and your know-how. Do not include any explanations or additional text.",
"x_buddy_systemPromptMode": "replace",
"messages": [
{ "role": "user", "content": "Write an email about 50% sale on the Business Mastery program." }
]
}

Add mode — extend existing prompt:

{
"x_buddy_systemPrompt": "IMPORTANT: Write your next response strictly in Spanish. No comments, just answer.",
"x_buddy_systemPromptMode": "add",
"messages": [
{ "role": "user", "content": "How would you write a message to invite people to join my new program?" }
]
}

Validation rules for x_buddy_systemPrompt:

  • Max 50,000 characters
  • Script tags (<script>...</script>) are stripped
  • Control characters are stripped (newlines, tabs, and carriage returns are preserved)
note

If x_buddy_systemPromptMode is omitted, it defaults to "add".


Response

Response Headers

HeaderDescription
x-request-idServer-generated unique request ID (always present)
x-client-request-idClient-supplied request ID echoed back (present only if provided)
Content-Typeapplication/json

Success — Text Only

{
"id": "chatcmpl-req_abc123def456",
"object": "chat.completion",
"created": 1710964800,
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "Hello! I'm doing well. How can I help you?"
},
"finish_reason": "stop"
}
]
}

Success — Image Output

When BuddyPro generates an image, it appears in message.image:

{
"id": "chatcmpl-req_def456",
"object": "chat.completion",
"created": 1710964800,
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "Here's the image you requested:",
"image": {
"id": "image_req_def456_generated_image.png",
"data": "iVBORw0KGgo...",
"media_type": "image/png",
"file_name": "generated_image.png",
"caption": "A sunset over the ocean"
}
},
"finish_reason": "stop"
}
]
}

Success — Audio Output (Music / Meditation)

Audio from music or meditation features is always returned regardless of modalities:

{
"id": "chatcmpl-req_ghi789",
"object": "chat.completion",
"created": 1710964800,
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": null,
"audio": {
"id": "audio_req_ghi789_response.ogg",
"data": "<base64>",
"format": "ogg",
"transcript": null,
"media_type": "audio/ogg",
"file_name": "response.ogg"
}
},
"finish_reason": "stop"
}
]
}

Success — Text + TTS Audio

When TTS is enabled via modalities and audio input was sent:

{
"id": "chatcmpl-req_abc123",
"object": "chat.completion",
"created": 1710964800,
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "Why don't scientists trust atoms? Because they make up everything!",
"audio": {
"id": "audio_req_abc123_response.mp3",
"data": "<base64>",
"format": "mp3",
"transcript": "Why don't scientists trust atoms? Because they make up everything!",
"media_type": "audio/mpeg",
"file_name": "response.mp3"
}
},
"finish_reason": "stop"
}
]
}
note

When audio output is present, transcript contains the same text as content (the concatenated text response).

Response Fields Reference

Top-level

FieldTypeDescription
idstringUnique completion ID: chatcmpl-{requestId}
objectstringAlways "chat.completion"
creatednumberUnix timestamp (seconds) of request start
choicesarrayArray with single choice (index 0)
note

Request ID and processing time metadata are available via response headers (X-Request-Id, X-Client-Request-Id) — they are not included in the response body.

choices[0].message

FieldTypeDescription
rolestringAlways "assistant"
contentstring | nullConcatenated text response. null if only media
audioobject | undefinedAudio output (first audio item). See below
imageobject | undefinedImage output (first image item). See below

message.audio (OpenAiAudioOutput)

FieldTypeDescription
idstringAudio identifier: audio_{requestId}_{fileName}
datastringBase64-encoded audio data
formatstringAudio format (e.g., mp3, ogg, wav)
transcriptstring | undefinedText transcript (same as content when TTS)
media_typestringMIME type (e.g., audio/mpeg, audio/ogg)
file_namestringSuggested filename

message.image (OpenAiImageOutput — BuddyPro Extension)

FieldTypeDescription
idstringImage identifier: image_{requestId}_{fileName}
datastringBase64-encoded image data
media_typestringMIME type (e.g., image/png)
file_namestringSuggested filename
captionstringImage caption/description

Error Response

All errors use a structured format with an error object:

{
"error": {
"message": "Invalid or inactive API key",
"type": "authentication_error",
"statusCode": 401,
"code": "invalid_api_key",
"param": null
}
}
Important

Always inspect the response body for the error field — do not rely solely on the HTTP status code. In certain conditions, the HTTP status code may be 200 even when the response body contains an error.

Error Fields

FieldTypeDescription
error.messagestringHuman-readable error description
error.typestringError category
error.statusCodenumberHTTP status code
error.codestring | nullMachine-readable error code
error.paramstring | nullThe request parameter that caused the error

Error Types

HTTP StatustypeDescription
400invalid_request_errorMalformed request, missing fields, invalid content
401authentication_errorMissing or invalid API key
403permission_errorInsufficient permissions
405method_not_allowedWrong HTTP method
410goneDeprecated endpoint no longer available
429rate_limit_errorRate limit exceeded
500server_errorInternal server error

Common Error Codes

CodeMeaning
invalid_jsonRequest body is not valid JSON
missing_required_parameterRequired field missing
missing_api_keyNo API key provided in Authorization header
invalid_api_keyAPI key not found or inactive
invalid_valueField has wrong type or invalid value
invalid_text_contentText empty or exceeds 50,000 char limit
invalid_content_typeUnknown content part type
invalid_contentContent has no usable items
invalid_media_dataMedia data invalid, download failed, or exceeds size limit
invalid_media_typeUnsupported MIME type
invalid_audio_formatUnsupported audio format
invalid_image_countToo many images (max 5)
invalid_parameterInvalid parameter value (e.g., bad user, x_buddy_systemPrompt, x_buddy_systemPromptMode, or x_buddy_saveToHistory)
insufficient_permissionsAPI key lacks required permissions
endpoint_deprecatedAPI version has been deprecated and is no longer available
rate_limit_exceededMore than 30 requests/minute

Rate Limits

  • 30 requests per minute per API key

Limitations

LimitationDetail
No streamingStreaming is not supported yet
Single user messageOnly 1 user message in messages array (BuddyPro manages history)
No model selectionmodel field is accepted but ignored, BuddyPro has its own model implementation
No usage statsusage object is not included in responses
First media winsOnly the first audio and first image in the response are surfaced per choice
Voice not controllableaudio.voice is accepted but ignored — voice is set by the bot owner

Media Limits

  • Max 5 images per request
  • Max 40 MB per media download (URL-fetched media)
  • Max 50,000 characters per text content part

Quick Start

curl — Text

curl -X POST https://api.buddypro.ai/v1/chat/completions \
-H "Authorization: Bearer bapi_xxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"messages": [
{ "role": "user", "content": "What is the weather like today?" }
]
}'

curl — Multimodal (Image + Text)

curl -X POST https://api.buddypro.ai/v1/chat/completions \
-H "Authorization: Bearer bapi_xxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"messages": [
{
"role": "user",
"content": [
{ "type": "text", "text": "What is in this image?" },
{ "type": "image_url", "image_url": { "url": "https://example.com/photo.jpg" } }
]
}
]
}'

curl — Audio Input with TTS Output

curl -X POST https://api.buddypro.ai/v1/chat/completions \
-H "Authorization: Bearer bapi_xxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"modalities": ["text", "audio"],
"audio": { "format": "mp3" },
"messages": [
{
"role": "user",
"content": [
{ "type": "input_audio", "input_audio": { "data": "<base64>", "format": "mp3" } }
]
}
]
}'

curl — Named User (Isolation)

curl -X POST https://api.buddypro.ai/v1/chat/completions \
-H "Authorization: Bearer bapi_xxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"user": "test-user-joe",
"messages": [
{ "role": "user", "content": "Hello!" }
]
}'

curl — Stateless Mode

curl -X POST https://api.buddypro.ai/v1/chat/completions \
-H "Authorization: Bearer bapi_xxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"x_buddy_saveToHistory": false,
"messages": [
{ "role": "user", "content": "What is 2 + 2?" }
]
}'

curl — Custom System Prompt

curl -X POST https://api.buddypro.ai/v1/chat/completions \
-H "Authorization: Bearer bapi_xxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"x_buddy_systemPrompt": "You are a helpful coding assistant. Only answer programming questions.",
"x_buddy_systemPromptMode": "replace",
"messages": [
{ "role": "user", "content": "How do I reverse a string in JavaScript?" }
]
}'

Important Notes

  • Do not send conversation history — send only the current user message. BuddyPro stores and manages conversation context internally.
  • By default, API requests use the profile that generated the API key — conversations are saved to its history and contribute to its memory. Use /test before key generation to bind the key to a test account. Use the user field for additional isolated profiles.
  • Use x_buddy_saveToHistory: false for stateless Q&A — nothing is stored to chat history, memory, or profile.
  • Named test user profiles (user field) are not private from the API key owner. Do not use them for real people's private data.
  • The API processes requests synchronously — the response is returned when BuddyPro finishes generating.
  • SSRF protection: URLs pointing to private/internal network addresses are blocked.