API reference
sympy.ai serves its verified math agent over HTTP at https://api.sympy.ai.
There are two endpoints, both authenticated with the same API key:
| Endpoint | Shape | Use it when |
|---|---|---|
POST /v1/solve | native REST | you want the verification metadata — verified, the notes, the node trail |
POST /v1/messages | Anthropic Messages API | you already have Anthropic SDK code and want to point it here |
Authentication
Create an API key on your account page or
dashboard — it is shown once, and starts with mv_. Both
endpoints accept either header:
X-API-Key: mv_xxxxxxxx...
# or
Authorization: Bearer mv_xxxxxxxx...
Usage is billed against your plan's token balance and recorded with
source=api. See Account & settings for key
management.
POST /v1/solve
curl https://api.sympy.ai/v1/solve \
-H "X-API-Key: $SYMPY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"problem": "integrate x^2", "model_tier": "flash"}'| Field | Type | Notes |
|---|---|---|
problem | string | required — the question, in plain language |
model_tier | string | "flash" (default) or "pro" |
conversation_id | string | optional — reuse to continue a thread |
The response carries the agent's verification record, which is the reason to prefer this endpoint over the Anthropic-compatible one:
{
"answer": "The integral equals x^3/3 + C.",
"verified": true,
"verification_notes": "…",
"usage": { "prompt_tokens": 812, "completion_tokens": 143, "total_tokens": 955 },
"conversation_id": "…",
"verification_strategy": "sympy",
"nodes_visited": [{ "node": "plan", "duration_ms": 412 }]
}verification_strategy is the lane the verifier chose (sympy, sage, or
both), and nodes_visited is the ordered per-node trail with timings and
token deltas.
POST /v1/messages
Request and response match Anthropic's POST /v1/messages, so an Anthropic SDK
pointed at https://api.sympy.ai works unchanged.
curl https://api.sympy.ai/v1/messages \
-H "x-api-key: $SYMPY_API_KEY" \
-H "content-type: application/json" \
-d '{
"model": "sympy-solve",
"max_tokens": 1024,
"messages": [
{ "role": "user", "content": "Integrate x^2 from 0 to 1" }
]
}'Anthropic SDK (Python)
from anthropic import Anthropic
client = Anthropic(
api_key="mv_your_key",
base_url="https://api.sympy.ai",
)
message = client.messages.create(
model="sympy-solve",
max_tokens=1024,
messages=[{"role": "user", "content": "Integrate x^2 from 0 to 1"}],
)
print(message.content[0].text)Anthropic SDK (TypeScript)
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic({
apiKey: "mv_your_key",
baseURL: "https://api.sympy.ai",
});
const message = await client.messages.create({
model: "sympy-solve",
max_tokens: 1024,
messages: [{ role: "user", content: "Integrate x^2 from 0 to 1" }],
});
console.log(message.content[0].text);Response
A standard Anthropic message object. The answer is a single text block;
usage reports input/output tokens. The verified flag and verification notes
are not part of this shape — use /v1/solve if you need them.
{
"id": "msg_…",
"type": "message",
"role": "assistant",
"model": "sympy-solve",
"content": [{ "type": "text", "text": "The integral equals 1/3." }],
"stop_reason": "end_turn",
"stop_sequence": null,
"usage": { "input_tokens": 812, "output_tokens": 143 }
}Streaming
Set "stream": true to receive the Anthropic SSE sequence — message_start →
content_block_start → content_block_delta → content_block_stop →
message_delta → message_stop. The Anthropic SDK's streaming helpers consume
it unchanged. /v1/solve does not stream.
Models
Any model string is accepted; it only selects a tier. A name containing pro,
opus, reasoner, think, reasoning, -r1, or /r1 routes to the
higher-effort pipeline — everything else to the fast one.
Errors
The two endpoints use different error shapes, because each matches the convention of the API it imitates.
/v1/messages returns the Anthropic envelope
{ "type": "error", "error": { "type", "message" } }:
| HTTP | error.type | Meaning |
|---|---|---|
| 401 | authentication_error | Missing, invalid, or revoked API key |
| 400 | invalid_request_error | Malformed request |
| 429 | rate_limit_error | Rate limited (with retry-after) |
| 403 | billing_error | Token balance exhausted |
| 500 | api_error | Agent or upstream failure |
/v1/solve returns { "detail": "…" }:
| HTTP | Meaning |
|---|---|
| 401 | Missing, invalid, or revoked API key |
| 429 | Rate limited (with Retry-After) |
| 402 | Insufficient token balance |
| 500 | Agent or upstream failure |
Note the mismatch on an exhausted balance: /v1/solve answers 402, while
/v1/messages answers 403 to stay within Anthropic's error vocabulary.
Handle both if you call both.
Per-key rate limits follow your plan, and are shared across /v1/solve,
/v1/messages, and the MCP server — one limit governs all three.
Two HTTP APIs — a native REST endpoint and an Anthropic-compatible Messages API.