MeasyAI /Docs

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.

Your prompts are never used for training. Enforced in the upstream request itself, not only in policy: every call carries a no-data-collection instruction and is routed only to providers that honour it.

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.

ScopeGrants
chat:readList models, read conversations and messages
chat:writeCreate completions, conversations and batches
analytics:readRead usage, latency and cost data
A key is shown once. Only a SHA-256 digest is stored, so a lost key cannot be recovered — revoke it and mint another. Keys cannot create or revoke other keys; that requires a signed-in session.

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.

ModelTierBest 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?"}
    ]
  }'
FieldTypeNotes
modelstringDefaults to the server's configured model.
messagesarrayRequired. role is system, user, assistant or tool.
streambooleanServer-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]
Web app streaming uses WebSocket, not SSE. The browser client connects to 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:

HeaderMeaning
X-MeasyAI-Signaturev1=<hex HMAC-SHA256>
X-MeasyAI-TimestampUnix seconds, inside the signed string
X-MeasyAI-EventEvent name
X-MeasyAI-DeliveryThis 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

EventFires when
message.completedA generation finished successfully
message.failedA generation errored
conversation.createdA new conversation was opened
batch.completedEvery item in a batch has landed
api_key.createdA key was minted
api_key.revokedA key was revoked
Endpoints must be publicly routable. Loopback, private, link-local and carrier-grade-NAT addresses are rejected at registration and re-checked at dial time. Redirects are not followed.

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.

HeaderMeaning
X-RateLimit-LimitRequests allowed per minute
X-RateLimit-RemainingRequests left in the current window
Retry-AfterSeconds 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…"
}
StatusTypeUsually means
400invalid_request_errorMalformed body or a rejected field
401authentication_errorMissing, invalid or revoked key
403permission_errorValid key, missing scope or wrong project
404not_found_errorNo such resource, or not visible to you
429rate_limit_errorRate limit or usage allowance exhausted
503api_errorAn 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.

Loading…

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