Tilbage til al dokumentation

Denne integrationsguide er kun tilgængelig på engelsk.

Reference

API and MCP reference

Fetch, push and keep translations current — from CI, a runtime, a browser or an AI assistant.

Every project has a UUID and its own API keys. Build-time integrations fetch a namespace per language with one GET; runtimes report missing keys as they meet them; CI declares the full key set with one PUT. The Embed script uses the unauthenticated endpoints from the visitor's browser, and an AI assistant reaches the same project over MCP.

The same description as a file: openapi.yml — OpenAPI 3.1, for Postman, code generators and agents. Every endpoint below has a Try it panel: the request leaves your browser for this site's own host with the token you paste, and nothing is stored.

Tokens and headers

Three tokens open the API. A project API key comes from a project's Connect page and is either read-only — it may fetch and nothing else — or read/write. A personal access token comes from your avatar → Personal access tokens and attributes every write to you; one token covers one project (pat_…) or the whole workspace (pat_ws_…). The API answers on https://app.bemywords.org; the marketing host serves it too, which is what the Try-it panels below use.

Authorization: Token token=YOUR_API_KEY      # project API key
Authorization: Bearer pat_…                  # personal access token

Ship a read-only key anywhere someone else can read it: a JavaScript bundle, a mobile app, a public repository. A read/write key in a browser lets anyone who views the source rewrite the strings that browser renders. A write attempted with a read-only key answers 403 with {"error":"read_only_key"}; a request without a valid token for the project answers 401 with {"error":"unauthorized"}.

Values are text and markup — links, <strong>, placeholders like %{name} — and what a browser would execute is refused with 422 invalid_translation: a value starting with a script URL, a link or image pointing at one, an inline event handler. That is a backstop, not a substitute for escaping where you render.

Translations

Project-scoped reads and writes. Authenticate with a project API key (Authorization: Token token=…) or a personal access token (Authorization: Bearer pat_…). A read-only key may only reach the two GETs; every write answers 403 read_only_key to it. Reads are not rate-limited; writes are capped at 300 a minute per project.

GET /api/{project_id}/latest/{language}/{namespace_key}

Read a namespace in one language (the CI fetch)

The flat { key: value } map for one namespace and language, served from a cache that writes refresh. Responses carry an ETag; send If-None-Match on repeat fetches and an unchanged body answers 304 Not Modified with no content. Cache the file in your build — a build only sees what existed when it ran.

Auth: Project API key or Personal access token

Parameter In What it is
project_id required path The project UUID, shown on the project's page and in its URL.
language required path A language code the project has on — `en`, `nb`, `sv`, `pt-BR`.
namespace_key required path The namespace's short key — `common`, `marketing`, `app`.

Responses

200 The namespace.
{
  "greeting": "Hei",
  "btn.save": "Lagre"
}
304 Your cached copy is still current.
401 Missing or wrong token
404 Unknown namespace

curl

curl -X GET \
  -H "Authorization: Token token=YOUR_API_KEY" \
  https://app.bemywords.org/api/PROJECT_ID/latest/nb/common
Try it

POST /api/missing/{project_id}/latest/{language}/{namespace_key}

Report missing keys

Adds keys the namespace does not have yet and leaves every existing translation untouched. The runtime safety net: when your i18n library meets a key it cannot find, post it with its source value and it appears for translation without waiting for the next build. Non-destructive, so safe to call from anywhere with a read/write key you control. Throttled with the other writes at 300 a minute per project.

Auth: Project API key or Personal access token — read/write

Parameter In What it is
project_id required path The project UUID, shown on the project's page and in its URL.
language required path A language code the project has on — `en`, `nb`, `sv`, `pt-BR`.
namespace_key required path The namespace's short key — `common`, `marketing`, `app`.

Request body

{
  "welcome.title": "Welcome to BeMyWords",
  "welcome.cta": "Get started"
}

Responses

201 Stored. Empty body.
403 The key is read-only.
413 Body over 5 MB — chunk it.
422 A value was refused — it starts with a script URL or carries an inline event handler.
{
  "error": "invalid_translation",
  "message": "Translation value starts with a script URL"
}

curl

curl -X POST \
  -H "Authorization: Token token=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"welcome.title":"Welcome to BeMyWords","welcome.cta":"Get started"}' \
  https://app.bemywords.org/api/missing/PROJECT_ID/latest/nb/common
