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.
| Name | Type | Required | Default | Allowed values / range | Max length / items |
|---|---|---|---|---|---|
text | string | Yes | — | — | 20000 |
mode | string | No | "standard" | standard, fluent, formal, simple, creative, shorten, expand | — |
synonym_strength | integer | No | 50 | 0 to 100 | — |
action | string | No | "rewrite" | rewrite, alternatives | — |
target_word | string | If action=alternatives | — | — | 80 |
stream | boolean | No | false | — | — |
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"
}
}
| Code | HTTP | Cause | Fix |
|---|---|---|---|
invalid_request | 400 | Check the request fields and their allowed values. | Send the documented JSON fields with the correct types. Unknown fields are rejected. |
invalid_json | 400 | The request body is not valid JSON. | Serialize the request with JSON.stringify or your language's JSON encoder. |
unsupported_media_type | 415 | Send application/json content. | Set Content-Type: application/json. File uploads use their separate documented route. |
body_too_large | 413 | The request body exceeds the allowed size. | Reduce the payload and split long documents at sentence boundaries. |
text_too_long | 413 | The text exceeds the configured character limit. | Use the max_input_chars value in the API specification and split longer documents. |
unauthorized | 401 | A valid API key is required. | Send Authorization: Bearer YOUR_KEY. Create a new key if the old one was revoked. |
forbidden | 403 | This action is not available to this account. | Check account status and the key's access permissions. |
rate_limited | 429 | Too many requests. Please wait and try again. | Wait for Retry-After seconds and use exponential backoff with jitter. |
quota_exceeded | 429 | The monthly usage quota has been reached. | Wait for the next UTC calendar month or ask an administrator to change the plan. |
service_unavailable | 503 | A required service is temporarily unavailable. | Wait and retry. The operator should check Redis, PostgreSQL, or the tool's health. |
not_found | 404 | This resource does not exist. | Check the API version, endpoint name, and resource identifier. |
method_not_allowed | 405 | This HTTP method is not supported. | Use POST for processing endpoints and the method documented for dashboard routes. |
internal_error | 500 | The request could not be completed. | Retry once. If it persists, provide the X-Request-Id header to the operator. |
budget_exceeded | 429 | The 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_configured | 503 | The 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_unavailable | 503 | The writing provider is temporarily unavailable. | Retry with backoff. The operator can inspect provider availability without logging submitted text. |
upstream_timeout | 504 | The 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_error | 502 | The 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_truncated | 502 | The 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.