Mova0.6 pre-release⌕
☰
home / parse / API

The parse API

The analysis behind the parse page over HTTP, as Markdown, JSON, JSON Lines, YAML or CoNLL-U: sentences with their language, dialect and style, Universal Dependencies tokens (lemma, UPOS, XPOS, features, head, relation), the CoNLL-U document, and for English the frames (who did what to whom) and the pragmatics (speech act, form, indirectness, hedging, polarity, voice, implicatures, presuppositions, irony candidates). The analysis is deterministic: the same text, language and model versions give the same bytes. English is the language of the API; French is experimental (trees only).

This service runs the experimental Mova 0.6 pre-release; the stable release is 0.5 on GitHub. Using the API means agreeing to the Terms of use: the texts and the IP address are collected automatically.

The API lives at https://api.mova.elamur.ai (/v1/…). The same handlers also answer under /api/v1/… on mova.elamur.ai.

Formats

Choose with format= (a query parameter, or "format" in a JSON body), a suffix on a stored result's address, or the Accept header — in that order. Without any of them the answer is JSON.

formatsuffixAcceptcontent
md.mdtext/markdowntitle, per sentence language/dialect/style, token table, tree outline, frames, pragmatics, model SHA-256s, CoNLL-U in a fence
json.jsonapplication/jsonthe full answer with quota
jsonl.jsonlapplication/jsonl, application/x-ndjsonone JSON object per sentence
yaml.yamlapplication/yamlthe JSON answer as YAML, keys in order
conllu.conllutext/plainthe CoNLL-U document

GET https://api.mova.elamur.ai/v1/parse

Parameters: text (up to 2000 characters in an address), lang: auto (default), en or fr, format.

curl 'https://api.mova.elamur.ai/v1/parse?text=Can+you+pass+the+salt%3F&format=md'
curl -H 'Accept: text/markdown' 'https://api.mova.elamur.ai/v1/parse?text=Can+you+pass+the+salt%3F'

POST https://api.mova.elamur.ai/v1/parse

A JSON body {"text": "…", "lang": "auto", "format": "json"}, or plain text with ?lang= and ?format= in the address. With an API key of an account (made on the account page), the account's limits apply.

curl -X POST https://api.mova.elamur.ai/v1/parse \
  -H 'Content-Type: application/json' \
  -d '{"text": "Some of the guests left early. They were tired.", "lang": "en"}'

curl -X POST 'https://api.mova.elamur.ai/v1/parse?lang=en&format=yaml' \
  -H 'Authorization: Bearer elmr_…' \
  -H 'Content-Type: text/plain' --data-binary @story.txt

GET https://api.mova.elamur.ai/v1/r/<id>.md

A stored result by its short id: the result page of a text too long for an address has the short link https://mova.elamur.ai/free/en/parse/s/<id>, and the same analysis is at https://api.mova.elamur.ai/v1/r/<id>.md (also .json, .jsonl, .yaml, .conllu). The same quotas, terms and request log apply as for a parse.

curl https://api.mova.elamur.ai/v1/r/0123456789ab.md

The JSON answer

{
  "quota": {"plan": "anonymous", "per_request": 5000, "per_day": 250000,
            "used_today": 5, "remaining_today": 249995, "resets_in_s": 40000, "words": 5},
  "text": "Can you pass the salt?",          the normalised text that was parsed
  "lang_requested": "auto",
  "sentences": [{
    "id": 1, "text": "…", "lang": "en",
    "dialect": {"label": null, "confidence": 0.0, "markers": []},
    "style": null,
    "spans": [{"start": 0, "end": 22, "lang": "en"}],
    "parse": {"en": "en.bin"},
    "tokens": [{"id": 1, "form": "Can", "lemma": "can", "upos": "AUX", "xpos": "MD",
                "feats": "VerbForm=Fin", "head": 3, "deprel": "aux", "misc": "_", "lang": "en"}, …],
    "parsed": true,
    "frames": [{"kind": "event", "verb": "pass", "agent": "you", "patient": "the salt", …}],
    "pragmatics": {"labels": {"act": {"value": "ask", "margin": 18.25}, "form": …, "indirect": …},
                   "cues": [], "implicatures": [], "presuppositions": [], "maxims": […], "irony": null}
  }],
  "conllu": "# sent_id = s-1\n# text = Can you pass the salt?\n…",
  "versions": {"service": "mova-serve/1", "release": "0.6 pre-release", "stable": "0.5", "models": {"en": {"file": "en.bin", "sha256": "…"}}, …}
}

Headers: X-Cache (hit or miss), X-Words (the words of this text), X-Quota-Plan, X-Quota-Limit (words a day), X-Quota-Remaining and X-Quota-Reset (seconds to 00:00 UTC). Everything but quota is the same for the same text; Markdown, JSONL and CoNLL-U carry the quota in these headers only (YAML has it like JSON).

MCP: the parse service for AI assistants

The MCP page has the details and client configs. An MCP server (Model Context Protocol, revisions 2025-03-26 to 2025-11-25) with two read-only tools: parse_text (the analysis; fields narrows it to tokens, conllu, frames, pragmatics) and explain_sentence (a sentence's grammar, frames and speech act in plain English). Both return Markdown text by default; the argument format (md, json, jsonl, yaml, conllu) chooses another, and json also fills structuredContent. It needs an API key of an account; the account's quota applies.

Streamable HTTP, for remote clients:

https://api.mova.elamur.ai/v1/mcp        Authorization: Bearer elmr_…

curl -X POST https://api.mova.elamur.ai/v1/mcp \
  -H 'Authorization: Bearer elmr_…' -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"explain_sentence","arguments":{"text":"Can you pass the salt?"}}}'

stdio, for local clients: the mova-serve binary from the repository forwards each message to the HTTP endpoint with your key:

{"mcpServers": {"mova": {"command": "mova-serve",
  "args": ["mcp-stdio", "--endpoint", "https://api.mova.elamur.ai/v1/mcp"],
  "env": {"ELAMUR_API_KEY": "elmr_…"}}}}

GET https://api.mova.elamur.ai/v1/health

Whether the service is up, its release and model versions, the cache's entries and hits, the queue and aggregate request counts.

curl https://api.mova.elamur.ai/v1/health

Limits

Words are counted by Mova's tokenizer. Anonymous use: 5,000 words a request and 250,000 words a day per IP address; a free account (API key or signed in): 20,000 words a request and 1,000,000 a day. A text in an address: up to 2000 characters; a body: up to 2 MB. Against bursts each client has a bucket of 40 requests refilled at 1 a second. 4 parses run at once and 16 wait; a parse gives up after 60 seconds.

Status codes: 400 a bad parameter or format, 401 a missing or unknown key (MCP), 404 an unknown or expired short id, 413 a text longer than the plan allows, 429 the day's words used up or too many requests at once (see Retry-After), 503 busy (try again in a few seconds), 504 the parse took too long.

Terms of use · Privacy policy · Parse · API · MCP · Account