Try it

PUT /api/sync/{project_id}/latest/{language}/{namespace_key}

Declare the full key set (CI)

Declares every key that exists in your source for this namespace. Keys in the payload are created or unhidden; keys the server has that you did not send are marked hidden so translators stop seeing them — only when language is the project's source language, and nothing is ever deleted. A first push to an unknown namespace creates it.

preserve_source_values (default true) decides who owns an edit to an existing source value: with the default, edits made in BeMyWords survive your syncs and only new keys take their value from the payload. Send false when the code is canonical — changed values are overwritten and listed in source_value_changed, and per-language locks on those keys clear so translators re-review.

dynamic_key_prefixes protects keys generated at runtime (error codes, for instance) from being hidden. partial: true marks one chunk of a larger file — nothing is hidden — for namespaces of about a thousand new keys and more, since a request has a 25-second budget; finish with one full sync. A flat { key: value } body is also accepted.

Auth: Project API key or Personal access token — read/write

Parameter In What it is
project_id required path The project UUID, shown on the project's page and in its URL.
language required path A language code the project has on — `en`, `nb`, `sv`, `pt-BR`.
namespace_key required path The namespace's short key — `common`, `marketing`, `app`.

Request body

{
  "translations": {
    "welcome.title": "Welcome",
    "welcome.cta": "Get started",
    "btn.save": "Save"
  },
  "dynamic_key_prefixes": [
    "errors.server."
  ],
  "preserve_source_values": true,
  "partial": false
}

Responses

200 What changed.
{
  "summary": {
    "total_incoming": 3,
    "created": 2,
    "hidden": 1,
    "unhidden": 0,
    "source_value_changed": 0,
    "unchanged": 1
  },
  "created": [
    "welcome.title",
    "btn.save"
  ],
  "unhidden": [],
  "hidden": [
    "legacy.unused_key"
  ],
  "source_value_changed": []
}
403 The key is read-only.
413 Body over 5 MB — send it as partial chunks.
422 A row failed to save.

curl

curl -X PUT \
  -H "Authorization: Token token=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"translations":{"welcome.title":"Welcome","welcome.cta":"Get started","btn.save":"Save"},"dynamic_key_prefixes":["errors.server."],"preserve_source_values":true,"partial":false}' \
  https://app.bemywords.org/api/sync/PROJECT_ID/latest/en/common
Try it

PUT /api/overwrite/{project_id}/latest/{language}/{namespace_key}

Overwrite values in one language

Force-sets the value of keys that already exist in this language. Keys it does not know come back in not_found and nothing is created — use missing or sync for that. refreshed lists keys whose value you sent unchanged while the source had moved: the row is stamped current so /api/stale stops flagging it, which is how you say "still correct for the new source" without rewriting it.

Auth: Project API key or Personal access token — read/write

Parameter In What it is
project_id required path The project UUID, shown on the project's page and in its URL.
language required path A language code the project has on — `en`, `nb`, `sv`, `pt-BR`.
namespace_key required path The namespace's short key — `common`, `marketing`, `app`.

Request body

{
  "welcome.title": "Welcome back",
  "btn.save": "Save changes"
}

Responses

200 What changed.
{
  "summary": {
    "total_incoming": 3,
    "updated": 1,
    "refreshed": 1,
    "unchanged": 0,
    "not_found": 1
  },
  "updated": [
    "welcome.title"
  ],
  "refreshed": [
    "btn.save"
  ],
  "unchanged": [],
  "not_found": [
    "missing.key"
  ]
}
403 The key is read-only.
422 A value was refused.

curl

curl -X PUT \
  -H "Authorization: Token token=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"welcome.title":"Welcome back","btn.save":"Save changes"}' \
  https://app.bemywords.org/api/overwrite/PROJECT_ID/latest/nb/common
Try it

GET /api/stale/{project_id}/latest/{namespace_key}

List translations the source has outrun

Keys whose translation in lang was made against an older source value than the current one. Rows that predate source versioning are included unless you pass include_null=false. Close the loop with overwrite (a human value) or retranslate (AI).

Auth: Project API key or Personal access token

