> This page is for Gateway.

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.merge.dev/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.merge.dev/_mcp/server.

# Create a chat completion

POST https://api-gateway.merge.dev/v1/chat/completions
Content-Type: application/json

OpenAI-compatible chat completions endpoint. Accepts the OpenAI chat completions request shape and routes to any catalogued model.

Also served at `/v1/openai/chat/completions`; both paths accept the same requests. This bare path matches the OpenAI SDK's default base URL shape, so pointing the SDK at `https://api-gateway.merge.dev/v1` works with no other changes.

Reference: https://docs.merge.dev/merge-gateway/api-overview/chat-completions/create

## Authentication

- `Authorization` header (bearer token, required) — Your production key sent as a bearer token.

## Request

### Body (application/json)

This endpoint expects an OpenAIChatCompletionRequest.

- `model` (string, required)
- `messages` (list of OpenAIChatMessage, required)
- `temperature` (double, optional, nullable)
- `top_p` (double, optional, nullable)
- `n` (integer, optional, nullable)
- `stream` (boolean, optional, default: false)
- `stop` (OpenAiChatCompletionRequestStop, optional, nullable)
- `max_tokens` (integer, optional, nullable)
- `max_completion_tokens` (integer, optional, nullable)
- `presence_penalty` (double, optional, nullable)
- `frequency_penalty` (double, optional, nullable)
- `logit_bias` (map from string to double, optional, nullable)
- `user` (string, optional, nullable)
- `tools` (list of OpenAITool, optional, nullable)
- `tool_choice` (OpenAiChatCompletionRequestToolChoice, optional, nullable)
- `response_format` (OpenAIResponseFormat, optional, nullable) — OpenAI response format.
- `seed` (integer, optional, nullable)
- `stream_options` (map from string to any, optional, nullable)
- `service_tier` (enum, optional, nullable) — Processing tier. 'flex' = discounted best-effort (slower, may be throttled); 'priority' = premium low-latency (not currently priced on any route, so it fails closed). Omit or 'standard' for normal processing. Allowed only on routes that price the requested tier, otherwise the request fails closed with 400.
  - Allowed values: `standard`, `flex`, `priority`
- `service_tier_fallback` (boolean, optional, default: false) — If the provider throttles the requested tier (429/503), retry once at the standard tier, billed at standard rates. The response service_tier shows the tier that actually served.
- `logprobs` (boolean, optional, nullable) — Return log probabilities of the output tokens.
- `top_logprobs` (integer, optional, nullable) — Number of most likely tokens to return per position; requires `logprobs`.
- `thinking` (map from string to any, optional, nullable) — Extended thinking settings for models that support it.
- `tags` (list of TagInput, optional, nullable) — Key-value tags to attach to this request.
- `project_id` (string, optional, nullable) — Project ID (UUID) to attribute this request to.
- `customer` (string, optional, nullable) — Customer ID (UUID) to scope this request to, applying that customer's routing policy, provider keys, budget, and usage attribution.
- `routing_policy_id` (string, optional, nullable) — Routing policy ID for this request: an org-level policy, or a project or customer policy when the request carries that scope.
- `priority_order` (list of OpenAiChatCompletionRequestPriorityOrderItems, optional, nullable) — Ordered list of models to try, first success wins, with the same rules as `priority_order` on `POST /v1/responses`.
- `vendor` (string, optional, nullable) — Restrict routing to one vendor (hosting platform).
- `vendors` (list of string, optional, nullable) — Ordered list of acceptable vendors; the first available one wins.
- `provider_options` (map from string to any, optional, nullable) — Provider-specific options, keyed by provider family.
- `prompt_cache_key` (string, optional, nullable) — Prompt-cache routing hint forwarded to providers that cache automatically.
- `include_routing_metadata` (boolean, optional, default: false) — Return routing metadata for this request.
- `include_guardrails_metadata` (boolean, optional, default: false) — Return prompt-injection and DLP results in a top-level `guardrails` object.

## Response

### 200

Successful Response

- `any`

## Errors

### 422 Unprocessable Entity Error

Validation Error

- `detail` (list of ValidationError, optional)

## Types

### OpenAIChatMessage

OpenAI chat message format.

- `role` (enum, required)
  - Allowed values: `system`, `user`, `assistant`, `tool`, `developer`
- `content` (OpenAiChatMessageContent, optional, nullable)
- `name` (string, optional, nullable)
- `tool_calls` (list of map from string to any, optional, nullable)
- `tool_call_id` (string, optional, nullable)
- `thinking` (string, optional, nullable) — Reasoning text from a previous assistant turn, replayed to models that need it.
- `thinking_signature` (string, optional, nullable) — Signature for the replayed `thinking` text.
- `cache_control` (map from string to any, optional, nullable) — Marks a prompt-caching breakpoint at this block for providers that support it.

### OpenAiChatCompletionRequestStop

### OpenAITool

OpenAI tool definition.

- `function` (OpenAIFunctionDef, required) — OpenAI function definition within a tool.
- `type` ("function", optional, default: function)

### OpenAiChatCompletionRequestToolChoice

### OpenAIResponseFormat

OpenAI response format.

