REST API reference
Every op, its input schema and a curl example, generated from the ops registry.
Every action in Glossa is an op. Call one with POST https://glossa-meterapp.vercel.app/api/v1/{op} and its input as a JSON body. Read-only ops also answer GET with the input as URL-encoded JSON in ?input=. This page is generated from the same registry that serves the API, so it lists exactly what the API accepts.
- Auth:
Authorization: Bearer gls_…(orX-Api-Key). With an OAuth token, pick a workspace withX-Glossa-Workspace: <slug>. - Errors are RFC 9457
application/problem+jsonwith acodeandrequest_id: see Errors. - Machine-readable: OpenAPI 3.1, the op catalog and llms-full.txt.
curl -X POST https://glossa-meterapp.vercel.app/api/v1/get_stats \ -H "Authorization: Bearer gls_…"All ops
Workspace
Settings, stats and the activity log.
get_workspace
readGet workspace · POST /api/v1/get_workspace or GET …?input=
The workspace this credential belongs to: name, source locale and the product context every AI prompt starts with. Call first to orient yourself.
curl -X POST https://glossa-meterapp.vercel.app/api/v1/get_workspace \ -H "Authorization: Bearer gls_…"npx @meterapp/glossa get_workspace{ "type": "object", "properties": {}}Update workspace · POST /api/v1/update_workspace
Change the workspace name, source locale or product context. The product context (what the app is, who uses it, tone) is prepended to every translation and audit prompt, so a good one improves every translation.
curl -X POST https://glossa-meterapp.vercel.app/api/v1/update_workspace \ -H "Authorization: Bearer gls_…"npx @meterapp/glossa update_workspace{ "type": "object", "properties": { "name": { "type": "string", "minLength": 1, "maxLength": 100 }, "product_context": { "description": "What the product is, its audience, voice and tone.", "type": "string", "maxLength": 8000 }, "source_locale": { "type": "string", "minLength": 2, "maxLength": 35, "description": "BCP 47 locale, e.g. es, pt-BR, zh-Hans." } }}get_stats
readGet stats · POST /api/v1/get_stats or GET …?input=
Counts across the workspace (projects, units, keys, open tasks) and per-locale translation coverage per project.
curl -X POST https://glossa-meterapp.vercel.app/api/v1/get_stats \ -H "Authorization: Bearer gls_…"npx @meterapp/glossa get_stats{ "type": "object", "properties": {}}list_activity
readList activity · POST /api/v1/list_activity or GET …?input=
Who changed what, from which surface (dashboard, api, mcp, cli, ai), newest first.
curl -X POST https://glossa-meterapp.vercel.app/api/v1/list_activity \ -H "Authorization: Bearer gls_…"npx @meterapp/glossa list_activity{ "type": "object", "properties": { "limit": { "default": 50, "description": "Page size, at most 200.", "type": "integer", "minimum": 1, "maximum": 200 }, "offset": { "default": 0, "type": "integer", "minimum": 0, "maximum": 9007199254740991 } }}Projects
Apps or repos, each with its source and target locales.
list_projects
readList projects · POST /api/v1/list_projects or GET …?input=
Every project (app) in the workspace with its target locales. Strings are shared across projects; files belong to one.
curl -X POST https://glossa-meterapp.vercel.app/api/v1/list_projects \ -H "Authorization: Bearer gls_…"npx @meterapp/glossa list_projects{ "type": "object", "properties": {}}create_project
writeCreate project · POST /api/v1/create_project
Add a project (one app, site or service) with the locales it ships in. Push files to it with push_file.
curl -X POST https://glossa-meterapp.vercel.app/api/v1/create_project \ -H "Authorization: Bearer gls_…" \ -H "Content-Type: application/json" \ -d '{"name":"CI"}'npx @meterapp/glossa create_project --json '{"name":"CI"}'{ "type": "object", "properties": { "name": { "type": "string", "minLength": 1, "maxLength": 100 }, "slug": { "description": "URL-safe id; derived from the name when omitted.", "type": "string", "pattern": "^[a-z0-9][a-z0-9-]{0,47}$" }, "description": { "default": "", "description": "What this app is; added to the product context for its strings.", "type": "string", "maxLength": 4000 }, "target_locales": { "default": [], "maxItems": 100, "type": "array", "items": { "type": "string", "minLength": 2, "maxLength": 35, "description": "BCP 47 locale, e.g. es, pt-BR, zh-Hans." } }, "auto_translate": { "default": true, "description": "Translate new strings into every target locale automatically.", "type": "boolean" } }, "required": [ "name" ]}update_project
writeUpdate project · POST /api/v1/update_project
Change a project's name, description, target locales or auto-translate. Adding a locale with auto_translate on queues translation of every existing string into it.
curl -X POST https://glossa-meterapp.vercel.app/api/v1/update_project \ -H "Authorization: Bearer gls_…" \ -H "Content-Type: application/json" \ -d '{"project":"web"}'npx @meterapp/glossa update_project --json '{"project":"web"}'{ "type": "object", "properties": { "project": { "type": "string", "minLength": 1, "description": "Project slug or id." }, "name": { "type": "string", "minLength": 1, "maxLength": 100 }, "description": { "type": "string", "maxLength": 4000 }, "target_locales": { "maxItems": 100, "type": "array", "items": { "type": "string", "minLength": 2, "maxLength": 35, "description": "BCP 47 locale, e.g. es, pt-BR, zh-Hans." } }, "auto_translate": { "type": "boolean" } }, "required": [ "project" ]}Files
Push translation files in, pull any locale back out.
list_files
readList files · POST /api/v1/list_files or GET …?input=
Files of a project. `path` is a pattern: `{locale}` (or `{android_locale}`) stands for each locale's copy, so one row covers en.json, es.json, ….
curl -X POST https://glossa-meterapp.vercel.app/api/v1/list_files \ -H "Authorization: Bearer gls_…" \ -H "Content-Type: application/json" \ -d '{"project":"web"}'npx @meterapp/glossa list_files --json '{"project":"web"}'{ "type": "object", "properties": { "project": { "type": "string", "minLength": 1, "description": "Project slug or id." } }, "required": [ "project" ]}push_file
writePush file · POST /api/v1/push_file
Upload a translation file in any format (JSON, YAML, xcstrings, .strings, stringsdict, strings.xml, PO, XLIFF, ARB, properties, RESX, CSV, or one Glossa learned). A source-locale file creates or updates keys and dedupes their strings into shared units across every project; another locale's file imports its translations. New strings are queued for AI translation. A format nobody can read yet starts a learn_format job instead.
curl -X POST https://glossa-meterapp.vercel.app/api/v1/push_file \ -H "Authorization: Bearer gls_…" \ -H "Content-Type: application/json" \ -d '{"project":"web","path":"locales/en.json","content":"{\"home.title\": \"Welcome back\"}"}'npx @meterapp/glossa push_file --json '{"project":"web","path":"locales/en.json","content":"{\"home.title\": \"Welcome back\"}"}'{ "type": "object", "properties": { "project": { "type": "string", "minLength": 1, "description": "Project slug or id." }, "path": { "type": "string", "minLength": 1, "maxLength": 500, "description": "Path in the repo, e.g. ios/App/en.lproj/Localizable.strings or locales/en.json. Used to infer the locale." }, "content": { "type": "string", "maxLength": 10000000, "description": "The file's text." }, "locale": { "description": "The file's locale when the path doesn't say.", "type": "string", "minLength": 2, "maxLength": 35 }, "format": { "description": "Format id to force (see list_formats); detected when omitted.", "type": "string" } }, "required": [ "project", "path", "content" ]}pull_file
readPull file · POST /api/v1/pull_file or GET …?input=
Render one locale of a file in its own format, ready to write to disk. Returns {path, content}.
curl -X POST https://glossa-meterapp.vercel.app/api/v1/pull_file \ -H "Authorization: Bearer gls_…" \ -H "Content-Type: application/json" \ -d '{"project":"web","path":"locales/en.json","locale":"es"}'npx @meterapp/glossa pull_file --json '{"project":"web","path":"locales/en.json","locale":"es"}'{ "type": "object", "properties": { "project": { "type": "string", "minLength": 1, "description": "Project slug or id." }, "path": { "type": "string", "description": "The file's path pattern from list_files, or a concrete path such as locales/es.json." }, "locale": { "type": "string", "minLength": 2, "maxLength": 35, "description": "BCP 47 locale, e.g. es, pt-BR, zh-Hans." }, "missing": { "default": "source", "description": "What untranslated keys contain.", "type": "string", "enum": [ "source", "empty", "omit" ] }, "approved_only": { "default": false, "description": "Only ship reviewed or approved translations.", "type": "boolean" } }, "required": [ "project", "path", "locale" ]}Formats
Detect, list and teach file formats.
detect_format
readDetect format · POST /api/v1/detect_format or GET …?input=
Which format Glossa would read a file as, with confidence and the runner-up candidates. Doesn't store anything.
curl -X POST https://glossa-meterapp.vercel.app/api/v1/detect_format \ -H "Authorization: Bearer gls_…" \ -H "Content-Type: application/json" \ -d '{"filename":"en.json","content":"{\"home.title\": \"Welcome back\"}"}'npx @meterapp/glossa detect_format --json '{"filename":"en.json","content":"{\"home.title\": \"Welcome back\"}"}'{ "type": "object", "properties": { "filename": { "type": "string" }, "content": { "type": "string", "maxLength": 2000000 } }, "required": [ "filename", "content" ]}list_formats
readList formats · POST /api/v1/list_formats or GET …?input=
Built-in formats and the templates this workspace has learned, with their status.
curl -X POST https://glossa-meterapp.vercel.app/api/v1/list_formats \ -H "Authorization: Bearer gls_…"npx @meterapp/glossa list_formats{ "type": "object", "properties": {}}learn_format
writeLearn format · POST /api/v1/learn_format
Ask the AI to write a template for a file format Glossa can't read yet, from a sample. Runs as a job (see get_job); the learned format is stored and reads every similar file from then on.
curl -X POST https://glossa-meterapp.vercel.app/api/v1/learn_format \ -H "Authorization: Bearer gls_…" \ -H "Content-Type: application/json" \ -d '{"project":"web","path":"locales/en.json","content":"{\"home.title\": \"Welcome back\"}"}'npx @meterapp/glossa learn_format --json '{"project":"web","path":"locales/en.json","content":"{\"home.title\": \"Welcome back\"}"}'{ "type": "object", "properties": { "project": { "type": "string", "minLength": 1, "description": "Project slug or id." }, "path": { "type": "string" }, "content": { "type": "string", "maxLength": 2000000 }, "hint": { "description": "Anything that helps: which fields are keys, which are comments.", "type": "string", "maxLength": 2000 } }, "required": [ "project", "path", "content" ]}approve_format
writeSave or retire a format · POST /api/v1/approve_format
Set a learned format's status (active reads files, retired stops). Optionally replace its template; the new template is validated against the stored sample first.
curl -X POST https://glossa-meterapp.vercel.app/api/v1/approve_format \ -H "Authorization: Bearer gls_…" \ -H "Content-Type: application/json" \ -d '{"format":"format"}'npx @meterapp/glossa approve_format --json '{"format":"format"}'{ "type": "object", "properties": { "format": { "type": "string", "description": "Format slug or id." }, "status": { "default": "active", "type": "string", "enum": [ "active", "retired", "draft" ] }, "template": {} }, "required": [ "format" ]}Strings
Deduplicated units, translations, merges and splits.
search_units
readSearch strings · POST /api/v1/search_units or GET …?input=
Full-text and fuzzy search across every source string, key name and translation in the workspace. Use it to find how a term is translated everywhere, spot inconsistencies, or find the unit behind a key.
curl -X POST https://glossa-meterapp.vercel.app/api/v1/search_units \ -H "Authorization: Bearer gls_…" \ -H "Content-Type: application/json" \ -d '{"query":"checkout"}'npx @meterapp/glossa search_units --json '{"query":"checkout"}'{ "type": "object", "properties": { "query": { "type": "string", "minLength": 1, "maxLength": 500 }, "locale": { "description": "Also match and return translations in this locale.", "type": "string", "minLength": 2, "maxLength": 35 }, "limit": { "default": 50, "description": "Page size, at most 200.", "type": "integer", "minimum": 1, "maximum": 200 } }, "required": [ "query" ]}list_units
readList strings · POST /api/v1/list_units or GET …?input=
Page through units (deduplicated source strings) with their translation in one locale. Filter by project and by translation status, e.g. status=missing to find what still needs translating or status=machine to review AI output.
curl -X POST https://glossa-meterapp.vercel.app/api/v1/list_units \ -H "Authorization: Bearer gls_…" \ -H "Content-Type: application/json" \ -d '{"locale":"es"}'npx @meterapp/glossa list_units --json '{"locale":"es"}'{ "type": "object", "properties": { "project": { "type": "string", "minLength": 1, "description": "Project slug or id." }, "locale": { "type": "string", "minLength": 2, "maxLength": 35, "description": "BCP 47 locale, e.g. es, pt-BR, zh-Hans." }, "status": { "default": "any", "type": "string", "enum": [ "any", "missing", "machine", "imported", "reviewed", "approved", "needs_review" ] }, "limit": { "default": 50, "description": "Page size, at most 200.", "type": "integer", "minimum": 1, "maximum": 200 }, "offset": { "default": 0, "type": "integer", "minimum": 0, "maximum": 9007199254740991 } }, "required": [ "locale" ]}get_unit
readGet string · POST /api/v1/get_unit or GET …?input=
One unit with every key that uses it (across projects and files), all its translations and their history.
curl -X POST https://glossa-meterapp.vercel.app/api/v1/get_unit \ -H "Authorization: Bearer gls_…" \ -H "Content-Type: application/json" \ -d '{"unit":"6f1c2e0a-4b7d-4c2e-9a51-0d3b8e7f9a10"}'npx @meterapp/glossa get_unit --json '{"unit":"6f1c2e0a-4b7d-4c2e-9a51-0d3b8e7f9a10"}'{ "type": "object", "properties": { "unit": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "Unit id (a deduplicated source string shared by every key that points at it)." } }, "required": [ "unit" ]}update_unit
writeUpdate string context · POST /api/v1/update_unit
Set a unit's description (context for translators and the AI), max length or tags. A good description fixes ambiguous strings in every locale at once; pass retranslate=true to redo its machine translations with the new context.
curl -X POST https://glossa-meterapp.vercel.app/api/v1/update_unit \ -H "Authorization: Bearer gls_…" \ -H "Content-Type: application/json" \ -d '{"unit":"6f1c2e0a-4b7d-4c2e-9a51-0d3b8e7f9a10"}'npx @meterapp/glossa update_unit --json '{"unit":"6f1c2e0a-4b7d-4c2e-9a51-0d3b8e7f9a10"}'{ "type": "object", "properties": { "unit": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "Unit id (a deduplicated source string shared by every key that points at it)." }, "description": { "type": "string", "maxLength": 4000 }, "max_length": { "anyOf": [ { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991 }, { "type": "null" } ] }, "tags": { "maxItems": 30, "type": "array", "items": { "type": "string", "maxLength": 50 } }, "retranslate": { "default": false, "type": "boolean" } }, "required": [ "unit" ]}set_translation
writeSet translation · POST /api/v1/set_translation
Write or correct a unit's translation in one locale. Every key sharing the unit gets it. Defaults to status reviewed; use approved for final copy. Placeholders must match the source.
curl -X POST https://glossa-meterapp.vercel.app/api/v1/set_translation \ -H "Authorization: Bearer gls_…" \ -H "Content-Type: application/json" \ -d '{"unit":"6f1c2e0a-4b7d-4c2e-9a51-0d3b8e7f9a10","locale":"es","text":"Bienvenido de nuevo"}'npx @meterapp/glossa set_translation --json '{"unit":"6f1c2e0a-4b7d-4c2e-9a51-0d3b8e7f9a10","locale":"es","text":"Bienvenido de nuevo"}'{ "type": "object", "properties": { "unit": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "Unit id (a deduplicated source string shared by every key that points at it)." }, "locale": { "type": "string", "minLength": 2, "maxLength": 35, "description": "BCP 47 locale, e.g. es, pt-BR, zh-Hans." }, "text": { "type": "string", "maxLength": 20000 }, "plural": { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "type": "string" } }, "status": { "default": "reviewed", "type": "string", "enum": [ "machine", "imported", "reviewed", "approved", "needs_review" ] }, "note": { "default": "", "type": "string", "maxLength": 2000 } }, "required": [ "unit", "locale", "text" ]}review_translations
writeReview translations · POST /api/v1/review_translations
Mark many translations reviewed, approved or needs_review at once, by unit and locale.
curl -X POST https://glossa-meterapp.vercel.app/api/v1/review_translations \ -H "Authorization: Bearer gls_…" \ -H "Content-Type: application/json" \ -d '{"locale":"es","units":["6f1c2e0a-4b7d-4c2e-9a51-0d3b8e7f9a10"],"status":"reviewed"}'npx @meterapp/glossa review_translations --json '{"locale":"es","units":["6f1c2e0a-4b7d-4c2e-9a51-0d3b8e7f9a10"],"status":"reviewed"}'{ "type": "object", "properties": { "locale": { "type": "string", "minLength": 2, "maxLength": 35, "description": "BCP 47 locale, e.g. es, pt-BR, zh-Hans." }, "units": { "minItems": 1, "maxItems": 500, "type": "array", "items": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "Unit id (a deduplicated source string shared by every key that points at it)." } }, "status": { "type": "string", "enum": [ "reviewed", "approved", "needs_review" ] } }, "required": [ "locale", "units", "status" ]}translate
writeTranslate · POST /api/v1/translate
Queue AI translation. Without units: fills every missing translation of a project (or the whole workspace) in the given locales. With units: (re)translates exactly those, replacing machine output but never reviewed, approved, imported or human translations. Returns a job id (get_job).
curl -X POST https://glossa-meterapp.vercel.app/api/v1/translate \ -H "Authorization: Bearer gls_…" \ -H "Content-Type: application/json" \ -d '{"locales":["es"]}'npx @meterapp/glossa translate --json '{"locales":["es"]}'{ "type": "object", "properties": { "locales": { "minItems": 1, "maxItems": 100, "type": "array", "items": { "type": "string", "minLength": 2, "maxLength": 35, "description": "BCP 47 locale, e.g. es, pt-BR, zh-Hans." } }, "project": { "type": "string", "minLength": 1, "description": "Project slug or id." }, "units": { "maxItems": 2000, "type": "array", "items": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "Unit id (a deduplicated source string shared by every key that points at it)." } } }, "required": [ "locales" ]}merge_units
writeMerge strings · POST /api/v1/merge_units
Point every key of the `merge` units at the `into` unit, so they share one translation per locale. The kept unit's translations win; a merged unit's translation fills a locale the kept unit lacks. The merged units are deleted.
curl -X POST https://glossa-meterapp.vercel.app/api/v1/merge_units \ -H "Authorization: Bearer gls_…" \ -H "Content-Type: application/json" \ -d '{"into":"6f1c2e0a-4b7d-4c2e-9a51-0d3b8e7f9a10","merge":["6f1c2e0a-4b7d-4c2e-9a51-0d3b8e7f9a10"]}'npx @meterapp/glossa merge_units --json '{"into":"6f1c2e0a-4b7d-4c2e-9a51-0d3b8e7f9a10","merge":["6f1c2e0a-4b7d-4c2e-9a51-0d3b8e7f9a10"]}'{ "type": "object", "properties": { "into": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "Unit id (a deduplicated source string shared by every key that points at it)." }, "merge": { "minItems": 1, "maxItems": 100, "type": "array", "items": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "Unit id (a deduplicated source string shared by every key that points at it)." } } }, "required": [ "into", "merge" ]}split_key
writeSplit key · POST /api/v1/split_key
Give one key its own unit (a copy of the source and its translations) so it can be translated differently from the other keys that shared the string. Use when the same English means different things in different places.
curl -X POST https://glossa-meterapp.vercel.app/api/v1/split_key \ -H "Authorization: Bearer gls_…" \ -H "Content-Type: application/json" \ -d '{"key_id":"6f1c2e0a-4b7d-4c2e-9a51-0d3b8e7f9a10"}'npx @meterapp/glossa split_key --json '{"key_id":"6f1c2e0a-4b7d-4c2e-9a51-0d3b8e7f9a10"}'{ "type": "object", "properties": { "key_id": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The key to split off (get_unit lists keys with ids)." }, "description": { "description": "Context that tells the new unit apart.", "type": "string", "maxLength": 4000 }, "retranslate": { "default": true, "description": "Retranslate the new unit's machine translations with its own context.", "type": "boolean" } }, "required": [ "key_id" ]}scan_duplicates
writeScan for near-duplicates · POST /api/v1/scan_duplicates
Queue a scan for near-duplicate strings (same meaning, slightly different text) and file merge_suggestion tasks for them.
curl -X POST https://glossa-meterapp.vercel.app/api/v1/scan_duplicates \ -H "Authorization: Bearer gls_…"npx @meterapp/glossa scan_duplicates{ "type": "object", "properties": { "threshold": { "default": 0.8, "type": "number", "minimum": 0.5, "maximum": 0.99 } }}Review queue
Claim and resolve review tasks.
list_tasks
readList review tasks · POST /api/v1/list_tasks or GET …?input=
The review queue, highest priority first. Each task has a kind, a title, a payload with everything needed to decide, and the actions it accepts (merge_review: keep_merged | split; merge_suggestion: merge_into_a | merge_into_b | keep_separate; learn_format: keep | retire | retry_with_hint | dismiss; translation_review: approve | edit | retranslate; audit_finding: apply | edit | dismiss; rule_suggestion: add | edit | dismiss; glossary_suggestion: add | dismiss).
curl -X POST https://glossa-meterapp.vercel.app/api/v1/list_tasks \ -H "Authorization: Bearer gls_…"npx @meterapp/glossa list_tasks{ "type": "object", "properties": { "status": { "default": "open", "type": "string", "enum": [ "open", "claimed", "resolved", "dismissed" ] }, "kind": { "type": "string", "enum": [ "merge_review", "merge_suggestion", "learn_format", "translation_review", "audit_finding", "rule_suggestion", "glossary_suggestion" ] }, "limit": { "default": 50, "description": "Page size, at most 200.", "type": "integer", "minimum": 1, "maximum": 200 }, "offset": { "default": 0, "type": "integer", "minimum": 0, "maximum": 9007199254740991 } }}claim_tasks
writeClaim review tasks · POST /api/v1/claim_tasks
Claim up to `limit` open tasks so parallel agents don't work the same ones. Claims expire after 30 minutes. Then decide each and call resolve_task.
curl -X POST https://glossa-meterapp.vercel.app/api/v1/claim_tasks \ -H "Authorization: Bearer gls_…"npx @meterapp/glossa claim_tasks{ "type": "object", "properties": { "kind": { "type": "string", "enum": [ "merge_review", "merge_suggestion", "learn_format", "translation_review", "audit_finding", "rule_suggestion", "glossary_suggestion" ] }, "limit": { "default": 10, "type": "integer", "minimum": 1, "maximum": 50 } }}resolve_task
writeResolve review task · POST /api/v1/resolve_task
Decide a task by naming one of its actions (merge_review: keep_merged | split; merge_suggestion: merge_into_a | merge_into_b | keep_separate; learn_format: keep | retire | retry_with_hint | dismiss; translation_review: approve | edit | retranslate; audit_finding: apply | edit | dismiss; rule_suggestion: add | edit | dismiss; glossary_suggestion: add | dismiss). The action is applied (split, merge, set translation, add rule, …) and the task is closed with your note. Pass text for edit actions, body for a rule edit, key_ids to choose which keys to split, hint for retry_with_hint.
curl -X POST https://glossa-meterapp.vercel.app/api/v1/resolve_task \ -H "Authorization: Bearer gls_…" \ -H "Content-Type: application/json" \ -d '{"task":"6f1c2e0a-4b7d-4c2e-9a51-0d3b8e7f9a10","action":"approve"}'npx @meterapp/glossa resolve_task --json '{"task":"6f1c2e0a-4b7d-4c2e-9a51-0d3b8e7f9a10","action":"approve"}'{ "type": "object", "properties": { "task": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "action": { "type": "string" }, "note": { "default": "", "type": "string", "maxLength": 2000 }, "text": { "type": "string", "maxLength": 20000 }, "body": { "type": "string", "maxLength": 2000 }, "key_ids": { "type": "array", "items": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" } }, "hint": { "type": "string", "maxLength": 2000 } }, "required": [ "task", "action" ]}Glossary
Brand names and fixed terms.
list_glossary
readList glossary · POST /api/v1/list_glossary or GET …?input=
Glossary terms: brand and product names that are never translated, and terms with a fixed translation per locale. Every translation prompt includes them.
curl -X POST https://glossa-meterapp.vercel.app/api/v1/list_glossary \ -H "Authorization: Bearer gls_…"npx @meterapp/glossa list_glossary{ "type": "object", "properties": {}}upsert_glossary_term
writeAdd or update glossary term · POST /api/v1/upsert_glossary_term
Add a term or change it. do_not_translate=true for brand names; translations maps locale → required translation (merged into the existing map).
curl -X POST https://glossa-meterapp.vercel.app/api/v1/upsert_glossary_term \ -H "Authorization: Bearer gls_…" \ -H "Content-Type: application/json" \ -d '{"term":"Glossa"}'npx @meterapp/glossa upsert_glossary_term --json '{"term":"Glossa"}'{ "type": "object", "properties": { "term": { "type": "string", "minLength": 1, "maxLength": 200 }, "do_not_translate": { "default": false, "type": "boolean" }, "translations": { "default": {}, "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "type": "string" } }, "note": { "default": "", "type": "string", "maxLength": 1000 } }, "required": [ "term" ]}delete_glossary_term
writeDelete glossary term · POST /api/v1/delete_glossary_term
Remove a glossary term; future translations no longer enforce it. Existing translations are unchanged.
curl -X POST https://glossa-meterapp.vercel.app/api/v1/delete_glossary_term \ -H "Authorization: Bearer gls_…" \ -H "Content-Type: application/json" \ -d '{"term":"Glossa"}'npx @meterapp/glossa delete_glossary_term --json '{"term":"Glossa"}'{ "type": "object", "properties": { "term": { "type": "string" } }, "required": [ "term" ]}Rules
Standing instructions for every translation.
list_rules
readList translation rules · POST /api/v1/list_rules or GET …?input=
Standing instructions appended to every translation prompt, globally or for one locale. Audits propose new ones as rule_suggestion tasks.
curl -X POST https://glossa-meterapp.vercel.app/api/v1/list_rules \ -H "Authorization: Bearer gls_…"npx @meterapp/glossa list_rules{ "type": "object", "properties": { "locale": { "type": "string", "minLength": 2, "maxLength": 35, "description": "BCP 47 locale, e.g. es, pt-BR, zh-Hans." }, "include_inactive": { "default": false, "type": "boolean" } }}add_rule
writeAdd translation rule · POST /api/v1/add_rule
Add a standing instruction for future translations, e.g. "Spanish: use tú, never usted" or "Keep button labels under 20 characters". locale null applies to every language.
curl -X POST https://glossa-meterapp.vercel.app/api/v1/add_rule \ -H "Authorization: Bearer gls_…" \ -H "Content-Type: application/json" \ -d '{"body":"Use tú, never usted."}'npx @meterapp/glossa add_rule --json '{"body":"Use tú, never usted."}'{ "type": "object", "properties": { "body": { "type": "string", "minLength": 3, "maxLength": 2000 }, "locale": { "default": null, "anyOf": [ { "type": "string", "minLength": 2, "maxLength": 35, "description": "BCP 47 locale, e.g. es, pt-BR, zh-Hans." }, { "type": "null" } ] }, "rationale": { "default": "", "type": "string", "maxLength": 2000 } }, "required": [ "body" ]}update_rule
writeUpdate translation rule · POST /api/v1/update_rule
Edit a translation rule's text, or set active=false to stop adding it to translation prompts.
curl -X POST https://glossa-meterapp.vercel.app/api/v1/update_rule \ -H "Authorization: Bearer gls_…" \ -H "Content-Type: application/json" \ -d '{"rule":"6f1c2e0a-4b7d-4c2e-9a51-0d3b8e7f9a10"}'npx @meterapp/glossa update_rule --json '{"rule":"6f1c2e0a-4b7d-4c2e-9a51-0d3b8e7f9a10"}'{ "type": "object", "properties": { "rule": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "body": { "type": "string", "minLength": 3, "maxLength": 2000 }, "active": { "type": "boolean" } }, "required": [ "rule" ]}Audits
Per-language quality reviews.
run_audit
writeRun audit · POST /api/v1/run_audit
Ask the AI to review one locale holistically ("How is our Spanish? Are brand names consistent?"). It answers the question, scores the locale, and files audit_finding, glossary_suggestion and rule_suggestion tasks. Runs as a job; read the result with get_audit.
curl -X POST https://glossa-meterapp.vercel.app/api/v1/run_audit \ -H "Authorization: Bearer gls_…" \ -H "Content-Type: application/json" \ -d '{"locale":"es"}'npx @meterapp/glossa run_audit --json '{"locale":"es"}'{ "type": "object", "properties": { "locale": { "type": "string", "minLength": 2, "maxLength": 35, "description": "BCP 47 locale, e.g. es, pt-BR, zh-Hans." }, "question": { "default": "", "type": "string", "maxLength": 2000 }, "sample_size": { "default": 300, "type": "integer", "minimum": 20, "maximum": 1000 } }, "required": [ "locale" ]}get_audit
readGet audit · POST /api/v1/get_audit or GET …?input=
An audit's answer, score and findings (empty while its job runs; see job_status).
curl -X POST https://glossa-meterapp.vercel.app/api/v1/get_audit \ -H "Authorization: Bearer gls_…" \ -H "Content-Type: application/json" \ -d '{"audit":"6f1c2e0a-4b7d-4c2e-9a51-0d3b8e7f9a10"}'npx @meterapp/glossa get_audit --json '{"audit":"6f1c2e0a-4b7d-4c2e-9a51-0d3b8e7f9a10"}'{ "type": "object", "properties": { "audit": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" } }, "required": [ "audit" ]}list_audits
readList audits · POST /api/v1/list_audits or GET …?input=
Past locale audits with their summary and score, newest first. Filter by locale.
curl -X POST https://glossa-meterapp.vercel.app/api/v1/list_audits \ -H "Authorization: Bearer gls_…"npx @meterapp/glossa list_audits{ "type": "object", "properties": { "locale": { "type": "string", "minLength": 2, "maxLength": 35, "description": "BCP 47 locale, e.g. es, pt-BR, zh-Hans." }, "limit": { "default": 50, "description": "Page size, at most 200.", "type": "integer", "minimum": 1, "maximum": 200 }, "offset": { "default": 0, "type": "integer", "minimum": 0, "maximum": 9007199254740991 } }}Jobs
Background AI work and its status.
get_job
readGet job · POST /api/v1/get_job or GET …?input=
Status and output of a background job (translate, learn_format, audit, dedupe_scan).
curl -X POST https://glossa-meterapp.vercel.app/api/v1/get_job \ -H "Authorization: Bearer gls_…" \ -H "Content-Type: application/json" \ -d '{"job":"6f1c2e0a-4b7d-4c2e-9a51-0d3b8e7f9a10"}'npx @meterapp/glossa get_job --json '{"job":"6f1c2e0a-4b7d-4c2e-9a51-0d3b8e7f9a10"}'{ "type": "object", "properties": { "job": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" } }, "required": [ "job" ]}list_jobs
readList jobs · POST /api/v1/list_jobs or GET …?input=
Recent background jobs (translate, learn_format, audit, dedupe_scan) with status and errors, newest first.
curl -X POST https://glossa-meterapp.vercel.app/api/v1/list_jobs \ -H "Authorization: Bearer gls_…"npx @meterapp/glossa list_jobs{ "type": "object", "properties": { "status": { "type": "string", "enum": [ "queued", "running", "done", "failed" ] }, "limit": { "default": 50, "description": "Page size, at most 200.", "type": "integer", "minimum": 1, "maximum": 200 }, "offset": { "default": 0, "type": "integer", "minimum": 0, "maximum": 9007199254740991 } }}API keys
Workspace keys for CLI, MCP and CI.
List API keys · POST /api/v1/list_api_keys or GET …?input=
API keys of this workspace (prefix only; the full key is shown once at creation).
curl -X POST https://glossa-meterapp.vercel.app/api/v1/list_api_keys \ -H "Authorization: Bearer gls_…"npx @meterapp/glossa list_api_keys{ "type": "object", "properties": {}}Create API key · POST /api/v1/create_api_key
Create a workspace API key for the CLI, MCP or CI. The full key (gls_…) is returned only once; store it as a secret.
curl -X POST https://glossa-meterapp.vercel.app/api/v1/create_api_key \ -H "Authorization: Bearer gls_…" \ -H "Content-Type: application/json" \ -d '{"name":"CI"}'npx @meterapp/glossa create_api_key --json '{"name":"CI"}'{ "type": "object", "properties": { "name": { "type": "string", "minLength": 1, "maxLength": 100 } }, "required": [ "name" ]}Revoke API key · POST /api/v1/revoke_api_key
Revoke an API key immediately; every CLI, CI job or MCP host using it stops working.
curl -X POST https://glossa-meterapp.vercel.app/api/v1/revoke_api_key \ -H "Authorization: Bearer gls_…" \ -H "Content-Type: application/json" \ -d '{"key":"6f1c2e0a-4b7d-4c2e-9a51-0d3b8e7f9a10"}'npx @meterapp/glossa revoke_api_key --json '{"key":"6f1c2e0a-4b7d-4c2e-9a51-0d3b8e7f9a10"}'{ "type": "object", "properties": { "key": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" } }, "required": [ "key" ]}Billing
Plans, prices, checkout links and the subscription.
get_pricing
readGet pricing · POST /api/v1/get_pricing or GET …?input=
The plans (Free, Pro, Team, Enterprise) with monthly and yearly prices in cents, AI translations included a month, member and project limits, features, and how to buy. Needs no credential over REST (GET /api/v1/get_pricing). Call before recommending or buying a plan.
curl -X POST https://glossa-meterapp.vercel.app/api/v1/get_pricing \ -H "Authorization: Bearer gls_…"npx @meterapp/glossa get_pricing{ "type": "object", "properties": {}}get_billing
readGet billing · POST /api/v1/get_billing or GET …?input=
This workspace's plan, subscription status, renewal or end date, whether a card is saved (so subscribe can charge it), and usage this month against the plan (AI translations, members, projects). Pass refresh: true right after a human finished a checkout to pull the latest state from Stripe.
curl -X POST https://glossa-meterapp.vercel.app/api/v1/get_billing \ -H "Authorization: Bearer gls_…"npx @meterapp/glossa get_billing{ "type": "object", "properties": { "refresh": { "default": false, "description": "Re-read the subscription from Stripe instead of the stored copy.", "type": "boolean" } }}Create checkout link · POST /api/v1/create_checkout_link
A Stripe Checkout URL where a human pays for a plan; hand it to them (or open it in their browser). Nothing is charged and the plan does not change until they complete it; then get_billing {refresh: true} shows the new plan. The link expires after 24 hours. If the workspace already has a subscription, the URL is a Stripe page where they confirm the plan change instead. Returns {url, kind: checkout | plan_change, plan, interval, amount_cents, expires_at}.
curl -X POST https://glossa-meterapp.vercel.app/api/v1/create_checkout_link \ -H "Authorization: Bearer gls_…" \ -H "Content-Type: application/json" \ -d '{"plan":"pro"}'npx @meterapp/glossa create_checkout_link --json '{"plan":"pro"}'{ "type": "object", "properties": { "plan": { "type": "string", "enum": [ "pro", "team" ], "description": "pro or team. get_pricing lists what each includes. Enterprise is sold by email." }, "interval": { "default": "month", "description": "month, or year (two months free).", "type": "string", "enum": [ "month", "year" ] } }, "required": [ "plan" ]}Subscribe · POST /api/v1/subscribe
Start or change this workspace's paid plan in one call, charging the card already saved for the workspace. Only after a human approved this plan and price: confirm must be true. Without a saved card (or if the card needs the human, e.g. 3-D Secure) nothing is charged and it returns status checkout_required with a checkout_url for a human to finish. A plan change is prorated and invoiced immediately. Returns {status: subscribed | changed | unchanged | checkout_required, billing}.
curl -X POST https://glossa-meterapp.vercel.app/api/v1/subscribe \ -H "Authorization: Bearer gls_…" \ -H "Content-Type: application/json" \ -d '{"plan":"pro","confirm":false}'npx @meterapp/glossa subscribe --json '{"plan":"pro","confirm":false}'{ "type": "object", "properties": { "plan": { "type": "string", "enum": [ "pro", "team" ], "description": "pro or team. get_pricing lists what each includes. Enterprise is sold by email." }, "interval": { "default": "month", "description": "month, or year (two months free).", "type": "string", "enum": [ "month", "year" ] }, "confirm": { "type": "boolean", "const": true, "description": "Must be true: a human has seen the plan and price and asked you to buy it. Never set it on your own initiative." } }, "required": [ "plan", "confirm" ]}Cancel subscription · POST /api/v1/cancel_subscription
Cancel the paid plan at the end of the current period (no refund; the plan stays until then, then the workspace is on Free). Only when a human asked: confirm must be true. resume_subscription undoes it before the period ends.
curl -X POST https://glossa-meterapp.vercel.app/api/v1/cancel_subscription \ -H "Authorization: Bearer gls_…" \ -H "Content-Type: application/json" \ -d '{"confirm":false}'npx @meterapp/glossa cancel_subscription --json '{"confirm":false}'{ "type": "object", "properties": { "confirm": { "type": "boolean", "const": true, "description": "Must be true: a human has seen the plan and price and asked you to buy it. Never set it on your own initiative." } }, "required": [ "confirm" ]}Resume subscription · POST /api/v1/resume_subscription
Undo a cancellation that has not taken effect yet, so the plan renews as before. Nothing is charged until the normal renewal date.
curl -X POST https://glossa-meterapp.vercel.app/api/v1/resume_subscription \ -H "Authorization: Bearer gls_…"npx @meterapp/glossa resume_subscription{ "type": "object", "properties": {}}Create billing portal link · POST /api/v1/create_billing_portal_link
A private Stripe page where a human downloads invoices, updates the card or billing details, or cancels. The link is for a human and expires after a few minutes of inactivity; never open it on your own.
curl -X POST https://glossa-meterapp.vercel.app/api/v1/create_billing_portal_link \ -H "Authorization: Bearer gls_…"npx @meterapp/glossa create_billing_portal_link{ "type": "object", "properties": {}}