# BetopiaAI API

> OpenAI-compatible inference and platform APIs for models available to your workspace.

## Documentation

- Interactive documentation: /docs
- Machine-readable index: /llms.txt
- API base URL: https://api.betopia.ai/v1

## Authentication

Inference endpoints use an API key:

~~~http
Authorization: Bearer sk_your_key
~~~

Account, API-key management, analytics, billing, and user endpoints use the JWT returned by login:

~~~http
Authorization: Bearer eyJ...
~~~

Keep credentials on your server. Never expose an API key in browser code or source control.

## Coding Agent authentication modes

Choose one mode explicitly. A Coding Agent subscription credential (sk_ca_…) is limited to the subscription gateway at /v1/coding-agent, plus self-revocation. A manually entered general API key (sk_…) uses the normal /v1 API and PAYG wallet balance with broad model access. Subscription credentials are rejected on general account, billing, model, and inference routes. Reaching a subscription limit never switches to wallet billing automatically; the user must choose manual-key mode. Free SSO/SBU users keep their existing shared tier behavior.

~~~bash
curl https://api.betopia.ai/v1/coding-agent/models \
  -H "Authorization: Bearer sk_ca_your_subscription_key"
~~~

Subscription routes include GET /v1/coding-agent/models and the image price endpoints; POST /v1/coding-agent/completions, /chat/completions, /embeddings, /images/generations, /images/edits, and /responses. They use the same request schemas as their matching /v1 routes. User-facing plan and subscription management routes require a JWT session: GET /v1/coding-agent/plans, GET /v1/coding-agent/subscription, POST /v1/coding-agent/subscription/checkout with { plan_id }, POST /v1/coding-agent/subscription/cancel, and POST /v1/coding-agent/subscription/portal to update payment details or pay invoices. Usage responses expose daily/monthly percentages only. Daily usage resets in the server-configured timezone; monthly usage resets on the Stripe billing anniversary.

## Quickstart

~~~bash
curl https://api.betopia.ai/v1/chat/completions \
  -H "Authorization: Bearer sk_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "auto",
    "messages": [{"role": "user", "content": "Hello"}]
  }'
~~~

## Chat completions

### POST /v1/chat/completions

OpenAI-compatible chat generation. Use model: auto for platform routing or pass an available model ID.

Request fields:

| Field | Type | Description |
| --- | --- | --- |
| model | string | Model ID or auto. |
| messages | array | Ordered role/content messages. |
| temperature | number | Optional sampling control. |
| max_tokens | integer | Optional output token limit. |
| stream | boolean | Optional Server-Sent Events response. |

## Responses

### POST /v1/responses

Use Responses for structured output, tools, reasoning configuration, and continuation state.

~~~bash
curl https://api.betopia.ai/v1/responses \
  -H "Authorization: Bearer sk_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "auto",
    "input": "Draft a product update.",
    "max_output_tokens": 150
  }'
~~~

Supported request fields include model, input, instructions, previous_response_id, max_output_tokens, tools, tool_choice, parallel_tool_calls, reasoning, and stream.

## Streaming

Set stream: true on supported inference requests. The server returns Server-Sent Events and ends with data: [DONE].

## Tools and capabilities

Responses accepts flat function tool definitions. Check the model capability profile before relying on tools, parallel tool calls, reasoning, JSON schema, or vision. Unsupported capabilities return 400 before provider execution.

## Embeddings and images

These operations use separate endpoints, not chat completions. Select a concrete model whose capabilities_configured flag is true and whose operation capability is enabled. Do not use model: auto; embedding and image requests never route or fall back to another model.

### POST /v1/embeddings

~~~bash
curl https://api.betopia.ai/v1/embeddings \
  -H "Authorization: Bearer sk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"model":"embedding-model-name","input":["first text","second text"]}'
~~~

### GET /v1/models/{modelID}/image-generation-prices

Returns the active image-operation schema and pricing choices for a model the authenticated caller may use. Read operation_schema.max_images, output_formats, backgrounds, and default_output_format. Image generation currently supports fixed per-image pricing; use an exact size/quality pair from prices. A legacy token-priced configuration may return supported_variants, but generation is unavailable until an admin switches that model to per-image pricing. The schema has a version so clients can refresh cached options when it changes.