Parameter In What it is
project_id required path The project UUID, shown on the project's page and in its URL.
namespace_key required path The namespace's short key — `common`, `marketing`, `app`.
lang required query The target language to check.
include_null query Set `false` to skip rows with no recorded source version.

Responses

200 The stale keys.
{
  "lang": "sv",
  "stale_keys": [
    "welcome.title",
    "btn.save"
  ]
}
404 Unknown namespace

curl

curl -X GET \
  -H "Authorization: Token token=YOUR_API_KEY" \
  https://app.bemywords.org/api/stale/PROJECT_ID/latest/common?lang=sv
Try it

POST /api/retranslate/{project_id}/latest/{language}/{namespace_key}

Retranslate keys with the project's AI

Regenerates the translations of the listed keys in language with the project's configured model and rules, and stores the result. Ten keys per call — the model runs inside the request — so chunk larger sets. Sixty calls a minute per project. Spend shows on Usage like any other AI work; on a BYOK workspace it runs on your key.

Auth: Project API key or Personal access token — read/write

Parameter In What it is
project_id required path The project UUID, shown on the project's page and in its URL.
language required path A language code the project has on — `en`, `nb`, `sv`, `pt-BR`.
namespace_key required path The namespace's short key — `common`, `marketing`, `app`.

Request body

[
  "welcome.title",
  "btn.save"
]

Responses

200 The new values, and what could not be done.
{
  "lang": "sv",
  "retranslated": {
    "welcome.title": "Välkommen tillbaka",
    "btn.save": "Spara ändringar"
  },
  "skipped_missing_source": [],
  "failed": []
}
422 Too many keys, or the project's AI is not configured.
429 Over sixty calls in a minute.

curl

curl -X POST \
  -H "Authorization: Token token=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '["welcome.title","btn.save"]' \
  https://app.bemywords.org/api/retranslate/PROJECT_ID/latest/nb/common
Try it

POST /api/{project_id}/sync_page_strings/{namespace_key}

Register page text as source strings

For sites where the source text is the key — hosted builders and the Embed script. Creates a source row per string that is new to the namespace, key equal to value, and never touches an existing row. Creates the namespace on first use. Sixty calls a minute per project.

Auth: Project API key or Personal access token — read/write

Parameter In What it is
project_id required path The project UUID, shown on the project's page and in its URL.
namespace_key required path The namespace's short key — `common`, `marketing`, `app`.

Request body

{
  "source_strings": [
    "Book a demo",
    "Read the guide"
  ]
}

Responses

200 Counts.
{
  "created": 2,
  "skipped": 0,
  "source_language": "en"
}
403 The key is read-only.
422 The strings could not be stored.

curl

curl -X POST \
  -H "Authorization: Token token=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"source_strings":["Book a demo","Read the guide"]}' \
  https://app.bemywords.org/api/PROJECT_ID/sync_page_strings/common
Try it

POST /api/{project_id}/redeploy

Refresh the cache and dispatch the project's redeploy

Refreshes the project's translation cache, then dispatches the GitHub Actions workflow configured under Connect → Redeploy, so a build-time site rebuilds with fresh strings. An audited human action: personal access tokens only, a project key answers 403 pat_required. Every attempt is listed under Recent redeploys on the Connect page.

Auth: Personal access token

Parameter In What it is
project_id required path The project UUID, shown on the project's page and in its URL.

Responses

200 Dispatched.
{
  "ok": true,
  "dispatched_at": "2026-07-28T12:00:00Z"
}
403 A project key was used.
{
  "error": "pat_required"
}
422 GitHub is not configured for the project, or its key is bad.
{
  "ok": false,
  "error": "not_configured"
}
502 GitHub refused the dispatch.

curl

curl -X POST \
  -H "Authorization: Bearer pat_…" \
  https://app.bemywords.org/api/PROJECT_ID/redeploy
Try it

Account

Who am I — for personal access tokens.

GET /api/me

The token's owner and what it reaches

A project token answers with its one project; a workspace token (pat_ws_…) answers with the workspace and every active project in it. The cheapest way to check a token before wiring it anywhere.

Auth: Personal access token

Responses

