endpoint
POST /v1/chat/completions
OpenAI-compatible, so existing client code works by changing two lines. It is a shim over a model that is not a chat model, and the places where that shows are listed below rather than left for you to discover.
from openai import OpenAI
client = OpenAI(
api_key=os.environ["MERAGPT_API_KEY"],
base_url="https://meragpt.com/v1",
)
resp = client.chat.completions.create(
model="text-restyler-1",
messages=[{"role": "user", "content": draft}],
)
print(resp.choices[0].message.content)The model you name selects the behaviour
The two models do different shapes of work, and this endpoint switches on the model field rather than on anything in the messages. Name text-restyler-1 and the last user message is treated as a document: split into paragraph-sized blocks, rewritten block by block, and rejoined. Name query-fanout-1 and it is treated as a question, which is never split, and the searches come back in one generation. They are not interchangeable — a rewrite is bounded against the length of its source, while a fan-out legitimately returns several times its input.
So the request limits differ too: Query Fanout 1 rejects an input over 2000 characters with 400 input_too_large, where the Restyler’s bound is 6,000.
Where it differs from OpenAI
- Only the last user message is used. There is no conversation to carry. Earlier turns and any system message are ignored, because concatenating them would build a prompt the model never saw in training and would make the output worse, not richer.
temperature,top_pand other sampling parameters are accepted and ignored. Decoding is fixed per model at whatever measured best for its task: greedy with a repetition penalty for the Restyler, where sampling measured worse on both naturalness and preservation and greedy without the penalty degenerates into repetition loops; temperature 0.7 for the fan-out, where greedy collapses a set of searches into one search written several ways. Requests are not rejected for sending them, so OpenAI client defaults work; the response says which was used in itsmeragptblock.- Streaming is not token-level. For a restyle each SSE chunk carries a whole paragraph rather than a token: documents fill in from the top, which is what the streaming is for, but a progress bar keyed to token counts will move in jumps. For a fan-out the whole list arrives as a single delta, because the queries are deduplicated as a set — two of them can collapse into one — so nothing can be emitted honestly until generation has finished.
n,tools,logprobsandresponse_formatare not supported. They have no meaning for these single-task completion models.
Response
{
"id": "chatcmpl-...",
"object": "chat.completion",
"created": 1788000000,
"model": "text-restyler-1",
"choices": [
{
"index": 0,
"message": { "role": "assistant", "content": "The restyled document." },
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 58,
"completion_tokens": 49,
"total_tokens": 107
},
"meragpt": {
"blocks_rewritten": 1,
"blocks_total": 2,
"cost_nano_usd": 9150,
"sampling": "fixed (greedy); temperature and top_p are ignored"
}
}The meragpt object is an addition to the OpenAI shape. Clients that do not know about it ignore it.
Query fan-out through the chat envelope
Name query-fanout-1, put the question in the last user message, and the searches come back newline-joined in the assistant message, because that is the only field an OpenAI client knows how to read. The structured list is also there, under meragpt.queries, so you do not have to split prose.
resp = client.chat.completions.create(
model="query-fanout-1",
messages=[{"role": "user", "content": "What are the best project management tools available right now?"}],
)
queries = resp.model_extra["meragpt"]["queries"]{
"id": "chatcmpl-...",
"object": "chat.completion",
"created": 1788000000,
"model": "query-fanout-1",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "best project management software 2026\nproject management tool comparison pricing"
},
"finish_reason": "stop"
}
],
"usage": { "prompt_tokens": 34, "completion_tokens": 42, "total_tokens": 76 },
"meragpt": {
"queries": [
"best project management software 2026",
"project management tool comparison pricing"
],
"cost_nano_usd": 8000,
"sampling": "fixed (temperature 0.7); caller temperature and top_p are ignored"
}
}There are no blocks_* counts here: there is one generation and nothing was split. The optional brands and category hint has nowhere to go in a chat request, so it is available only on /v1/fanout.
Streaming
stream = client.chat.completions.create(
model="text-restyler-1",
messages=[{"role": "user", "content": draft}],
stream=True,
)
for chunk in stream:
print(chunk.choices[0].delta.content or "", end="")The final chunk carries usage and the meragpt block. If something fails after the stream has opened, the status code is already sent, so the failure arrives as a frame containing an error object, check for it rather than assuming every frame is a delta.
Prefer the task-native endpoints
/v1/restyle does the same work and reports per block what it rewrote, what it skipped and why. /v1/fanout returns the searches as an array in a field called queries and accepts the brand hint. The chat envelope has nowhere to put either.