~~~bash
curl https://api.betopia.ai/v1/models/<model-id>/image-generation-prices \
  -H "Authorization: Bearer sk_your_key"
~~~

### POST /v1/images/generations

Discover options through GET /v1/models/{modelID}/image-generation-prices before generating. The request's n, output_format, and optional background must follow operation_schema; size/quality must match an exact returned per-image price. Image generation currently supports fixed per-image billing only. A model with a legacy token-pricing configuration cannot generate and may return 503 until an admin switches it to per-image pricing. The response contains bounded base64 image data (with media_type) and usage.cost_usd.
The JSON fields below are Betopia's normalized, shared image-generation request contract: field names and types stay the same across providers, while the platform adapter translates them upstream. Actual option support depends on the selected provider/model. Admin-only provider parameters configure upstream mapping; they do not change the fields API users send or the platform price matrix.

Normalized user request fields (JSON):

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| model | string | Yes | Caller-available image_generation model ID or name; auto is not supported. |
| prompt | string | Yes | 1–32,000 Unicode characters. |
| n | integer | No | Number of images; defaults to 1; must be 1–4 and no greater than operation_schema.max_images. |
| size | string | Yes | Exact configured size in the model's per-image price matrix; auto is not accepted. |
| quality | string | Yes | Exact configured quality paired with size in the price matrix; auto is not accepted. |
| resolution | string | No | 512, 768, 1K, 1.5K, 2K, or 4K; support varies by provider/model. |
| aspect_ratio | string | No | auto or supported ratios including 1:1, 16:9, 9:16, 4:3, 3:2, 4:5, 1:2, and 21:9. |
| output_format | string | No | Model-enabled png, jpeg, webp; svg is OpenRouter-only. Defaults to operation_schema.default_output_format. |
| background | string | No | Model-enabled auto, opaque, or transparent. Transparent output requires png or webp. |
| output_compression | integer | No | 0–100; only for jpeg or webp. |
| seed | integer | No | 0–4,294,967,295; deterministic only where supported upstream. |
| input_references | array | No | Up to four type=image_url objects with HTTPS URL without credentials or base64 PNG/JPEG/WebP data URL; embedded images max 8 MiB each. |
| stream | boolean | No | true returns SSE partial-image and completed events if provider/model supports it. |

Optional header: Idempotency-Key (1–128 visible ASCII characters). Reusing the key with the same non-streamed request replays a successful result for 24 hours; it cannot be combined with stream=true. Stream events use image_generation.partial_image, then image_generation.completed after billing settlement, then [DONE]; a mid-stream failure uses error. When resolution/aspect_ratio is set, size remains the platform price selector and is omitted upstream. The JSON body is limited to 10 MiB; unlisted fields are rejected.

~~~bash
curl https://api.betopia.ai/v1/images/generations \
  -H "Authorization: Bearer sk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"model":"image-model-name","prompt":"A paper-cut mountain landscape","n":1,"size":"<supported-size>","quality":"<supported-quality>","resolution":"2K","aspect_ratio":"16:9","output_format":"webp","output_compression":80,"seed":42}'
~~~

### POST /v1/images/edits

Send multipart/form-data. The endpoint accepts only these fields:

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| model | text | Yes | Caller-available image_edit model ID or name; auto is not supported. |
| prompt | text | Yes | 1–32,000 Unicode characters. |
| size | text | Yes | Exact size configured for the model; auto is not accepted. |
| quality | text | Yes | Exact quality configured for the model; auto is not accepted. |
| image[] | file, repeated | Yes | Upload 1–4 PNG or JPEG images. Each file is at most 8 MiB; request total is at most 10 MiB; each image is limited to 16,384 pixels per side and 100 megapixels. |
| mask | file | No | One optional PNG with alpha; the first source image must also be PNG and have the same dimensions. The same 8 MiB file, 10 MiB request, and image-dimension limits apply. |