200 Owner, and project or workspace.
{
  "user": {
    "id": "6f1c…",
    "email": "you@example.com"
  },
  "project": {
    "id": "4d1e…",
    "title": "Marketing site",
    "source_language": "en",
    "enabled_languages": [
      "nb",
      "sv"
    ],
    "editable_languages": [
      "nb",
      "sv",
      "da"
    ],
    "namespaces": [
      "common",
      "marketing"
    ],
    "deploy_configured": true,
    "integration_type": "astro",
    "auto_translate_languages": [
      "nb",
      "sv"
    ]
  }
}
401 Not a valid personal access token.

curl

curl -X GET \
  -H "Authorization: Bearer pat_…" \
  https://app.bemywords.org/api/me
Try it

MCP

The Model Context Protocol endpoints — JSON-RPC 2.0 over HTTP, stateless, one POST per call. The full tool list is generated further down this page.

POST /api/mcp

MCP — the whole workspace

Workspace tokens only (pat_ws_…). JSON-RPC 2.0 in the body, one call per POST, Accept: application/json. No session is minted — every request stands alone, which is what lets it run on many dynos; tools/list and tools/call work without a prior initialize. Tools name a project per call. Send the header X-BeMyWords-Read-Only: 1 and only the read tools are offered.

Auth: Personal access token

Parameter In What it is
X-BeMyWords-Read-Only header Any value restricts the connection to read tools.

Request body

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/list"
}

Responses

200 The JSON-RPC result.
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "tools": [
      {
        "name": "list_projects"
      }
    ]
  }
}
401 Not a workspace token.

curl

curl -X POST \
  -H "Authorization: Bearer pat_…" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' \
  https://app.bemywords.org/api/mcp
Try it

POST /api/{project_id}/mcp

MCP — one project

Any token for the project: an API key or a personal access token. The same protocol and tools as the workspace endpoint, with the project fixed, so a builder connected here never names one. A read-only API key is offered read tools only, whatever the client declares.

Auth: Project API key or Personal access token

Parameter In What it is
project_id required path The project UUID, shown on the project's page and in its URL.
X-BeMyWords-Read-Only header Any value restricts the connection to read tools.

Request body

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "get_project_status",
    "arguments": {}
  }
}

Responses

200 The JSON-RPC result.
401 Not a token for this project.

curl

curl -X POST \
  -H "Authorization: Token token=YOUR_API_KEY" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"get_project_status","arguments":{}}}' \
  https://app.bemywords.org/api/PROJECT_ID/mcp
Try it

Embed

The unauthenticated endpoints the Embed script calls from a visitor's browser. CORS-open, throttled per IP, guarded by the project's allowed origins where a project is named.

POST /api/embed/resolve

Host → project (the first-load handshake)

Called once by the Embed script with the workspace's public token and the page's host. Answers the project for that host, creating it on first sight — the zero-config install. Thirty calls a minute per IP. Answers 503 while the emergency switch is off.

Auth: No token — called from the visitor's browser

Request body

{}

Responses

200 The project.
{
  "project_id": "4d1e…"
}
402 The plan's host limit is reached.
403 The host is not authorized for this account.
404 Unknown public token.
422 Not a host name.

curl

curl -X POST \
  -H "Content-Type: application/json" \
  -d '{}' \
  https://app.bemywords.org/api/embed/resolve
Try it

POST /api/embed/{project_id}/harvest

Report page strings the project does not know

The script posts text it found on the page and could not translate — up to fifty strings a call, two to five thousand characters each — and they become source rows, key equal to value. Always answers 204, also when the origin is not permitted or the project is not in Embed mode; nothing about the outcome is disclosed to a page. Sixty calls a minute per IP.

Auth: No token — called from the visitor's browser

Parameter In What it is
project_id required path The project UUID, shown on the project's page and in its URL.

Request body

{
  "strings": [
    "Book a demo",
    "Read the guide"
  ]
}

Responses

204 Taken.

curl

curl -X POST \
  -H "Content-Type: application/json" \
  -d '{"strings":["Book a demo","Read the guide"]}' \
  https://app.bemywords.org/api/embed/PROJECT_ID/harvest
Try it

GET /api/{project_id}/dictionary/{language}/{namespace_key}

The public swap dictionary

A flat { text_on_the_page: text_it_should_say } map for one namespace and language, read by the script on every page view and swapped into the DOM. Two kinds of entry, and which you get depends on src:

  • source → current — for a page still showing the text as authored.
  • prior → current — for a page whose translations were baked into its build before someone corrected them. Present only while the project has keep my site up to date between deploys on.

