Browse documentation
METAPHRASE / ENDPOINTSREST API v1
Open in AI
Open in ChatGPT Open in Claude
Markdown

paraphrase

Rewrite text in one of seven modes while preserving its meaning.

Endpoint and method

POST https://metaphrase.msalman.com/api/v1/paraphrase

Authentication

Send Authorization: Bearer <key> and Content-Type: application/json. Create a key at the dashboard. Store it in backend environment variable METAPHRASE_API_KEY; never expose it in a browser, mobile binary, public repository, or widget. See authentication and a working backend proxy.

Request parameters

JSON uses snake_case. Unknown fields are rejected. Omit optional values instead of sending null. Maximum text length: 20,000 Unicode code points.

NameTypeRequiredDefaultAllowed values / rangeMax length / items
textstringYes——20000
modestringNo"standard"standard, fluent, formal, simple, creative, shorten, expand—
synonym_strengthintegerNo500 to 100—
actionstringNo"rewrite"rewrite, alternatives—
target_wordstringIf action=alternatives——80
streambooleanNofalse——
  • text: Plain text. Limit counts Unicode code points.
  • mode: Rewrite style. All seven modes preserve source language, names, facts and meaning.
  • synonym_strength: Vocabulary change strength, from 0 (minimal) to 100 (strong).
  • action: rewrite returns rewritten text; alternatives returns context-appropriate alternatives for target_word.
  • target_word: Required for action=alternatives. Must appear in text; returns up to eight alternatives, at most 80 characters each.
  • stream: Use true for SSE on paraphrase/rewrite, translate or summarize. Other operations require false; alternatives always returns JSON.

All modes preserve the source language. synonym_strength controls vocabulary changes. changes contains output segments with changed=true for newly written words; concatenating segments reconstructs result.text. For contextual word alternatives, send action=alternatives and target_word that appears in text; it always returns JSON, even if stream=true.

Full example request

{
  "text": "Good writing helps people understand an idea.",
  "mode": "standard",
  "synonym_strength": 50,
  "action": "rewrite",
  "stream": false
}

Word alternatives request (same endpoint):

{
  "text": "Good writing helps people understand an idea.",
  "action": "alternatives",
  "target_word": "Good",
  "mode": "standard",
  "synonym_strength": 50,
  "stream": false
}

Full example response

HTTP 200, application/json. This is an illustrative response; writing, source metadata, token counts and cost can vary. request_id is a server-generated UUID. Cache hits use usage.cached=true and report zero new tokens/cost. usage_estimated=true means the provider did not supply exact token counts.

{
  "request_id": "019b8df0-1234-4000-8000-000000000001",
  "tool": "paraphrase",
  "result": {
    "text": "Clear writing makes ideas easier to understand.",
    "mode": "standard",
    "synonym_strength": 50,
    "changes": [
      {
        "text": "Clear writing makes ideas easier to understand.",
        "changed": true
      }
    ]
  },
  "usage": {
    "input_tokens": 60,
    "output_tokens": 20,
    "total_tokens": 80,
    "estimated_cost_usd": 0.000016,
    "usage_estimated": false,
    "cached": false,
    "provider": "primary",
    "model": "gpt-6-luna"
  },
  "input_words": 7,
  "output_words": 7
}

For alternatives, the same envelope contains result.text equal to the input, changes: [], target_word, and up to eight alternatives, for example ["Clear", "Effective", "Thoughtful", "Strong", "Skilled"]. Usage is metered in the usual envelope.

Errors: cause and fix

Every error uses this JSON shape and a link to its exact fix:

{
  "error": {
    "code": "unauthorized",
    "message": "A valid API key is required.",
    "docs_url": "https://metaphrase.msalman.com/docs/errors#unauthorized"
  }
}
CodeHTTPCauseFix
invalid_request400Check the request fields and their allowed values.Send the documented JSON fields with the correct types. Unknown fields are rejected.
invalid_json400The request body is not valid JSON.Serialize the request with JSON.stringify or your language's JSON encoder.
unsupported_media_type415Send application/json content.Set Content-Type: application/json. File uploads use their separate documented route.
body_too_large413The request body exceeds the allowed size.Reduce the payload and split long documents at sentence boundaries.
text_too_long413The text exceeds the configured character limit.Use the max_input_chars value in the API specification and split longer documents.
unauthorized401A valid API key is required.Send Authorization: Bearer YOUR_KEY. Create a new key if the old one was revoked.
forbidden403This action is not available to this account.Check account status and the key's access permissions.
rate_limited429Too many requests. Please wait and try again.Wait for Retry-After seconds and use exponential backoff with jitter.
quota_exceeded429The monthly usage quota has been reached.Wait for the next UTC calendar month or ask an administrator to change the plan.
service_unavailable503A required service is temporarily unavailable.Wait and retry. The operator should check Redis, PostgreSQL, or the tool's health.
not_found404This resource does not exist.Check the API version, endpoint name, and resource identifier.
method_not_allowed405This HTTP method is not supported.Use POST for processing endpoints and the method documented for dashboard routes.
internal_error500The request could not be completed.Retry once. If it persists, provide the X-Request-Id header to the operator.
budget_exceeded429The writing service has reached its configured spending limit.The operator must review usage and adjust the configured budget before more paid requests can run.
provider_not_configured503The writing provider is not configured yet.The operator must configure LLM_PRIMARY_API_KEY or a fallback provider in .env and recreate the web container.
upstream_unavailable503The writing provider is temporarily unavailable.Retry with backoff. The operator can inspect provider availability without logging submitted text.
upstream_timeout504The writing provider took too long to respond.Retry a shorter input or wait before retrying. Do not append a retry to partial streamed output.
upstream_error502The writing provider returned an invalid response.Retry once with a shorter input. If it continues, the operator should check the configured model's compatibility.
output_truncated502The response reached its output limit before finishing.Use a shorter input or ask the operator to adjust the tool's output cap and chunk size.

For streaming requests, failures after HTTP headers are sent arrive as an SSE error event with this same error object. Never treat partial text as a completed result or append output from a retry.

Rate limits and quotas

Defaults: Free 15 requests per 60 seconds and 500 accepted calls per key per UTC calendar month; Pro placeholders 120/60 seconds and 25,000/month. The operator can change plans; response headers are authoritative. Calls to all tools share a key's limits. Accepted cache hits and upstream failures consume quota. Authentication/schema failures and provider-not-configured preflight failures do not. X-RateLimit-Remaining, X-RateLimit-Reset, X-Quota-Remaining and X-Quota-Reset show remaining capacity and Unix-second reset times. For HTTP 429 wait Retry-After seconds; quota/budget limits need a reset or operator action. Requests may also receive 429 when the shared processing slots are busy. See retries and long texts.

Code samples

Complete backend programs. Set METAPHRASE_API_KEY in your server environment; never expose it in a frontend.

request.sh
#!/usr/bin/env bash
set -euo pipefail
: "${METAPHRASE_API_KEY:?Set METAPHRASE_API_KEY in your backend environment}"
BASE_URL="${METAPHRASE_BASE_URL:-https://metaphrase.msalman.com}"
curl --fail-with-body --silent --show-error \
  --request POST "${BASE_URL%/}/api/v1/paraphrase" \
  --header "Authorization: Bearer $METAPHRASE_API_KEY" \
  --header 'Content-Type: application/json' \
  --data-binary @- <<'JSON'
{
  "text": "Good writing helps people understand an idea.",
  "mode": "standard",
  "synonym_strength": 50,
  "action": "rewrite",
  "stream": false
}
JSON

Run: bash request.sh

Try the API with Scalar

Explore the schema and send a real request. Enter your key only in this playground.