Extra or duplicate fields are rejected. Edits do not accept n, output_format, or background, and return one edited image. Uploads are not persisted.


~~~bash
curl https://api.betopia.ai/v1/images/edits \
  -H "Authorization: Bearer sk_your_key" \
  -F "model=image-edit-model" -F "prompt=Replace the cloudy sky with sunset" \
  -F "size=<configured-size>" -F "quality=<configured-quality>" \
  -F "image[]=@source.png"
# Optional: include an alpha PNG mask like this:
# -F "mask=@mask.png"
~~~

Do not persist prompts, uploaded files, or large base64 outputs in browser storage or analytics. JavaScript and Go examples are available in /docs#embeddings-images and the full API Guide; see those references for exact limits, pricing, and response shapes.

## Models

### GET /v1/models

Returns models available to the authenticated caller.

### GET /v1/public/models

Returns public model metadata without authentication.

Model records can include id, name, provider, model_owner, input_cost_per_million, output_cost_per_million, max_tokens, created_at, capabilities, capabilities_configured, and authenticated available status.

Example response:

~~~json
{
  "models": [{
    "id": "auto",
    "name": "auto",
    "provider": "betopia",
    "capabilities_configured": false,
    "available": true
  }],
  "count": 1
}
~~~

## API keys

API keys are created with a JWT. The full secret is returned only when the key is created; list responses expose the prefix.

| Method | Path | Description |
| --- | --- | --- |
| GET | /v1/keys | List key metadata and prefixes. |
| POST | /v1/keys | Create a key. |
| DELETE | /v1/keys/{keyID} | Revoke a key permanently. |
| POST | /v1/keys/{keyID}/reset-tokens | Reset the token counter. |

Create request fields: name, optional expires_in_days, optional token_limit, and optional allowed_models.

## Usage and limits

| Method | Path | Description |
| --- | --- | --- |
| GET | /v1/user/limits | Cost limit, period, used, remaining, and reset. |
| GET | /v1/user/analytics?days=30 | Daily totals and model/provider composition. |
| GET | /v1/user/analytics/daily?date=YYYY-MM-DD | Daily detail. |
| GET | /v1/user/analytics/monthly?months=12 | Monthly totals. |
| GET | /v1/user/audit-log?limit=50 | Recent account activity. |

## Coding Agent subscription API path

| Method | Path |
| --- | --- |
| GET | /v1/coding-agent/models |
| GET | /v1/coding-agent/models/{modelID}/image-generation-prices |
| GET | /v1/coding-agent/models/{modelID}/image-edit-prices |
| GET | /v1/coding-agent/plans (JWT) |
| GET | /v1/coding-agent/subscription (JWT) |
| POST | /v1/coding-agent/subscription/checkout (JWT) |
| POST | /v1/coding-agent/subscription/cancel (JWT) |
| POST | /v1/coding-agent/subscription/portal (JWT) |
| POST | /v1/coding-agent/completions |
| POST | /v1/coding-agent/chat/completions |
| POST | /v1/coding-agent/embeddings |
| POST | /v1/coding-agent/images/generations |
| POST | /v1/coding-agent/images/edits |
| POST | /v1/coding-agent/responses |

## Errors

Errors return JSON. When available, keep request_id with your logs.

~~~json
{
  "error": "invalid or expired api key",
  "request_id": "req_01hzy..."
}
~~~

Common status codes: 400 invalid request or unsupported capability, 401 invalid credentials, 403 permission or verification required, 404 resource not found, 429 quota limit, and 500 server error.

## Endpoint map

| Method | Path |
| --- | --- |
| POST | /v1/auth/register |
| POST | /v1/auth/login |
| POST | /v1/auth/verify-email-otp |
| GET | /v1/models |
| GET | /v1/public/models |
| POST | /v1/chat/completions |
| POST | /v1/completions |
| POST | /v1/responses |
| POST | /v1/embeddings |
| POST | /v1/images/generations |
| POST | /v1/images/edits |
| GET | /v1/user/limits |
| GET | /v1/user/analytics |
| GET | /v1/keys |
| POST | /v1/keys |