A regional tag falls back to its base language (en-GBen). Carries an ETag that varies with src; unchanged answers 304. Refused with 403 from an origin the project has not allowed. Counts as visitor demand for the language. 240 calls a minute per IP.

Auth: No token — called from the visitor's browser

Parameter In What it is
project_id required path The project UUID, shown on the project's page and in its URL.
language required path A language code the project has on — `en`, `nb`, `sv`, `pt-BR`.
namespace_key required path The namespace's short key — `common`, `marketing`, `app`.
src query `0` asks for the prior → current entries only. Send it when the page's translations came from its own build, so the swap corrects stale strings without rewriting text from source. Omit it for the full map — which is what every embed built before this parameter existed does.

Responses

200 The dictionary.
{
  "Book a demo": "Bestill en demo",
  "Read the guide": "Les guiden"
}
304 Unchanged.
403 Origin not allowed.
404 Unknown project

curl

curl -X GET \
  https://app.bemywords.org/api/PROJECT_ID/dictionary/nb/common
Try it

GET /api/{project_id}/changes/{language}/{namespace_key}

What changed since a moment

Translations that changed after since (ISO 8601, at most seven days back), each with the prior values that are safe to swap for the current one. Used by the editor and by ?bw-live previews. A visitor's page never calls it: the dictionary carries recent prior values, so one fetch both translates the page and corrects anything stale on it. At most 500 changes; truncated says when there were more. 120 calls a minute per IP.

Auth: No token — called from the visitor's browser

Parameter In What it is
project_id required path The project UUID, shown on the project's page and in its URL.
language required path A language code the project has on — `en`, `nb`, `sv`, `pt-BR`.
namespace_key required path The namespace's short key — `common`, `marketing`, `app`.
since required query

Responses

200 The changes.
{
  "since": "2026-09-12T06:00:00Z",
  "server_time": "2026-09-12T15:40:12Z",
  "changes": [
    {
      "key": "welcome.title",
      "current": "Velkommen tilbake",
      "priors": [
        "Velkommen"
      ]
    }
  ],
  "truncated": false
}
400 `since` is missing, unparsable or in the future.
404 Unknown project

curl

curl -X GET \
  https://app.bemywords.org/api/PROJECT_ID/changes/nb/common?since=2026-09-12T06:00:00Z
Try it

POST /api/{project_id}/install_ping

We see your site

One ping per browser session so the dashboard can show that the script is live, kept seven days, no analytics. Sixty a minute per IP.

Auth: No token — called from the visitor's browser

Parameter In What it is
project_id required path The project UUID, shown on the project's page and in its URL.

Responses

204 Noted.
404 Unknown project.

curl

curl -X POST \
  https://app.bemywords.org/api/PROJECT_ID/install_ping
Try it

GET /api/{project_id}/public_info

Languages for the switcher

The project's source language, the languages live for visitors, and whether the footer switcher shows — what the script needs to draw the dropdown without baking a list into the tag. Cached five minutes. 120 calls a minute per IP.

Auth: No token — called from the visitor's browser

Parameter In What it is
project_id required path The project UUID, shown on the project's page and in its URL.

Responses

200 The project's public shape.
{
  "source_language": "en",
  "enabled_languages": [
    "nb",
    "sv"
  ],
  "show_switcher": true,
  "capabilities": {
    "mode": "auto",
    "jit_harvest": true,
    "auto_apply": true
  }
}
404 Unknown project.

curl

curl -X GET \
  https://app.bemywords.org/api/PROJECT_ID/public_info
Try it

MCP tools

What the server offers a connected assistant, generated from the tools it serves. Connect by URL with a personal access token as Bearer — the MCP guide has the client-by-client steps and the prompt to paste into an app builder. Every connection receives these standing instructions:

BeMyWords keeps a project's user-facing text translated. Recommended loop for an app or site:
1. get_project_status — source language, languages on, namespace keys. Turn on any language the user asked for with enable_language BEFORE registering strings.
2. Register every user-facing string you write with register_source_strings (namespace "app", keys like section.element). Never write your own translations; respect list_terminology.
3. Ship translations the simplest way: get_embed_snippet returns one <script> tag — paste it into the app's HTML head and every page is translated in the visitor's browser, with a language switcher. No files, no i18n library, nothing to re-fetch.
Only if the user wants the translations as files inside their build: wait until get_project_status shows missing = 0 per language, then get_translations per language into the app's locale files. Translation is asynchronous — never fetch before it is finished.

