Request parameters
Four settings shape almost every request: how long the reply may be, the instructions the model follows, where it must stop, and who the request is for. This page covers each one on POST /v1/chat/completions. The same fields exist on Messages with the names noted below.
Today only max_tokens and the system message reach the model; stop, user and metadata are accepted and ignored. This page is the design for honouring all of them.
At a glance
| Field | Type | Default | Purpose |
|---|---|---|---|
max_tokens | integer | model’s max_output_tokens | Cap on output tokens. |
messages[0] with role: "system" | message | none | Instructions for the whole conversation. |
stop | string or array of up to 4 strings | none | End the reply as soon as one of these strings is produced. |
user | string | none | A stable id for the end user who triggered the request. |
metadata | object | none | Your own tags, stored with the usage record. |
Endpoint and auth
POST https://app.syntic.ai/v1/chat/completions
Authorization: Bearer sk_live_...
Content-Type: application/jsonmax_tokens
The highest number of tokens the reply may contain. When generation reaches it, the reply ends and finish_reason is length.
- Must be a positive integer no larger than the model’s
max_output_tokens(see Models). Larger values return400 max_tokens_too_largeinstead of being clipped. - Reasoning tokens count against it when reasoning is on.
- It caps the reply only. Input size is limited separately by the model’s context window.
max_completion_tokensis accepted as an alias. Sending both with different values returns400 conflicting_parameters.
System instructions
Put instructions in one system message at the start of messages. On the Messages endpoint use the top-level system field instead.
Syntic places a short identity instruction ahead of your text. Your instructions follow it unchanged and take priority for everything the identity instruction does not cover. A second system message later in the conversation is treated as a system note at that point, which is useful for switching mode mid-conversation.
stop
One string or a list of up to four. When the model produces any of them, generation ends before that string, and the string itself is not included in the reply.
| Rule | Value |
|---|---|
| Count | 1 to 4 strings |
| Length | 1 to 64 characters each |
| Matching | Exact and case-sensitive, across token boundaries |
| Messages endpoint name | stop_sequences (array only) |
When a stop string ends the reply, the response says which one:
{
"choices": [{
"index": 0,
"message": { "role": "assistant", "content": "Q1 revenue: 4.2M" },
"finish_reason": "stop_sequence",
"stop_sequence": "\n\n"
}]
}In a stream, the final chunk carries finish_reason: "stop_sequence" and stop_sequence. Text after the match is never sent, even in streaming mode, so a stop string can be relied on as a hard boundary.
user and metadata
user is a stable, opaque id for the person behind the request: a hashed account id, not an email address. Syntic uses it to trace abuse to one end user instead of blocking your whole key.
metadata holds your own tags. Syntic stores it with the usage record so you can filter usage reports by it.
| Key | Type | Notes |
|---|---|---|
end_user_id | string | Same meaning as user. If both are sent they must match. |
| any other key | string | Up to 16 keys, 64-character names, 512-character values. |
Do not put personal data such as names or email addresses in user or metadata. They are stored for as long as usage records are kept (see Data retention).
Neither field is sent to the model, and neither affects the reply.
Example
curl https://app.syntic.ai/v1/chat/completions \
-H "Authorization: Bearer $SYNTIC_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "Amara S1.2",
"stream": false,
"max_tokens": 200,
"stop": ["\n\n", "END"],
"user": "u_8f31c2",
"metadata": { "feature": "invoice-summary", "tenant": "acme" },
"messages": [
{ "role": "system", "content": "Summarise the invoice in one line. Write END when done." },
{ "role": "user", "content": "Invoice 4471: 12 x lavender 2L at 6.50, delivery 9.00." }
]
}'Errors
All errors use the unified envelope {error:{type, code, message, param}, request_id}.
| Status | code | param | Cause |
|---|---|---|---|
| 400 | max_tokens_too_large | max_tokens | Above the model’s output limit. |
| 400 | invalid_type | the field | Wrong JSON type, for example max_tokens: "200". |
| 400 | too_many_stop_sequences | stop | More than 4 strings. |
| 400 | invalid_stop_sequence | stop[i] | Empty or longer than 64 characters. |
| 400 | invalid_metadata | metadata.<key> | Too many keys, or a non-string or over-long value. |
| 400 | conflicting_parameters | the second field | max_tokens and max_completion_tokens disagree, or user and metadata.end_user_id differ. |
Build notes for the platform team
- Forward
stopincallUpstream(); if the upstream cannot stop on a string, cut the text server-side and still reportstop_sequence. - In streaming mode hold back up to 63 characters at the tail so a partial match is never sent.
- Store
userandmetadataon the usage row; indexmetadata.end_user_id.