- `type` (string, optional, default: text) — One of 'text', 'json_object', or 'json_schema'.
- `json_schema` (JsonSchemaSpec, optional, nullable) — Required when type is 'json_schema'.

### TagInput

Tag key-value pair for use in requests.

- `key` (string, required) — Tag key
- `value` (string, required) — Tag value

### OpenAiChatCompletionRequestPriorityOrderItems

### ValidationError

Single field-level validation error. `loc` is the JSON path to the offending field, `msg` is a human-readable explanation, and `type` is a stable machine-readable error code.

- `loc` (list of ValidationErrorLocItems, required)
- `msg` (string, required)
- `type` (string, required)
- `input` (any, optional)
- `ctx` (ValidationErrorCtx, optional)

### OpenAiChatMessageContent

### OpenAIFunctionDef

OpenAI function definition within a tool.

- `name` (string, required)
- `description` (string, optional, default: )
- `parameters` (map from string to any, optional)

### JsonSchemaSpec

The `json_schema` wrapper for structured output; omit `strict` to keep the provider's default, and unknown wrapper keys pass through to the provider.

- `schema` (map from string to any, required)
- `name` (string, optional, default: response)
- `description` (string, optional, nullable)
- `strict` (boolean, optional, nullable)

### PriorityOrderEntry

One entry of `priority_order`: a model, optionally pinned to vendors.

- `model` (string, required) — Model id, `provider/model` or a bare base name that resolves the same way `model` does.
- `priority` (integer, optional, nullable) — Lower tries first, as in the routing policies API's PRIORITY shape. Omit to use list order; explicit values sort ahead of list order.
- `vendors` (list of string, optional, nullable) — Pin this entry to these execution hosts, in order of preference. Omit to allow every vendor that serves the model. Must not be empty when sent.

### ValidationErrorLocItems

### ValidationErrorCtx

## Examples

**Request**

```json
{
  "model": "openai/gpt-5.1",
  "messages": [
    {
      "role": "user",
      "content": "What is the capital of France?"
    }
  ]
}
```

**Response**

```json
{
  "choices": [
    {
      "finish_reason": "stop",
      "index": 0,
      "message": {
        "content": "The capital of France is Paris.",
        "role": "assistant"
      }
    }
  ],
  "created": 1774137600,
  "id": "chatcmpl-cc_a1b2c3d4e5f6",
  "model": "openai/gpt-5.1",
  "object": "chat.completion",
  "usage": {
    "completion_tokens": 8,
    "prompt_tokens": 14,
    "total_tokens": 22
  }
}
```

**SDK Code**

```python
import requests

url = "https://api-gateway.merge.dev/v1/chat/completions"

payload = {
    "model": "openai/gpt-5.1",
    "messages": [
        {
            "role": "user",
            "content": "What is the capital of France?"
        }
    ]
}
headers = {
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

```javascript
const url = 'https://api-gateway.merge.dev/v1/chat/completions';
const options = {
  method: 'POST',
  headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
  body: '{"model":"openai/gpt-5.1","messages":[{"role":"user","content":"What is the capital of France?"}]}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://api-gateway.merge.dev/v1/chat/completions"

	payload := strings.NewReader("{\n  \"model\": \"openai/gpt-5.1\",\n  \"messages\": [\n    {\n      \"role\": \"user\",\n      \"content\": \"What is the capital of France?\"\n    }\n  ]\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("Authorization", "Bearer <token>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby
require 'uri'
require 'net/http'

url = URI("https://api-gateway.merge.dev/v1/chat/completions")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"model\": \"openai/gpt-5.1\",\n  \"messages\": [\n    {\n      \"role\": \"user\",\n      \"content\": \"What is the capital of France?\"\n    }\n  ]\n}"

response = http.request(request)
puts response.read_body
```

```java
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://api-gateway.merge.dev/v1/chat/completions")
  .header("Authorization", "Bearer <token>")
  .header("Content-Type", "application/json")
  .body("{\n  \"model\": \"openai/gpt-5.1\",\n  \"messages\": [\n    {\n      \"role\": \"user\",\n      \"content\": \"What is the capital of France?\"\n    }\n  ]\n}")
  .asString();
```

```php
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api-gateway.merge.dev/v1/chat/completions', [
  'body' => '{
  "model": "openai/gpt-5.1",
  "messages": [
    {
      "role": "user",
      "content": "What is the capital of France?"
    }
  ]
}',
  'headers' => [
    'Authorization' => 'Bearer <token>',
    'Content-Type' => 'application/json',
  ],
]);

echo $response->getBody();
```

```csharp
using RestSharp;

var client = new RestClient("https://api-gateway.merge.dev/v1/chat/completions");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer <token>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"model\": \"openai/gpt-5.1\",\n  \"messages\": [\n    {\n      \"role\": \"user\",\n      \"content\": \"What is the capital of France?\"\n    }\n  ]\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift
import Foundation

let headers = [
  "Authorization": "Bearer <token>",
  "Content-Type": "application/json"
]
let parameters = [
  "model": "openai/gpt-5.1",
  "messages": [
    [
      "role": "user",
      "content": "What is the capital of France?"
    ]
  ]
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://api-gateway.merge.dev/v1/chat/completions")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```