btelo.com HTTP API. This document is the complete, authoritative contract — any third party (human or AI) should be able to integrate using ONLY this JSON, without additional communication.
Quickstart
1. Ask a btelo admin to create an Integration for you. You will receive (integration_id, secret).
2. Store the secret server-side. Never ship it to browsers. The secret itself is never sent over the wire — each request carries only a short-lived HMAC signature derived from it.
3. For API calls (server-to-server): sign each request with the HMAC scheme documented in `auth.hmac` (secret stays local; only `Btelo-Sign` is transmitted, valid for ±5 min).
4. For end-user login (OAuth2 SSO): send users to /api/oauth/authorize, exchange the code at /api/oauth/token using your integration_id + secret as client_id + client_secret.
5. If you are an automation (e.g. AI agent) that needs to REGISTER OTHER INTEGRATIONS programmatically, ask the admin to set is_admin=true on your integration. You can then call /admin/integrations/* via the same HMAC auth.
Authentication
Each third-party product ("integration") is registered in the btelo admin console and gets ONE pair of credentials: (integration_id, secret). The same pair is used for BOTH server-to-server API calls (HMAC below) AND OAuth login (client_id=integration_id, client_secret=secret on the /api/oauth/token endpoint). The secret can be viewed or rotated by the admin at any time. A disabled integration is rejected by both flows.
HMAC-SHA256
Server-to-server API endpoints (including /admin/integrations/* for admin integrations) require 3 headers. The secret is never transmitted — only a time-limited HMAC signature.
Headers
Btelo-Key-Id
The integration_id (public identifier).
Btelo-Sign
First 16 hex chars of HMAC-SHA256("<integration_id>:<timestamp>", <secret>)
Btelo-Ts
Current Unix timestamp (seconds). Must be within ±5 minutes of server time.
Start an OAuth 2.0 authorization code flow. Redirects the user to the btelo.com login page, then back to your redirect_uri with ?code=... on success. Desktop/mobile clients must use PKCE (RFC 7636) by passing code_challenge — this allows the subsequent /api/oauth/token call to omit client_secret.
Name
In
Type
Required
Description
client_id
query
string
required
Your integration_id.
redirect_uri
query
string
required
URI to redirect to after authorization. Must match a registered URI for the client.
response_type
query
string
required
Must be "code".
state
query
string
optional
Opaque value echoed back in the redirect to prevent CSRF.
PKCE code challenge: base64url(SHA256(code_verifier)). When present, /api/oauth/token requires the matching code_verifier and does not require client_secret.
code_challenge_method
query
string
optional
Only "S256" is supported (default when code_challenge is set). "plain" is rejected.
Response
error
302 redirect to redirect_uri?error=...
success
302 redirect to redirect_uri?code=AUTH_CODE&state=...
Example
GET https://btelo.com/api/oauth/authorize?client_id=CLIENT_ID&redirect_uri=https://yourapp.com/callback&response_type=code&state=xyz&scope=openid+profile+email&code_challenge=CHALLENGE&code_challenge_method=S256
POST/api/oauth/token
Exchange an authorization code for a JWT access token, or refresh an existing token. Two flows are supported: (1) confidential-client flow requires client_secret; (2) PKCE public-client flow (for desktop/mobile apps) requires code_verifier instead — client_secret is optional and may be omitted entirely.
Name
In
Type
Required
Description
grant_type
body (form)
string
required
"authorization_code" or "refresh_token".
code
body (form)
string
optional
The authorization code from /api/oauth/authorize (required when grant_type=authorization_code).
redirect_uri
body (form)
string
optional
Must match the redirect_uri used in /api/oauth/authorize.
refresh_token
body (form)
string
optional
Required when grant_type=refresh_token.
client_id
body (form)
string
required
Your integration_id.
client_secret
body (form)
string
optional
Integration secret. Required for confidential-client flow (no code_challenge at authorize time). Optional for PKCE flow — omit it on desktop/mobile clients that cannot safely hold a secret.
code_verifier
body (form)
string
optional
PKCE verifier (RFC 7636). Required when grant_type=authorization_code and the original /api/oauth/authorize call used code_challenge. Server verifies base64url(SHA256(code_verifier)) == stored code_challenge.
Response
content_type
application/json
schema
access_token
Signed JWT (RS256) — use as Bearer token
expires_in
Seconds until the access token expires
refresh_token
Opaque token to obtain a new access token
scope
Granted scopes
token_type
"Bearer"
Example
POST https://btelo.com/api/oauth/token body (PKCE): grant_type=authorization_code&code=CODE&redirect_uri=...&client_id=...&code_verifier=VERIFIER
GET/api/oauth/userinfo
Returns the authenticated user's profile. Requires a valid Bearer access token obtained from /api/oauth/token.
Name
In
Type
Required
Description
Authorization
header
string
required
Bearer <access_token>
Response
content_type
application/json
schema
email
User email address
name
Display name
picture
Avatar URL
sub
Unique user ID
Example
GET https://btelo.com/api/oauth/userinfo Authorization: Bearer <access_token>
GET/api/oauth/jwks.json
Returns the RSA public key set (JWKS) used to verify JWT access tokens issued by /api/oauth/token.
Response
content_type
application/json
schema
RFC 7517 JSON Web Key Set
Example
GET https://btelo.com/api/oauth/jwks.json
Auth
GET/api/auth/me
Returns the currently logged-in user's profile (session cookie required). Returns 401 if not authenticated.
Response
content_type
application/json
schema
avatar_url
Avatar URL
bio
User bio / description
email
Email address
id
User ID
name
Display name
owner_apps
Array of app slugs this user owns, e.g. ["vibe-remote"].
provider
Auth provider (google, email)
Example
GET https://btelo.com/api/auth/me
Profile
GET/api/profile
Returns the authenticated user's editable profile. Auth: session cookie (browser) or Btelo-Api-Key + user_id (server-to-server).
Response
content_type
application/json
schema
avatar_url
Avatar URL
bio
User bio / description
email
Email address
id
User ID
name
Display name
owner_apps
Array of app slugs this user owns, e.g. ["vibe-remote"].
provider
Auth provider (google, email)
Example
GET https://btelo.com/api/profile (Cookie: btelo_session=... or Authorization: Bearer ...)
PUT/api/profile
Update the authenticated user's profile. Send only the fields you want to change. Auth: session cookie (browser) or Btelo-Api-Key + user_id (server-to-server).
Name
In
Type
Required
Description
name
body (JSON)
string
optional
Display name.
avatar_url
body (JSON)
string
optional
Avatar image URL.
bio
body (JSON)
string
optional
Short bio / description.
Response
content_type
application/json
schema
avatar_url
Avatar URL (updated)
bio
Bio (updated)
email
Email address
id
User ID
name
Display name (updated)
owner_apps
Array of app slugs this user owns.
provider
Auth provider
Example
PUT https://btelo.com/api/profile body: {"name":"New Name","bio":"Hello world"}
POST/api/account/delete
Delete the currently logged-in account. Requires a browser session cookie; HMAC/API-key auth is intentionally not accepted. The user must manually type their full user id and send it as user_id_confirm. The backend validates an exact match before deleting. Account/login/app state is removed; historical order rows are retained for legal/accounting audit. This endpoint does not cancel Apple or Stripe subscriptions; users must cancel those in Apple subscriptions or Stripe billing.
Name
In
Type
Required
Description
Cookie
header
string
required
btelo_session=<session token>.
user_id_confirm
body (JSON or form)
string
required
The exact current user's 32-char btelo user id, typed manually by the user.
Response
content_type
application/json for JSON requests; otherwise 303 redirect
errors
401 when not logged in; 400 when user_id_confirm is missing or does not exactly match the session user id.
success
{
"ok": true,
"deleted": true
}
Example
POST https://btelo.com/api/account/delete Cookie: btelo_session=... body: {"user_id_confirm":"32hexuserid"}
POST/api/profile/inviter
Bind the authenticated user to an inviter by invite code. This is allowed after registration only if the user does not already have an inviter. Once set, the inviter cannot be changed. Future successful subscription payments use this inviter relationship to apply regular invite rewards or share-partner commission ledger entries.
Name
In
Type
Required
Description
invite_code
body (JSON or form)
string
required
Invite code to bind. `code` is also accepted as an alias.
Response
content_type
application/json
errors
400
Invalid code, unknown code, or self-invite.
409
The user already has an inviter and it cannot be changed.
schema
invite_code
Normalized invite code snapshot
inviter_id
User ID of the inviter
ok
true on success
source
"regular" or "affiliate", frozen at bind time
Example
POST https://btelo.com/api/profile/inviter body: {"invite_code":"streamer-jenny"}
Email
POST/api/email/send
Send an email to a user immediately, or schedule it for a future time. Requires Btelo-Api-Key header.
Name
In
Type
Required
Description
Btelo-Key-Id
header
string
required
API key ID.
Btelo-Ts
header
string
required
Unix timestamp (±5 min).
Btelo-Sign
header
string
required
First 16 hex chars of HMAC-SHA256(key_id:timestamp, secret).
user_id
body (JSON)
string
required
Target user ID.
subject
body (JSON)
string
required
Email subject line.
html
body (JSON)
string
required
Email HTML body.
send_at
body (JSON)
string
optional
RFC3339 timestamp for scheduled send (e.g. "2026-04-20T10:00:00Z"). Omit for immediate send.
Response
content_type
application/json
schema
email
Target email address
id
Scheduled email ID
send_at
Scheduled send time (RFC3339)
status
"sending" (immediate) or "scheduled" (future)
subject
Email subject
user_id
Target user ID
Example
POST https://btelo.com/api/email/send Btelo-Key-Id: ... Btelo-Ts: ... Btelo-Sign: ... body: {"user_id":"abc","subject":"Hello","html":"<h1>Hi</h1>"}
GET/api/email/scheduled
List scheduled emails. Optionally filter by user_id. Requires Btelo-Api-Key header.
Name
In
Type
Required
Description
Btelo-Key-Id
header
string
required
API key ID.
Btelo-Ts
header
string
required
Unix timestamp (±5 min).
Btelo-Sign
header
string
required
First 16 hex chars of HMAC-SHA256(key_id:timestamp, secret).
user_id
query
string
optional
Filter by target user ID.
Response
content_type
application/json
schema
emails
Array of {id, user_id, subject, send_at, sent_at, canceled}
Example
GET https://btelo.com/api/email/scheduled?user_id=abc Btelo-Key-Id: ... Btelo-Ts: ... Btelo-Sign: ...
DELETE/api/email/scheduled/{id}
Cancel a pending scheduled email before it is sent. Requires Btelo-Api-Key header.
Name
In
Type
Required
Description
Btelo-Key-Id
header
string
required
API key ID.
Btelo-Ts
header
string
required
Unix timestamp (±5 min).
Btelo-Sign
header
string
required
First 16 hex chars of HMAC-SHA256(key_id:timestamp, secret).
id
path
string
required
Scheduled email ID.
Response
status
204 No Content on success, 404 if not found or already sent
GET https://btelo.com/api/v1/tiers Authorization: Bearer <user_jwt>
GET/api/v1/subscription
Get a user's current subscription status. Auth: Bearer user JWT (user_id inferred from token) OR HMAC + user_id. With Bearer, query user_id is ignored.
Name
In
Type
Required
Description
Authorization
header
string
optional
Bearer <user_jwt> (recommended).
Btelo-Key-Id
header
string
optional
HMAC key ID (alternative).
Btelo-Ts
header
string
optional
Required with HMAC.
Btelo-Sign
header
string
optional
Required with HMAC.
user_id
query
string
optional
Btelo user ID. Required for HMAC; ignored for Bearer.
tier
query
string
optional
Check if user has access to this tier level (returns has_access field).
POST https://btelo.com/api/v1/credits/checkout-url Authorization: Bearer <user_jwt> body: {"slug":"credits-500","success_url":"https://yourapp.com/ok","cancel_url":"https://yourapp.com/cancel"}
POST/api/v1/entitlements/quote
Calculate the wallet credit cost for a product entitlement price. This does not require btelo-side SKU configuration: product servers choose their own SKU names and dollar prices, and btelo converts price_cents to credits using the same credit price curve used by credit purchases. Auth: Bearer user JWT OR HMAC.
Name
In
Type
Required
Description
Authorization
header
string
optional
Bearer <user_jwt>.
Btelo-Key-Id
header
string
optional
HMAC key ID (alternative).
Btelo-Ts
header
string
optional
Required with HMAC.
Btelo-Sign
header
string
optional
Required with HMAC.
price_cents
body (JSON)
integer
required
Dollar price in cents, e.g. 5000 for $50. btelo returns the matching cost_credits.
POST https://btelo.com/api/v1/entitlements/quote Authorization: Bearer <user_jwt> body: {"price_cents":5000}
GET/api/v1/entitlements
List active product entitlements for a user, or check one product/SKU pair. Auth: Bearer user JWT (user_id inferred from token) OR HMAC + user_id. With Bearer, query user_id is ignored.
Name
In
Type
Required
Description
Authorization
header
string
optional
Bearer <user_jwt>.
Btelo-Key-Id
header
string
optional
HMAC key ID (alternative).
Btelo-Ts
header
string
optional
Required with HMAC.
Btelo-Sign
header
string
optional
Required with HMAC.
user_id
query
string
optional
Required for HMAC; ignored for Bearer.
product
query
string
optional
Product integration slug, e.g. vibe-remote.
sku
query
string
optional
Product-defined SKU, e.g. lifetime or pro-lifetime. When product and sku are both provided, response includes active.
GET https://btelo.com/api/v1/entitlements?product=vibe-remote&sku=lifetime Authorization: Bearer <user_jwt>
POST/api/v1/entitlements/redeem
Redeem wallet credits for a product entitlement. This is the recommended buyout/lifetime access flow. No btelo-side product/SKU configuration is required: the authenticated product backend sends its own SKU and price_cents. This endpoint is HMAC-only so users cannot forge dynamic prices from the browser. The product defaults to Btelo-Key-Id and, if provided, must match Btelo-Key-Id. Currently only lifetime entitlements are supported. Repeated redemption of the same active user/product/sku returns the existing entitlement without deducting credits again.
Name
In
Type
Required
Description
Btelo-Key-Id
header
string
required
Integration ID. This becomes the product slug unless body.product is provided with the same value.
Btelo-Ts
header
string
required
Unix timestamp (±5 min).
Btelo-Sign
header
string
required
First 16 hex chars of HMAC-SHA256(key_id:timestamp, secret).
user_id
query or X-User-ID header
string
required
Btelo user ID receiving the entitlement.
product
body (JSON)
string
optional
Product slug. Omit to use Btelo-Key-Id. If provided, it must match Btelo-Key-Id.
sku
body (JSON)
string
optional
Product-defined SKU. Defaults to lifetime.
name
body (JSON)
string
optional
Display name for audit/support views.
kind
body (JSON)
string
optional
Entitlement kind. Defaults to lifetime; only lifetime is currently supported.
price_cents
body (JSON)
integer
required
Product price in cents. btelo computes cost_credits from this value using the credit price curve.
idempotency_key
body (JSON)
string
optional
Optional product-side idempotency key. When omitted, btelo uses user_id:product:sku:kind.
Response
content_type
application/json
errors
401
Missing or invalid HMAC headers. Bearer JWT is not accepted for redeem.
Check whether a user is marked as an owner of an app. Btelo admins set owner apps on the user detail page. Auth: Bearer user JWT (user_id inferred from token) OR HMAC + user_id. With Bearer, query user_id is ignored.
Name
In
Type
Required
Description
Authorization
header
string
optional
Bearer <user_jwt> (recommended).
Btelo-Key-Id
header
string
optional
HMAC key ID (alternative).
Btelo-Ts
header
string
optional
Required with HMAC.
Btelo-Sign
header
string
optional
Required with HMAC.
user_id
query
string
optional
Required for HMAC; ignored for Bearer.
app
query
string
optional
App slug to check, e.g. vibe-remote. When omitted, the response only lists owner_apps.
GET https://btelo.com/api/v1/ownership?app=vibe-remote Authorization: Bearer <user_jwt>
AI Proxy
GET/api/ai/readme
Returns the AI proxy API documentation as JSON. Lists all AI endpoints, auth requirements, and request/response formats.
Response
content_type
application/json
Example
GET https://btelo.com/api/ai/readme
GET/api/ai/quota
Get the caller's current monthly AI-credit allowance and wallet balance. Use this to render a usage gauge before making AI calls. Auth: Bearer user JWT (required — HMAC not supported on this endpoint).
GET https://btelo.com/api/ai/quota Authorization: Bearer <user_jwt>
POST/v1/images/generations
OpenAI image generation with auto-resize. Auth: Bearer user JWT OR HMAC. Bearer calls are metered per-user.
Name
In
Type
Required
Description
Authorization
header
string
optional
Bearer <user_jwt> (recommended).
Btelo-Product
header
string
optional
Registered product slug. Required on Bearer path.
Btelo-Key-Id
header
string
optional
HMAC key ID (alternative).
Btelo-Ts
header
string
optional
Required with HMAC.
Btelo-Sign
header
string
optional
Required with HMAC.
Example
POST https://btelo.com/v1/images/generations Authorization: Bearer <user_jwt> Btelo-Product: btelo-up
POST/v1/audio/speech
OpenAI text-to-speech proxy. Auth: Bearer user JWT OR HMAC. Bearer calls are metered per-user.
Name
In
Type
Required
Description
Authorization
header
string
optional
Bearer <user_jwt> (recommended).
Btelo-Product
header
string
optional
Registered product slug. Required on Bearer path.
Btelo-Key-Id
header
string
optional
HMAC key ID (alternative).
Btelo-Ts
header
string
optional
Required with HMAC.
Btelo-Sign
header
string
optional
Required with HMAC.
Example
POST https://btelo.com/v1/audio/speech Authorization: Bearer <user_jwt> Btelo-Product: btelo-up
GET/api/ai/pricing
Public price list for every enabled model, normalized to credits. Chat rates are credits per 1k input/output/cache-read/cache-write tokens; image rates are credits per single image for each (model,size,quality) combo; TTS rates are credits per 1k characters. Use this to label model pickers with authoritative, always-fresh cost info — re-fetch on startup and whenever model admin state may have changed.
Convert one user-uploaded image into a fully-spec-compliant macOS + iOS app-icon bundle. Returns a ZIP containing: macos/icon.icns (drop-in binary), macos/icon.iconset/* (Apple squircle template, 16-1024 px with @2x), and ios/AppIcon.appiconset/* (iPhone + iPad full-bleed PNGs at every standard size, plus 1024 marketing image and a preconfigured Contents.json). Pure CPU work — no upstream AI is called. Flat 50 credits per request; free when called with Btelo-Product: btelo-up.
Name
In
Type
Required
Description
Authorization
header
string
optional
Bearer <user_jwt> (recommended).
Btelo-Product
header
string
optional
Registered product slug. Required on Bearer path. Setting it to "btelo-up" waives the credit charge.
Btelo-Key-Id
header
string
optional
HMAC key ID (alternative).
Btelo-Ts
header
string
optional
Required with HMAC.
Btelo-Sign
header
string
optional
Required with HMAC.
image
body (multipart/form-data)
file
required
Source image (PNG or JPEG). Any aspect/size — will be center-fit and resized to a 1024×1024 working canvas.
Response
content_type
application/zip
schema
ZIP archive: macos/icon.icns, macos/icon.iconset/icon_NxN[@2x].png, ios/AppIcon.appiconset/Contents.json + Icon-N.png set, README.txt.
Example
POST https://btelo.com/v1/images/icon-pack Authorization: Bearer <user_jwt> Btelo-Product: btelo-up -F [email protected]
POST/v1/minimax/video/generation
MiniMax video generation (synchronous wrapper — the server submits the async task, polls every 5s up to 5 min, then returns the final download URL). Billed once at submission per (model, resolution, duration); full refund on upstream failure or timeout. The (model, resolution, duration) triple must match an enabled row in the video price table (see GET /api/ai/pricing → video). Auth: Bearer user JWT OR HMAC.
Name
In
Type
Required
Description
Authorization
header
string
optional
Bearer <user_jwt> (recommended).
Btelo-Product
header
string
optional
Registered product slug. Required on Bearer path.
Btelo-Key-Id
header
string
optional
HMAC key ID (alternative).
Btelo-Ts
header
string
optional
Required with HMAC.
Btelo-Sign
header
string
optional
Required with HMAC.
model
body (JSON)
string
required
MiniMax video model slug (e.g. MiniMax-Hailuo-02, MiniMax-Hailuo-2.3, MiniMax-Hailuo-2.3-Fast).
prompt
body (JSON)
string
required
Text description of the desired video.
resolution
body (JSON)
string
required
512P | 768P | 1080P (must match enabled price row for the model).
duration
body (JSON)
integer
required
Video duration in seconds: 6 or 10 (must match enabled price row).
MiniMax music generation (synchronous). Flat per-song charge for tracks up to 5 minutes. model must be an enabled music-* slug (music-2.6, music-2.5+, music-2.5, music-2.0). Auth: Bearer user JWT OR HMAC.
Name
In
Type
Required
Description
Authorization
header
string
optional
Bearer <user_jwt> (recommended).
Btelo-Product
header
string
optional
Registered product slug. Required on Bearer path.
Btelo-Key-Id
header
string
optional
HMAC key ID (alternative).
Btelo-Ts
header
string
optional
Required with HMAC.
Btelo-Sign
header
string
optional
Required with HMAC.
model
body (JSON)
string
required
Enabled music-* model slug (see GET /api/ai/pricing → music).
lyrics
body (JSON)
string
optional
Lyric text to sing (MiniMax schema).
prompt
body (JSON)
string
optional
Style / mood prompt.
audio_setting
body (JSON)
object
optional
MiniMax audio config (see MiniMax docs).
Response
content_type
application/json
schema
MiniMax music_generation response (passthrough).
Example
POST https://btelo.com/v1/minimax/music/generation Authorization: Bearer <user_jwt> Btelo-Product: btelo-up body: {"model":"music-2.6","lyrics":"...","prompt":"upbeat pop"}
POST/v1/minimax/music/lyrics
MiniMax lyrics generation. Flat per-song charge billed against the virtual 'lyrics-gen' model (see GET /api/ai/pricing → music). Auth: Bearer user JWT OR HMAC.
Anthropic Messages API wire format. Integrate with @anthropic-ai/sdk or any Anthropic-compatible client — callers see pure Anthropic semantics (messages, content blocks, tool_use, stop_reason). Upstream happens to be MiniMax's anthropic-compat endpoint, but that is an implementation detail. Distinct from /v1/responses (Codex) and /v1/chat/completions (OpenAI). Auth: Bearer user JWT OR HMAC. Bearer calls are metered against the user's subscription tier + wallet.
Name
In
Type
Required
Description
Authorization
header
string
optional
Bearer <user_jwt> (recommended).
Btelo-Product
header
string
optional
Registered product slug (e.g. btelo-up). Required on Bearer path.
Btelo-Key-Id
header
string
optional
HMAC key ID (alternative).
Btelo-Ts
header
string
optional
Required with HMAC.
Btelo-Sign
header
string
optional
Required with HMAC.
Example
POST https://btelo.com/v1/messages Authorization: Bearer <user_jwt> Btelo-Product: btelo-up
AI Proxy · Protocol B · OpenAI Chat Completions
POST/v1/chat/completions
OpenAI Chat Completions wire format. Use with OpenAI SDKs and legacy OpenAI-style clients. NOTE: codex 0.95+ does NOT use this path — codex speaks Responses API only (see /v1/responses). Distinct from /v1/messages (Anthropic) and /v1/responses (Codex). Supports streaming. Requires AI API key (HMAC headers or user JWT).
Name
In
Type
Required
Description
Btelo-Key-Id
header
string
optional
API key ID (HMAC path).
Btelo-Ts
header
string
optional
Unix timestamp (±5 min). Required with HMAC.
Btelo-Sign
header
string
optional
First 16 hex chars of HMAC-SHA256(key_id:timestamp, secret). Required with HMAC.
Authorization
header
string
optional
Bearer <user_jwt> as alternative to HMAC.
model
body (JSON)
string
optional
MiniMax model id (e.g. MiniMax-M2.7). Defaults to the active MiniMax config model.
messages
body (JSON)
array
required
OpenAI-format chat messages.
stream
body (JSON)
boolean
optional
If true, server streams SSE deltas.
Example
POST https://btelo.com/v1/chat/completions body: {"model":"MiniMax-M2.7","messages":[{"role":"user","content":"hi"}]}
Admin API
POST/admin/integrations
Register a new integration. Auth: admin session cookie OR HMAC from an integration with is_admin=true. Returns the created integration including the generated secret.
Name
In
Type
Required
Description
Btelo-Key-Id
header
string
optional
Admin integration ID (HMAC auth path). Omit when using session cookie.
Btelo-Ts
header
string
optional
Unix timestamp (±5 min). Required with HMAC auth.
Btelo-Sign
header
string
optional
HMAC signature. Required with HMAC auth.
id
body (JSON)
string
required
URL-safe slug chosen by caller (e.g. "auto-social"). Must be unique.
name
body (JSON)
string
required
Human-readable product name.
redirect_uris
body (JSON)
array<string>
optional
Allowed OAuth redirect URIs. Omit/empty if the integration only uses HMAC API. URIs under *.btelo.com are auto-allowed.
is_admin
body (JSON)
boolean
optional
If true, the new integration can call /admin/* endpoints. Default false.
Response
content_type
application/json
errors
400 invalid body · 409 id already exists
schema
created_at
YYYY-MM-DD HH:MM:SS
disabled
boolean
id
integration_id
is_admin
boolean
name
display name
redirect_uris
array of registered redirect URIs
secret
plaintext secret (bti_<hex>). Store securely. Can be viewed again via GET.
List all registered integrations. Secrets are included (plaintext) because they must be retrievable for re-display.
Name
In
Type
Required
Description
Btelo-Key-Id
header
string
optional
Admin integration ID (HMAC auth path).
Btelo-Ts
header
string
optional
Unix timestamp.
Btelo-Sign
header
string
optional
HMAC signature.
Response
content_type
application/json
schema
array of integration objects (same shape as POST /admin/integrations response)
status
200 OK
Example
GET https://btelo.com/admin/integrations Btelo-Key-Id: ... Btelo-Ts: ... Btelo-Sign: ...
PATCH/admin/integrations/{id}
Update an existing integration's name, redirect URIs, and admin flag. The secret is NOT changed (use /rotate for that). Pass the full desired redirect_uris list — the stored list is replaced, not merged.
Name
In
Type
Required
Description
id
path
string
required
integration_id to update.
Btelo-Key-Id
header
string
optional
Admin integration ID (HMAC auth path). Omit when using session cookie.
Btelo-Ts
header
string
optional
Unix timestamp (±5 min). Required with HMAC auth.
Btelo-Sign
header
string
optional
HMAC signature. Required with HMAC auth.
name
body (JSON)
string
required
Human-readable product name.
redirect_uris
body (JSON)
array<string>
optional
Full replacement list of allowed OAuth redirect URIs. Send [] to clear. URIs under *.btelo.com are auto-allowed regardless.
is_admin
body (JSON)
boolean
optional
Whether this integration can call /admin/* endpoints.
Response
content_type
application/json
errors
400 invalid body or empty name · 404 integration not found
schema
integration object (same shape as POST /admin/integrations response)
Rotate the secret of an existing integration. The previous secret is invalidated immediately. Returns the new plaintext secret.
Name
In
Type
Required
Description
id
path
string
required
integration_id.
Btelo-Key-Id
header
string
optional
Admin integration ID (HMAC auth path).
Btelo-Ts
header
string
optional
Unix timestamp.
Btelo-Sign
header
string
optional
HMAC signature.
Response
content_type
application/json
schema
id
integration_id
secret
new plaintext secret (bti_<hex>)
status
200 OK
Example
POST https://btelo.com/admin/integrations/vibe-remote/rotate Btelo-Key-Id: ... Btelo-Ts: ... Btelo-Sign: ...
POST/admin/integrations/{id}/disable
Enable or disable an integration without deleting it. Disabled integrations cannot authenticate (OAuth and HMAC both return 401).
Name
In
Type
Required
Description
id
path
string
required
integration_id.
disabled
body (JSON)
boolean
required
true to disable, false to re-enable.
Btelo-Key-Id
header
string
optional
Admin integration ID (HMAC auth path).
Btelo-Ts
header
string
optional
Unix timestamp.
Btelo-Sign
header
string
optional
HMAC signature.
Response
status
204 No Content
Example
POST https://btelo.com/admin/integrations/vibe-remote/disable Btelo-Key-Id: ... Btelo-Ts: ... Btelo-Sign: ... body: {"disabled":true}
AI Proxy · Protocol C · OpenAI Responses (Codex)
POST/v1/responses
OpenAI Responses API wire format — the protocol codex 0.95+ speaks to custom providers. Input items are message / function_call / function_call_output; tools are declared as flat {type,name,parameters}. Always SSE; events follow the response.* schema (response.created, response.output_item.added, response.output_text.delta, response.output_item.done, response.completed). Internally translated to Chat Completions before forwarding upstream and streamed back as Responses events. Distinct from /v1/messages (Anthropic protocol) and /v1/chat/completions (OpenAI Chat protocol) — they are NOT interchangeable. Codex clients SHOULD set model_provider.proxy.wire_api="responses" in ~/.codex/config.toml. Same auth, billing, and quota pipeline as the other AI proxy paths.
Name
In
Type
Required
Description
Authorization
header
string
optional
Bearer <user_jwt> (preferred), or use HMAC headers.
Always set true for codex; the endpoint always emits SSE.
Example
POST https://btelo.com/v1/responses body: {"model":"MiniMax-M2.7","instructions":"be helpful","input":[{"type":"message","role":"user","content":[{"type":"input_text","text":"hi"}]}],"stream":true}
AI Proxy · Protocol D · MiniMax Coding Plan MCP
POST/v1/coding_plan/search
Web-search tool exposed by the minimax-coding-plan-mcp server (the `web_search` MCP tool). Returns a structured JSON of organic results with title / link / snippet. Preferred over shell `curl` inside agent sandboxes — avoids dumping raw HTML into function_call_output. Same auth + billing pipeline as the other /v1 AI proxy routes.
Name
In
Type
Required
Description
Authorization
header
string
optional
Bearer <user_jwt> (preferred), or use HMAC headers.
query
body (JSON)
string
required
Search query. 3–5 keywords works best; include a date for time-sensitive topics.
Example
POST https://btelo.com/v1/coding_plan/search body: {"query":"codex CLI mcp config"}
POST/v1/coding_plan/vlm
Image-understanding tool exposed by the minimax-coding-plan-mcp server (the `understand_image` MCP tool). Analyzes images with AI based on text prompts. Supports JPEG/PNG/GIF/WebP up to 20MB. Same auth + billing pipeline as the other /v1 AI proxy routes.
Name
In
Type
Required
Description
Authorization
header
string
optional
Bearer <user_jwt> (preferred), or use HMAC headers.
prompt
body (JSON)
string
required
Question or instruction about the image.
image
body (JSON)
string
required
Image as URL, absolute path, or base64 data URI.
Example
POST https://btelo.com/v1/coding_plan/vlm body: {"prompt":"what is in this screenshot?","image":"https://.../shot.png"}
GET/api/ai/quota
Caller's current monthly allowance + wallet (requires user JWT).
GET/api/ai/usage
Caller's recent AI usage rows (requires user JWT). ?month=YYYY-MM optional.
User Meta
GET/api/meta
List every meta blob owned by the caller. Each entry has `kind`, `data` (verbatim JSON you stored), and `updated_at`.
GET https://btelo.com/api/meta Authorization: Bearer <jwt>
GET/api/meta/{kind}
Fetch a single meta blob by kind. 404 if absent. `kind` must match [a-z0-9_.-]{1,64}.
Name
In
Type
Required
Description
Authorization
header
string
required
Bearer <user_jwt>.
kind
path
string
required
Namespace slug for the blob (e.g. "settings", "editor.prefs").
Response
content_type
application/json
schema
{
kind: string,
data: any,
updated_at: string
}
Example
GET https://btelo.com/api/meta/settings Authorization: Bearer <jwt>
PUT/api/meta/{kind}
Create-or-update the blob under kind. Body must be valid JSON (object, array, number, string, boolean, or null) and ≤ 256 KiB. (user_id, kind) is the unique key — there is no separate POST/create.
Name
In
Type
Required
Description
Authorization
header
string
required
Bearer <user_jwt>.
kind
path
string
required
Namespace slug for the blob.
body
body (JSON)
any
required
Arbitrary JSON value stored verbatim.
Response
content_type
application/json
schema
{
kind: string,
data: any,
updated_at: string
}
Example
PUT https://btelo.com/api/meta/settings Authorization: Bearer <jwt> body: {"theme":"dark","lang":"en"}
DELETE/api/meta/{kind}
Remove the blob under kind. Idempotent — returns 204 even if the kind was already absent.
Return store product IDs for one app/platform. Client apps use this to discover StoreKit product IDs without hardcoding them. Auth: Bearer user JWT OR HMAC.
GET https://btelo.com/api/v1/billing/config?app_id=btelo-english&platform=apple Authorization: Bearer <user_jwt>
POST/api/v1/iap/apple/transactions
Sync an Apple StoreKit purchase to btelo. The app sends the transaction_id after purchase; btelo verifies it with Apple's App Store Server API, checks the configured bundle/product mapping, then records either a unified billing subscription or a one-time wallet credit transaction. The app should pass StoreKit appAccountToken during purchase when possible so Apple server notifications can be routed even if they arrive before this client sync. Auth: Bearer user JWT.
POST https://btelo.com/api/v1/iap/apple/transactions Authorization: Bearer <user_jwt> body: {"app_id":"btelo-english","transaction_id":"2000000123456789"}
POST/api/iap/apple/notifications
Apple App Store Server Notifications V2 receiver. Configure this exact URL as both Production and Sandbox Server URL for each app that uses btelo billing. This endpoint is called by Apple, not by client apps. A single shared URL is safe for multiple apps because btelo routes by bundleId + originalTransactionId/appAccountToken and validates product mappings before writing subscription state or wallet-credit transactions.
Name
In
Type
Required
Description
signedPayload
body (JSON)
string
required
Apple V2 signed notification payload.
Response
content_type
text/plain
schema
HTTP 200 when accepted or intentionally ignored; HTTP 500 for retryable update failures.
Example
App Store Connect -> My Apps -> <app> -> App Information -> App Store Server Notifications -> Version 2 -> Production/Sandbox URL = https://btelo.com/api/iap/apple/notifications
Billing Admin API
POST/api/v1/billing/apps
Create or update a billing app config. Auth: HMAC from an Integration with is_admin=true.
Name
In
Type
Required
Description
Btelo-Key-Id
header
string
required
Admin HMAC key ID.
id
body (JSON)
string
required
App id, e.g. btelo-english.
name
body (JSON)
string
required
Human app name.
ios_bundle_id
body (JSON)
string
optional
Apple bundle id for IAP verification.
disabled
body (JSON)
boolean
optional
Disable this billing app.
Example
POST https://btelo.com/api/v1/billing/apps <admin HMAC headers> body: {"id":"btelo-english","name":"Btelo English","ios_bundle_id":"com.btelo.english"}
POST/api/v1/billing/products
Create or update a store product mapping. Auth: HMAC from an Integration with is_admin=true.
Name
In
Type
Required
Description
Btelo-Key-Id
header
string
required
Admin HMAC key ID.
app_id
body (JSON)
string
required
Registered app id.
platform
body (JSON)
string
required
apple or stripe.
store_product_id
body (JSON)
string
required
Apple product id or Stripe price id.
kind
body (JSON)
string
optional
subscription (default) or wallet_credits.
tier
body (JSON)
string
optional
Btelo tier slug. Required when kind=subscription.
plan
body (JSON)
string
optional
month or year. Required when kind=subscription.
credit_slug
body (JSON)
string
optional
Btelo credit product slug, e.g. credits-5000. Used when kind=wallet_credits.
credits
body (JSON)
integer
optional
Wallet credits to add for this one-time product. Required when kind=wallet_credits unless credit_slug maps to a known Btelo credit product.
cents
body (JSON)
integer
optional
Store price in cents for audit/display.
Announcements
GET/api/v1/announcements
Return active announcements for one product app. Disabled announcements, expired announcements, and announcements for other apps are filtered out by btelo.com. Audience targeting is returned for product apps to evaluate locally.
Name
In
Type
Required
Description
Authorization
header
string
optional
Bearer <user_jwt>. Recommended when the app has the user's btelo JWT.
Btelo-Key-Id
header
string
optional
HMAC key ID. Alternative server-to-server auth.
Btelo-Ts
header
string
optional
Required with HMAC.
Btelo-Sign
header
string
optional
Required with HMAC.
app
query
string
required
Product app slug, e.g. btelo-english.
Response
content_type
application/json
example_body
announcements
field_values
audience
audiences
date_semantics
expires_at
Inclusive admin date in YYYY-MM-DD. Example: expires_at=2026-02-15 may be shown on 2026-02-15; it is omitted starting 2026-02-16 UTC.
enabled
schema
announcement
apps
string[]. Lowercase product app slugs selected in btelo.com admin. The requested app is guaranteed to be present in this array.
audience
string. Legacy single audience field mirroring audiences[0]. Current values: "all" or "paid". Prefer audiences for new integrations.
audiences
string[]. Audience enum values. Current values: "all" = show to every authenticated user; "paid" = show only when the product app locally knows the user has paid access. Current responses contain exactly one value, but callers should treat this as an array.
bodies
object<string,string>. Locale-keyed body map. "en" is required and is the fallback. Values are plain announcement body text authored by admin.
enabled
boolean. Always true in this public endpoint because disabled announcements are filtered out by btelo.com before response.
expires_at
string, optional. YYYY-MM-DD maximum display date authored by admin. The date is inclusive; after that date passes in UTC, btelo.com omits the announcement.
id
string. Stable announcement id. Product apps must persist this id locally per user after display/read.
titles
object<string,string>. Locale-keyed title map. "en" is required and is the fallback. Keys are lowercase locale tags stored by admin, e.g. "en", "zh", "zh-hans", "ja".
announcements
array
Example
GET https://btelo.com/api/v1/announcements?app=btelo-english <Btelo HMAC headers>
Feedback
GUIDEapp-integration-prompt
Prompt for product app agents implementing Btelo feedback. Use this as the canonical integration behavior instead of inventing app-specific feedback protocols.
POST/api/v1/feedback
Create a product-scoped feedback thread. Product apps may use their own user ids; the user_id does not need to exist in btelo.com. If Authorization: Bearer is present and user_id is omitted, btelo uses the JWT subject. Clients should provide system_info whenever possible so admins can diagnose issues without asking the user for hidden technical details.
Name
In
Type
Required
Description
Btelo-Product
header
string
optional
Product name or slug. Used when product_name is omitted from the body.
product_name
body
string
optional
Product name or slug. Required when Btelo-Product is not provided.
user_id
body/header/query
string
optional
Product-side user id. Required unless a Bearer JWT is provided.
user_name
body
string
optional
Optional display name for admin context.
content
body
string
required
Initial feedback text.
system_info
body
object
optional
Admin-only diagnostic context collected automatically by the client. It is accepted on create, stored on the ticket, and not returned by user-facing feedback APIs. Provide as much as is reasonably available: current user name/email/id, subscription tier/status/source/current_period_end, account created_at, app version/build/platform, device model/OS, browser user agent/language/timezone/screen size, network mode, active route, locale, feature flags, recent error codes, and any safe product state useful for support. Do not include secrets, auth tokens, payment card data, passwords, or sensitive document/content bodies.
metadata
body
object|string
optional
Alias for system_info, accepted for clients that already use a metadata field.
POST https://btelo.com/api/v1/feedback Btelo-Product: btelo-english body: {"user_id":"app-user-123","user_name":"Alice","content":"The transcript screen is blank.","system_info":{"user":{"email":"[email protected]","created_at":"2026-05-01T12:00:00Z"},"subscription":{"tier":"pro","status":"active","source":"apple"},"app":{"version":"1.4.2","build":"88","route":"#/video"},"device":{"platform":"ios","model":"iPhone","os":"17.5"},"browser":{"user_agent":"...","language":"en-US","timezone":"America/Chicago","screen":"390x844"}}}
GET/api/v1/feedback
List feedback threads for one product/user pair, including official replies and user follow-ups. If Authorization: Bearer is present and user_id is omitted, btelo uses the JWT subject.
Name
In
Type
Required
Description
product_name
query/header
string
optional
Product name or slug. Required unless Btelo-Product is provided.
user_id
query/header
string
optional
Product-side user id. Required unless a Bearer JWT is provided.
Response
feedback
Array of feedback threads with messages[] in chronological order.
Example
GET https://btelo.com/api/v1/feedback?product_name=vibe-remote&user_id=app-user-123
POST/api/v1/feedback/{id}/messages
Append a user follow-up to an existing feedback thread. The supplied product/user identity must match the original thread.
Name
In
Type
Required
Description
id
path
string
required
Feedback thread id.
product_name
body/header/query
string
optional
Optional product name check.
user_id
body/header/query
string
optional
Product-side user id. Required unless a Bearer JWT is provided.
user_name
body
string
optional
Optional display name.
content
body
string
required
Follow-up text.
Response
feedback
Updated feedback thread with messages[] in chronological order.
Example
POST https://btelo.com/api/v1/feedback/{id}/messages body: {"product_name":"vibe-remote","user_id":"app-user-123","content":"More details..."}