Overview
Base URLs and versions
| Protocol | Base URL | Notes |
|---|---|---|
| OpenAI-compatible | https://modelportal.ai/v1 |
Same /v1 paths as the OpenAI API |
| Anthropic-compatible | https://modelportal.ai |
Endpoints live under /v1/messages and need the anthropic-version header |
| Gemini-compatible | https://modelportal.ai/v1beta |
Same /v1beta paths as the Gemini API |
| Platform API | https://modelportal.ai/api/v1 |
The public model list and similar |
API versions follow each protocol's official version. The platform only adds fields and never changes existing ones; breaking changes are announced in advance.
Authentication
| Protocol | Header |
|---|---|
| OpenAI-compatible | Authorization: Bearer YOUR_API_KEY |
| Anthropic-compatible | x-api-key: YOUR_API_KEY or Bearer |
| Gemini-compatible | x-goog-api-key: YOUR_API_KEY, the key query parameter, or Bearer |
See Authentication.
Platform request headers
| Header | Protocols | Meaning |
|---|---|---|
X-ModelPortal-Provider-Preferences |
All three | Routing preferences as JSON with the provider fields, at most 4096 bytes; see Provider selection |
X-ModelPortal-Session |
All three | Session identifier for session affinity; see Default routing |
Idempotency-Key |
All three | Idempotency key: a repeated submission with the same key never calls the upstream again; non-streaming requests get the first result back, streaming requests get 409 |
Platform response headers
Successful model call responses carry these headers:
| Header | Meaning |
|---|---|
X-ModelPortal-Request-Id |
Platform request ID, matching the console's call details and your bill |
X-ModelPortal-Provider |
Provider identifier that served the request |
X-ModelPortal-Endpoint |
Endpoint identifier that served the request |
X-ModelPortal-Model |
Canonical model ID that was used |
X-ModelPortal-Attempts |
How many endpoints the request tried |
A streaming response sends its headers when the first content event arrives or when keepalives start, whichever comes first. If only keepalives have gone out, the provider, endpoint and attempt count are not settled yet; those three headers are left out and the fields in the stream are authoritative.
Extra response fields
In all three protocols the response body gains three fields; when streaming they are in the last event that carries usage:
| Field | Meaning |
|---|---|
provider |
Provider identifier that served the request |
attempts |
One item per attempt: provider, endpoint (endpoint identifier), status (HTTP status), cost (USD); cost is 0 for failed attempts |
cost in the usage object |
The amount charged for this request (USD), matching your bill |
The usage object is usage in OpenAI (response.usage in streaming Responses), usage in Anthropic and usageMetadata in Gemini. Every OpenAI Chat streaming chunk also carries provider. The endpoint that served the request is the one in the last attempts item.
Errors
Each protocol returns its own error format: in the OpenAI format and the platform API, code is the platform error code; the Anthropic format carries only an error type, and the Gemini format's code is the HTTP status. The full code table and the 422 exclusion reason codes are in Common errors.
Rate limits
Account requests per minute, per-key requests per minute and concurrent requests are limited; going over returns 429 rate_limited with Retry-After. Tiers are in Common errors.
Request detail and key quota
These two endpoints authenticate with your API key and accept only Authorization: Bearer YOUR_API_KEY. They are free but count toward the key's requests per minute. Amount fields end in _minor and are in units of 0.000001 USD.
GET /api/v1/requests/{request ID}
The request ID is the value of the X-ModelPortal-Request-Id response header. A key can only look up requests it made itself: requests made by another key on the same account, or by another account, return 404 call.not_found, the same as a request ID that does not exist. How far back you can look matches the call record retention period.
| Field | Description |
|---|---|
request_id, started_at, model, status |
Request ID, start time, model ID, status |
provider, offering_id |
Provider and endpoint identifiers that finally served the request |
config_version, price_version |
Config version and price version of that endpoint when it served the request |
error_category |
Error type when the request failed |
duration_ms, first_byte_ms |
Duration and time to first token, in milliseconds |
tokens |
Usage by dimension |
cost_minor |
What the request cost, matching your bill |
meter_flags |
Metering flags, for example estimated when billed on an estimate |
routing_constraints |
Routing constraints in effect: data policy, region, quantization and other limits after merging account preferences, key preferences and request parameters; null when there were none |
attempts |
One item per attempt: provider, offering_id, config_version, started_at, duration_ms, upstream_status (HTTP status), error_category, cost_minor |
GET /api/v1/key
Returns the current key's settings and quota:
| Field | Description |
|---|---|
id, name, last4, status, expires_at |
Key ID, name, last 4 characters, status, expiry |
allowed_model_ids |
Model allowlist; empty means every model |
daily_limit_minor, monthly_limit_minor |
Daily and monthly spending limits, null when not set |
spent_today_minor, spent_month_minor |
Spent today and this month, matching the key list in the console |
held_minor |
Amount held for requests still in flight |
rate_limits |
Rate limit tier: account requests per minute, per-key requests per minute, concurrent requests |
routing_preferences |
Key-level routing preferences |
available_minor |
What this key can spend right now |
available_minor counts only your cash balance and gift credit that is not limited to specific models, minus what is already held. If the key has a spending limit, it never exceeds the limit minus what was spent this period and what is held in flight.
App authorization and the management API are not open yet; they will be added here when they launch.