Read tools

list_projects

List the workspace's projects with the ids the other tools' project_id argument expects.

get_project_status

Project overview: source language, enabled languages, namespaces, and per-language counts of translated, missing and source-drifted strings. Call this first to learn the namespace keys and language codes the other tools expect.

  • project_id Project id (see list_projects). Required on the workspace endpoint; omit when connected to a project endpoint.

get_embed_snippet

The simplest way to ship translations: returns one <script> tag for this project. Paste it into the app's HTML <head> (index.html) and every page is translated in the visitor's browser as soon as strings are registered — a footer language switcher included. No translation files, no i18n library, nothing to re-fetch when text changes. Prefer this over get_translations unless the user asks for translation files in their build.

  • project_id Project id (see list_projects). Required on the workspace endpoint; omit when connected to a project endpoint.

get_translations

Fetch one language's translations as an i18n file (json, yml, po or strings) to write into the project, e.g. src/locales/<language>.json — for a user who wants the translations inside their build rather than the get_embed_snippet script. Translation is asynchronous: check get_project_status shows missing = 0 for the language first, or the file will be incomplete. Includes approved translations and AI drafts.

  • project_id Project id (see list_projects). Required on the workspace endpoint; omit when connected to a project endpoint.
  • language required Language code, e.g. 'nb'. Must be enabled on the project — see get_project_status.
  • format File format. Default json.
  • namespace_key Limit to one namespace. Default: the whole project.

get_translation

One translation key across all languages — values, statuses, flags and comments.

  • project_id Project id (see list_projects). Required on the workspace endpoint; omit when connected to a project endpoint.
  • namespace_key required Namespace the key lives in.
  • translation_key required The key, e.g. 'hero.title'.

search_translations

Search a project's translations by key or value substring, language and status. Returns at most 50 rows; pass the returned next_offset to page.

  • project_id Project id (see list_projects). Required on the workspace endpoint; omit when connected to a project endpoint.
  • key_contains Substring of the translation key.
  • value_contains Substring of the translated text.
  • language Limit to one language code.
  • status Limit to one status.
  • offset Paging offset from a previous call's next_offset.

list_terminology

Glossary, do-not-translate terms and substitution rules for this project. Respect these in any text you write or translate: glossary pairs are fixed translations, do-not-translate terms must appear verbatim in every language.

  • project_id Project id (see list_projects). Required on the workspace endpoint; omit when connected to a project endpoint.
  • locale Limit glossary and substitution rules to one language (rules marked 'all' are always included).

get_checkup_report

Findings from the most recent completed AI checkup or language audit (or one named by report_id).

  • project_id Project id (see list_projects). Required on the workspace endpoint; omit when connected to a project endpoint.
  • report_id A specific report's id. Default: the newest completed one.

Write tools

A read-only key, or the header X-BeMyWords-Read-Only: 1, hides these. Everything a write tool changes is attributed to the token's owner and lands as needs review.

enable_language

Turn on a target language for the project. Enable the languages FIRST: strings registered afterwards are translated into every enabled language automatically, while strings that already exist need ai_translate_keys or the app's Translate action to fill the new language. No plan limits how many languages a project has.

  • project_id Project id (see list_projects). Required on the workspace endpoint; omit when connected to a project endpoint.
  • language required Language code to enable, e.g. 'es'. Must be a language BeMyWords supports, and not the project's source language.

register_source_strings

Register source-language strings as they are written. Creates missing keys only — an existing key's value is never changed. Translation into the project's languages starts automatically. Call this whenever new user-facing text is added.

  • project_id Project id (see list_projects). Required on the workspace endpoint; omit when connected to a project endpoint.
  • namespace_key required Namespace to file the strings under, e.g. 'app' or 'marketing'. Created if new.
  • strings required Map of translation key to source-language text, e.g. {"hero.title": "Welcome"}.

update_translation

