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).
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
| Property | Value |
|---|---|
| Path | POST /v1/chat/completions |
| Auth | Authorization: Bearer bapi_... header |
| Format | OpenAI Chat Completions compatible |
| Streaming | Not 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.
- There is no stateless mode yet. Every request is stored and affects the profile. A future API extension will support stateless queries that don't save to memory or history, but this is not yet available.
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
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.
Recommended use cases for the Owner API
- 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
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
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.
Authentication
Getting an API Key
When you generate an API key, it is tied to the profile that generated it. All API conversations are saved into that profile's message history and contribute to its memory — even though you don't see those conversations in Telegram. Generate API keys on a testing account (use /test in Telegram first) 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.
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
| Command | Description |
|---|---|
/generateApiKey:{name} | Create a new API key |
/invalidateApiKey:{name} | Revoke a key by name or raw key |
/getApiStats | List 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.
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 20,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 URI —
data: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:
| Field | Type | Description |
|---|---|---|
data | string | Base64-encoded audio data or URL |
format | string | Audio 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
modalitiesincludes"audio", TTS is enabled audio.formatdefaults to"mp3"if omitted- TTS only applies when audio input is present in the request
audio.voiceis accepted but ignored — voice is set by the bot owner
Request Fields Reference
| Field | Type | Required | Description |
|---|---|---|---|
messages | array | Yes | OpenAI-format messages. Must contain exactly 1 user message. |
modalities | ["text"] | ["text", "audio"] | — | Output types. Include "audio" to enable TTS |
audio | object | — | Audio config: { "format": "mp3"|"wav" } |
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.
Response
Response Headers
| Header | Description |
|---|---|
x-request-id | Server-generated unique request ID (always present) |
x-client-request-id | Client-supplied request ID echoed back (present only if provided) |
Content-Type | application/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"
}
]
}
When audio output is present, transcript contains the same text as content (the concatenated text response).
Response Fields Reference
Top-level
| Field | Type | Description |
|---|---|---|
id | string | Unique completion ID: chatcmpl-{requestId} |
object | string | Always "chat.completion" |
created | number | Unix timestamp (seconds) of request start |
choices | array | Array with single choice (index 0) |
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
| Field | Type | Description |
|---|---|---|
role | string | Always "assistant" |
content | string | null | Concatenated text response. null if only media |
audio | object | undefined | Audio output (first audio item). See below |
image | object | undefined | Image output (first image item). See below |
message.audio (OpenAiAudioOutput)
| Field | Type | Description |
|---|---|---|
id | string | Audio identifier: audio_{requestId}_{fileName} |
data | string | Base64-encoded audio data |
format | string | Audio format (e.g., mp3, ogg, wav) |
transcript | string | undefined | Text transcript (same as content when TTS) |
media_type | string | MIME type (e.g., audio/mpeg, audio/ogg) |
file_name | string | Suggested filename |
message.image (OpenAiImageOutput — BuddyPro Extension)
| Field | Type | Description |
|---|---|---|
id | string | Image identifier: image_{requestId}_{fileName} |
data | string | Base64-encoded image data |
media_type | string | MIME type (e.g., image/png) |
file_name | string | Suggested filename |
caption | string | Image 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
}
}
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
| Field | Type | Description |
|---|---|---|
error.message | string | Human-readable error description |
error.type | string | Error category |
error.statusCode | number | HTTP status code |
error.code | string | null | Machine-readable error code |
error.param | string | null | The request parameter that caused the error |
Error Types
| HTTP Status | type | Description |
|---|---|---|
| 400 | invalid_request_error | Malformed request, missing fields, invalid content |
| 401 | authentication_error | Missing or invalid API key |
| 403 | permission_error | Insufficient permissions |
| 405 | method_not_allowed | Wrong HTTP method |
| 410 | gone | Deprecated endpoint no longer available |
| 429 | rate_limit_error | Rate limit exceeded |
| 500 | server_error | Internal server error |
Common Error Codes
| Code | Meaning |
|---|---|
invalid_json | Request body is not valid JSON |
missing_required_parameter | Required field missing |
missing_api_key | No API key provided in Authorization header |
invalid_api_key | API key not found or inactive |
invalid_value | Field has wrong type or invalid value |
invalid_text_content | Text empty or exceeds 20,000 char limit |
invalid_content_type | Unknown content part type |
invalid_content | Content has no usable items |
invalid_media_data | Media data invalid, download failed, or exceeds size limit |
invalid_media_type | Unsupported MIME type |
invalid_audio_format | Unsupported audio format |
invalid_image_count | Too many images (max 5) |
insufficient_permissions | API key lacks required permissions |
endpoint_deprecated | API version has been deprecated and is no longer available |
rate_limit_exceeded | More than 30 requests/minute |
Rate Limits
- 30 requests per minute per API key
Limitations
| Limitation | Detail |
|---|---|
| No streaming | Streaming is not supported yet |
| Single user message | Only 1 user message in messages array (BuddyPro manages history) |
| No model selection | model field is accepted but ignored, BuddyPro has it's own models implementation |
| No usage stats | usage object is not included in responses |
| First media wins | Only the first audio and first image in the response are surfaced per choice |
| Voice not controllable | audio.voice is accepted but ignored — voice is set by the bot owner |
| No stateless mode | All requests are saved to memory and chat history. Stateless queries coming in a future update |
Media Limits
- Max 5 images per request
- Max 40 MB per media download (URL-fetched media)
- Max 20,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" } }
]
}
]
}'
Important Notes
- Do not send conversation history — send only the current user message. BuddyPro stores and manages conversation context internally.
- API conversations are saved to the key owner's profile and message history, even though they don't appear in Telegram.
- Use
/testbefore generating API keys to keep API interactions separate from your personal profile. - The API processes requests synchronously — the response is returned when BuddyPro finishes generating.
- SSRF protection: URLs pointing to private/internal network addresses are blocked.