MeasyAI API
An OpenAI-compatible chat API. Point an SDK you already use at
https://api.measyai.com/v1, change the key, and it works —
streaming, tool calling and batching included.
Base URL
https://api.measyai.com/v1
Quickstart
Create a key in the dashboard under API keys, then:
Authentication
Send your key as a bearer token. Keys begin with msy_.
Authorization: Bearer msy_...
Each key belongs to exactly one project and carries an explicit scope set. A key can only reach its own project — that boundary is the isolation model, not a convenience.
| Scope | Grants |
|---|---|
chat:read | List models, read conversations and messages |
chat:write | Create completions, conversations and batches |
analytics:read | Read usage, latency and cost data |
Models
MeasyAI models are named, not passed through. The name you send stays stable even when the model serving it is upgraded, so stored conversations and running integrations never break.
| Model | Tier | Best for |
|---|---|---|
| Loading… | ||
Fetch the live list at any time:
curl https://api.measyai.com/v1/models \
-H "Authorization: Bearer $MEASYAI_API_KEY"
Chat completions
POST /v1/chat/completions
The request and response shapes mirror OpenAI's. Fields not listed here —
temperature, top_p, response_format,
tools — are forwarded to the provider unchanged.
curl https://api.measyai.com/v1/chat/completions \
-H "Authorization: Bearer $MEASYAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "measyai/meridian",
"messages": [
{"role": "system", "content": "You are terse."},
{"role": "user", "content": "Why is Postgres MVCC useful?"}
]
}'
| Field | Type | Notes |
|---|---|---|
model | string | Defaults to the server's configured model. |
messages | array | Required. role is system, user, assistant or tool. |
stream | boolean | Server-sent events when true. See below. |
Streaming
Set stream: true for a text/event-stream of
chat.completion.chunk objects, terminated by
data: [DONE]. This is the format OpenAI SDKs already parse.
data: {"id":"chatcmpl-…","object":"chat.completion.chunk","choices":[{"delta":{"content":"Post"}}]}
data: {"id":"chatcmpl-…","object":"chat.completion.chunk","choices":[{"delta":{"content":"gres"}}]}
data: [DONE]
wss://api.measyai.com/ws, which
allows a second tab or another device to attach to a generation already in
flight — and to resume it after a dropped connection. The
/v1 SSE transport above exists for SDK compatibility.
Tool calling
Pass tools and tool_choice exactly as you would to
OpenAI. They are forwarded verbatim, and tool call deltas come back in the
stream unchanged.
{
"model": "measyai/meridian",
"messages": [{"role": "user", "content": "What is the weather in Berlin?"}],
"tools": [{
"type": "function",
"function": {
"name": "get_weather",
"parameters": {
"type": "object",
"properties": {"city": {"type": "string"}},
"required": ["city"]
}
}
}]
}
Batches
Queue up to 1000 completions and collect them later. Each item writes its
own usage record, and batch.completed fires when the last one
lands.
curl https://api.measyai.com/v1/batches \
-H "Authorization: Bearer $MEASYAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"requests": [
{"custom_id": "row-1", "body": {"messages": [{"role":"user","content":"Summarise: …"}]}},
{"custom_id": "row-2", "body": {"messages": [{"role":"user","content":"Summarise: …"}]}}
]
}'
Poll GET /v1/batches/{id} for progress and per-item results.
Webhooks
Register endpoints in the dashboard. Every delivery carries these headers:
| Header | Meaning |
|---|---|
X-MeasyAI-Signature | v1=<hex HMAC-SHA256> |
X-MeasyAI-Timestamp | Unix seconds, inside the signed string |
X-MeasyAI-Event | Event name |
X-MeasyAI-Delivery | This delivery's id |
Verifying a delivery
Compute over the raw body. Re-serializing parsed JSON will not reproduce the same bytes and the check will fail.
const expected =
"v1=" + crypto.createHmac("sha256", secret)
.update(`${timestamp}.${rawBody}`)
.digest("hex");
// Constant-time compare, and reject stale timestamps — that is what
// stops a captured delivery from being replayed later.
const valid =
Math.abs(Date.now() / 1000 - Number(timestamp)) < 300 &&
crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
Failed deliveries retry at 30s, 2m, 10m, 30m and 1h. A non-retryable 4xx stops immediately. Every attempt is visible in the dashboard's delivery log, and can be replayed from there.
Events
| Event | Fires when |
|---|---|
message.completed | A generation finished successfully |
message.failed | A generation errored |
conversation.created | A new conversation was opened |
batch.completed | Every item in a batch has landed |
api_key.created | A key was minted |
api_key.revoked | A key was revoked |
Rate and usage limits
Two independent limits apply, for different reasons.
Rate limits
Per-minute burst protection, applied per key or per user. Exceeding one
returns 429 with a Retry-After header.
| Header | Meaning |
|---|---|
X-RateLimit-Limit | Requests allowed per minute |
X-RateLimit-Remaining | Requests left in the current window |
Retry-After | Seconds until capacity returns |
Usage allowance
A rolling per-account message allowance over a longer window — the
"5-hour limit". It is not a burst guard: it caps total consumption. Read
the current state at GET /usage/limit, which reports
remaining and reset_at.
Errors
Every failure uses the same envelope, shaped like OpenAI's so SDK error
handling works unchanged. code is stable and safe to branch on;
quote request_id in a bug report.
{
"error": {
"code": "insufficient_scope",
"message": "This API key is missing the required scope: chat:write",
"type": "permission_error"
},
"request_id": "5f3c…"
}
| Status | Type | Usually means |
|---|---|---|
| 400 | invalid_request_error | Malformed body or a rejected field |
| 401 | authentication_error | Missing, invalid or revoked key |
| 403 | permission_error | Valid key, missing scope or wrong project |
| 404 | not_found_error | No such resource, or not visible to you |
| 429 | rate_limit_error | Rate limit or usage allowance exhausted |
| 503 | api_error | An upstream dependency is unavailable |
Privacy
- No training on your data, enforced in the upstream request.
- IP addresses are stored hashed, never raw.
- Export everything as a ZIP from Settings (GDPR Art. 20).
- Delete your account with a cancellable grace period (Art. 17).
- No third-party fonts or analytics — nothing leaks your visitors' IPs.
All endpoints
Read live from the deployed server's OpenAPI document, so this cannot drift from what actually exists.
SDKs
Because /v1 is OpenAI-compatible, the official OpenAI SDK for
any language works by changing the base URL. A typed MeasyAI client is
generated from the OpenAPI document for TypeScript and Go, adding the
endpoints OpenAI has no equivalent for — batches, analytics and webhook
verification.
npm install @measyai/sdk