Set one translation's text. Lands as needs_review for a human to approve unless status 'approved' is explicitly requested. Attributed to the token's user.

  • project_id Project id (see list_projects). Required on the workspace endpoint; omit when connected to a project endpoint.
  • namespace_key required
  • translation_key required
  • language required Language of the value being written.
  • value required The new text.
  • status Default needs_review.

set_translation_status

Mark one translation approved or needs_review without changing its text.

  • project_id Project id (see list_projects). Required on the workspace endpoint; omit when connected to a project endpoint.
  • namespace_key required
  • translation_key required
  • language required
  • status required

add_key

Create one new key with its source-language text. Fails if the key exists — an existing value is never changed. Translation starts automatically.

  • project_id Project id (see list_projects). Required on the workspace endpoint; omit when connected to a project endpoint.
  • namespace_key required
  • translation_key required
  • source_value required The source-language text.

add_comment

Comment on one translation (e.g. why a wording was chosen, or a question for the reviewer).

  • project_id Project id (see list_projects). Required on the workspace endpoint; omit when connected to a project endpoint.
  • namespace_key required
  • translation_key required
  • language required Which language's row to comment on.
  • body required

flag_translation

Set do_not_translate (term must stay verbatim) or language_locked (this language's value must not be overwritten) on one row.

  • project_id Project id (see list_projects). Required on the workspace endpoint; omit when connected to a project endpoint.
  • namespace_key required
  • translation_key required
  • language required
  • flag required
  • value required true to set, false to clear.

add_glossary_term

Add a glossary pair: whenever source_term appears, translations must use target_term. Applies to one locale, or 'all'.

  • project_id Project id (see list_projects). Required on the workspace endpoint; omit when connected to a project endpoint.
  • source_term required
  • target_term required
  • locale Language code, or 'all' (default).

ai_translate_keys

AI-translate up to 10 named keys into one language. Approved translations are never overwritten. For whole-language coverage, the app's own Translate action is the right tool — this is for a handful of keys.

  • project_id Project id (see list_projects). Required on the workspace endpoint; omit when connected to a project endpoint.
  • namespace_key required
  • translation_keys required Keys to translate.
  • target_lang required

Webhooks

Outbound — a translation was approved, created or updated

Configure an endpoint under Connect → Webhooks. Each delivery is a POST with X-Webhook-Secret carrying your shared secret verbatim — compare it before trusting the body. At-least-once: a failed delivery is retried three times with backoff, the last outcome per webhook shows on the Connect page, endpoints get ten seconds, and private or loopback addresses are refused. Events: translation.approved, translation.created, translation.updated.

{
  "event": "translation.approved",
  "timestamp": "2026-07-28T12:00:00Z",
  "data": {
    "key": "home.hero.kicker",
    "locale": "nb",
    "project": "Marketing site"
  }
}

Status codes

200 OK A read, or a write that reports what changed.
201 Created Missing keys stored.
204 No Content Taken — the Embed endpoints that report nothing back.
304 Not Modified Your If-None-Match still matches; reuse your copy.
400 Bad Request A required query parameter is missing or unparsable.
401 Unauthorized No token, a wrong one, or one for another project.
403 Forbidden A read-only key on a write, a project key where a personal token is required, or an origin the project has not allowed.
404 Not Found Unknown project, namespace, or a language the project does not have on.
413 Payload Too Large Body over 5 MB — chunk it; sync accepts partial: true.
422 Unprocessable A value was refused or a row failed to save; the body says which.
429 Too Many Requests Writes are capped at 300 a minute per project, retranslate at 60; the Embed endpoints per IP as listed above.

Hvad koster BeMyWords?

Gratis at starte: 5.000 ord gemt, 1 websted, intet kort. Betalte planer starter ved 199 kr om måneden — 1.990 kr for et år — og tælles på gemte ord — kilden plus hver oversættelse af den — aldrig på brugere, sidevisninger eller en grænse for hvor mange sprog du kører. Medbring din egen AI-nøgle og det er 199 kr om måneden fast uden ordgrænse.

Hvilket niveau det er afhænger af hvor mange ord dit websted indeholder. Indsæt din adresse, så læser vi den og fortæller dig det.

Hver plan, og hvad den indeholder Beregn størrelsen på dit websted

Opret et projekt, og den første forespørgsel er ét curl væk.

Den gratis tier inkluderer API'en, MCP og Embed-scriptet. Intet kort.

Start gratis