> 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 Classifier

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

Create a classifier from labeled examples. It returns at once with `status`
`building` and builds in the background, usually within a minute; poll it until
`status` is `ready`. It needs 3 examples on each side of 0.5. Use it by setting a
routing policy's `complexity_classifier_id` to its `id`.

Reference: https://docs.merge.dev/merge-gateway/management-api/routing-policies/create-routing-classifier

## Authentication

- `Authorization` header (bearer token, required) — A management key (`mgmt_...`), sent as `Authorization: Bearer <key>`. Reading /v1/routing-policies also accepts the organization's gateway API keys; writing there needs a management key.

## Request

### Body (application/json)

This endpoint expects a ClassifierV1Create.

- `examples` (list of ClassifierExampleV1, required) — Labeled prompts: what your requests look like and how complex each one is, from 0 (simple) to 1 (complex). Scores further from 0.5 count more. The classifier is ready once at least 3 are below 0.5 and 3 are at or above it.
- `name` (string, required) — Unique within the organization.
- `description` (string, optional, nullable) — What the classifier is for.

## Response

### 201

The created classifier

- `build_error` (string, required, nullable) — Why the last build failed, when `status` is `failed`.
- `created_at` (datetime, required)
- `description` (string, required, nullable) — What the classifier is for.
- `examples` (list of ClassifierExampleV1, required) — Labeled prompts: what your requests look like and how complex each one is, from 0 (simple) to 1 (complex). Scores further from 0.5 count more. The classifier is ready once at least 3 are below 0.5 and 3 are at or above it.
- `has_readout` (boolean, required) — Whether routers that score with the difficulty readout use it too. Classifiers saved before readouts get one when their examples are next updated.
- `id` (string, required) — Send as a routing policy's `complexity_classifier_id` to use it.
- `is_ready` (boolean, required) — Whether it has a build that scores requests (also true while a rebuild runs). A policy using a classifier that isn't ready scores with the built-in scorer.
- `name` (string, required) — Unique within the organization.
- `quality_report` (ClassifierQualityV1, required, nullable) — null until the classifier is ready.
- `status` (enum, required) — `building` while the classifier builds in the background after a save (a few seconds to a minute), then `ready`, or `not_enough_examples` when either side of 0.5 has fewer than 3 examples, or `failed`. While a rebuild runs, policies keep using the previous build.
  - Allowed values: `building`, `ready`, `not_enough_examples`, `failed`
- `updated_at` (datetime, required)

## Errors

### 401 Unauthorized Error

The key is missing or invalid.

- `detail` (ErrorResponseDetail, required) — A message, or an object with a `code` to branch on and a `message`.

### 403 Forbidden Error

The key lacks the scope this route needs, or the change is not allowed.

- `detail` (ErrorResponseDetail, required) — A message, or an object with a `code` to branch on and a `message`.

### 409 Conflict Error

The request conflicts with the current state.

- `detail` (ErrorResponseDetail, required) — A message, or an object with a `code` to branch on and a `message`.

### 422 Unprocessable Entity Error

Validation Error

- `detail` (list of ValidationError, optional)

## Types

### ClassifierExampleV1

A labeled prompt.

- `complexity` (double, required) — How complex it is: 0 is simple, 1 is complex.
- `prompt` (string, required) — A prompt like the ones you send.

### ClassifierQualityV1

How well the classifier separates its own examples, measured when it was built. Each example is scored by the classifier rebuilt without it, so accuracy reflects prompts it hasn't seen. The built-in scorer's results on the same examples are the baseline.

- `accuracy` (double, required) — Share of examples scored on the right side of 0.5, from 0 to 1.
- `auc` (double, required, nullable) — Chance a complex example outscores a simple one, from 0 to 1.
- `examples` (integer, required) — Examples measured.
- `flagged_examples` (list of FlaggedExampleV1, required) — Up to 10 examples scored on the wrong side of their label: mislabeled, or unlike the rest of their side.
- `generic_accuracy` (double, required, nullable) — `accuracy` of the built-in scorer on the same examples.
- `generic_auc` (double, required, nullable) — `auc` of the built-in scorer on the same examples.
- `one_sided_terms` (OneSidedTermsV1, required) — Terms only one side uses.
- `warnings` (list of string, required) — What to change, if anything.

### ErrorResponseDetail

A message, or an object with a `code` to branch on and a `message`.

- string
- ErrorDetail: ErrorDetail

### ValidationError

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

### FlaggedExampleV1

- `complexity` (double, required) — The example's label.
- `index` (integer, required) — The example's position in `examples`, from 0.
- `prompt` (string, required) — The example's prompt, cut to 200 characters.
- `score` (double, required) — Its score from the classifier rebuilt without it.

### OneSidedTermsV1

- `complex` (list of string, required) — Terms only complex examples use. A simple request that mentions one may be scored complex; add simple examples that use them.
- `simple` (list of string, required) — Terms only simple examples use. A complex request that mentions one may be scored simple; add complex examples that use them.

### ErrorDetail

A structured error. Some carry extra fields, like `count`.

- `code` (string, required) — A stable code to branch on, like `payment_method_required`.
- `message` (string, required) — A human-readable explanation.

### ValidationErrorLocItems

- string
- integer

### ValidationErrorCtx

## Examples

**Request**

```json
{
  "examples": [
    {
      "complexity": 0.05,
      "prompt": "What was our ARR at the end of Q3?"
    },
    {
      "complexity": 0.1,
      "prompt": "Who owns the intercompany elimination entries this quarter?"
    },
    {
      "complexity": 0.05,
      "prompt": "Send me the link to the FY26 opex budget."
    },
    {
      "complexity": 0.95,
      "prompt": "Reconcile Q3 deferred revenue against the billing schedules and explain every variance over $5k."
    },
    {
      "complexity": 0.9,
      "prompt": "Build the ARR bridge from Q2 to Q3 and tie it back to the GAAP revenue waterfall."
    },
    {
      "complexity": 0.95,
      "prompt": "Walk through the ASC 606 treatment of a 3-year ramp deal with a free first quarter."
    }
  ],
  "name": "Finance requests",
  "description": "What counts as complex for the finance team."
}
```

**Response**

```json
{
  "build_error": null,
  "created_at": "2026-06-02T17:04:00Z",
  "description": "What counts as complex for the finance team.",
  "examples": [
    {
      "complexity": 0.05,
      "prompt": "What was our ARR at the end of Q3?"
    },
    {
      "complexity": 0.1,
      "prompt": "Who owns the intercompany elimination entries this quarter?"
    },
    {
      "complexity": 0.05,
      "prompt": "Send me the link to the FY26 opex budget."
    },
    {
      "complexity": 0.95,
      "prompt": "Reconcile Q3 deferred revenue against the billing schedules and explain every variance over $5k."
    },
    {
      "complexity": 0.9,
      "prompt": "Build the ARR bridge from Q2 to Q3 and tie it back to the GAAP revenue waterfall."
    },
    {
      "complexity": 0.95,
      "prompt": "Walk through the ASC 606 treatment of a 3-year ramp deal with a free first quarter."
    }
  ],
  "has_readout": true,
  "id": "5d7f9b1c-3e5a-4c7e-9a1b-6c8e0a2c4e69",
  "is_ready": true,
  "name": "Finance requests",
  "quality_report": {
    "accuracy": 1,
    "auc": 1,
    "examples": 6,
    "flagged_examples": [],
    "generic_accuracy": 0.83,
    "generic_auc": 0.89,
    "one_sided_terms": {
      "complex": [
        "revenue"
      ],
      "simple": []
    },
    "warnings": [
      "Add more examples: 10 or more on each side give steadier scores"
    ]
  },
  "status": "ready",
  "updated_at": "2026-09-14T09:30:00Z"
}
```

**SDK Code**

```python
import requests

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

payload = {
    "examples": [
        {
            "complexity": 0.05,
            "prompt": "What was our ARR at the end of Q3?"
        },
        {
            "complexity": 0.1,
            "prompt": "Who owns the intercompany elimination entries this quarter?"
        },
        {
            "complexity": 0.05,
            "prompt": "Send me the link to the FY26 opex budget."
        },
        {
            "complexity": 0.95,
            "prompt": "Reconcile Q3 deferred revenue against the billing schedules and explain every variance over $5k."
        },
        {
            "complexity": 0.9,
            "prompt": "Build the ARR bridge from Q2 to Q3 and tie it back to the GAAP revenue waterfall."
        },
        {
            "complexity": 0.95,
            "prompt": "Walk through the ASC 606 treatment of a 3-year ramp deal with a free first quarter."
        }
    ],
    "name": "Finance requests",
    "description": "What counts as complex for the finance team."
}
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/classifiers';
const options = {
  method: 'POST',
  headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
  body: '{"examples":[{"complexity":0.05,"prompt":"What was our ARR at the end of Q3?"},{"complexity":0.1,"prompt":"Who owns the intercompany elimination entries this quarter?"},{"complexity":0.05,"prompt":"Send me the link to the FY26 opex budget."},{"complexity":0.95,"prompt":"Reconcile Q3 deferred revenue against the billing schedules and explain every variance over $5k."},{"complexity":0.9,"prompt":"Build the ARR bridge from Q2 to Q3 and tie it back to the GAAP revenue waterfall."},{"complexity":0.95,"prompt":"Walk through the ASC 606 treatment of a 3-year ramp deal with a free first quarter."}],"name":"Finance requests","description":"What counts as complex for the finance team."}'
};

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/classifiers"

	payload := strings.NewReader("{\n  \"examples\": [\n    {\n      \"complexity\": 0.05,\n      \"prompt\": \"What was our ARR at the end of Q3?\"\n    },\n    {\n      \"complexity\": 0.1,\n      \"prompt\": \"Who owns the intercompany elimination entries this quarter?\"\n    },\n    {\n      \"complexity\": 0.05,\n      \"prompt\": \"Send me the link to the FY26 opex budget.\"\n    },\n    {\n      \"complexity\": 0.95,\n      \"prompt\": \"Reconcile Q3 deferred revenue against the billing schedules and explain every variance over $5k.\"\n    },\n    {\n      \"complexity\": 0.9,\n      \"prompt\": \"Build the ARR bridge from Q2 to Q3 and tie it back to the GAAP revenue waterfall.\"\n    },\n    {\n      \"complexity\": 0.95,\n      \"prompt\": \"Walk through the ASC 606 treatment of a 3-year ramp deal with a free first quarter.\"\n    }\n  ],\n  \"name\": \"Finance requests\",\n  \"description\": \"What counts as complex for the finance team.\"\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/classifiers")

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  \"examples\": [\n    {\n      \"complexity\": 0.05,\n      \"prompt\": \"What was our ARR at the end of Q3?\"\n    },\n    {\n      \"complexity\": 0.1,\n      \"prompt\": \"Who owns the intercompany elimination entries this quarter?\"\n    },\n    {\n      \"complexity\": 0.05,\n      \"prompt\": \"Send me the link to the FY26 opex budget.\"\n    },\n    {\n      \"complexity\": 0.95,\n      \"prompt\": \"Reconcile Q3 deferred revenue against the billing schedules and explain every variance over $5k.\"\n    },\n    {\n      \"complexity\": 0.9,\n      \"prompt\": \"Build the ARR bridge from Q2 to Q3 and tie it back to the GAAP revenue waterfall.\"\n    },\n    {\n      \"complexity\": 0.95,\n      \"prompt\": \"Walk through the ASC 606 treatment of a 3-year ramp deal with a free first quarter.\"\n    }\n  ],\n  \"name\": \"Finance requests\",\n  \"description\": \"What counts as complex for the finance team.\"\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/classifiers")
  .header("Authorization", "Bearer <token>")
  .header("Content-Type", "application/json")
  .body("{\n  \"examples\": [\n    {\n      \"complexity\": 0.05,\n      \"prompt\": \"What was our ARR at the end of Q3?\"\n    },\n    {\n      \"complexity\": 0.1,\n      \"prompt\": \"Who owns the intercompany elimination entries this quarter?\"\n    },\n    {\n      \"complexity\": 0.05,\n      \"prompt\": \"Send me the link to the FY26 opex budget.\"\n    },\n    {\n      \"complexity\": 0.95,\n      \"prompt\": \"Reconcile Q3 deferred revenue against the billing schedules and explain every variance over $5k.\"\n    },\n    {\n      \"complexity\": 0.9,\n      \"prompt\": \"Build the ARR bridge from Q2 to Q3 and tie it back to the GAAP revenue waterfall.\"\n    },\n    {\n      \"complexity\": 0.95,\n      \"prompt\": \"Walk through the ASC 606 treatment of a 3-year ramp deal with a free first quarter.\"\n    }\n  ],\n  \"name\": \"Finance requests\",\n  \"description\": \"What counts as complex for the finance team.\"\n}")
  .asString();
```

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

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api-gateway.merge.dev/v1/classifiers', [
  'body' => '{
  "examples": [
    {
      "complexity": 0.05,
      "prompt": "What was our ARR at the end of Q3?"
    },
    {
      "complexity": 0.1,
      "prompt": "Who owns the intercompany elimination entries this quarter?"
    },
    {
      "complexity": 0.05,
      "prompt": "Send me the link to the FY26 opex budget."
    },
    {
      "complexity": 0.95,
      "prompt": "Reconcile Q3 deferred revenue against the billing schedules and explain every variance over $5k."
    },
    {
      "complexity": 0.9,
      "prompt": "Build the ARR bridge from Q2 to Q3 and tie it back to the GAAP revenue waterfall."
    },
    {
      "complexity": 0.95,
      "prompt": "Walk through the ASC 606 treatment of a 3-year ramp deal with a free first quarter."
    }
  ],
  "name": "Finance requests",
  "description": "What counts as complex for the finance team."
}',
  'headers' => [
    'Authorization' => 'Bearer <token>',
    'Content-Type' => 'application/json',
  ],
]);

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

```csharp
using RestSharp;

var client = new RestClient("https://api-gateway.merge.dev/v1/classifiers");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer <token>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"examples\": [\n    {\n      \"complexity\": 0.05,\n      \"prompt\": \"What was our ARR at the end of Q3?\"\n    },\n    {\n      \"complexity\": 0.1,\n      \"prompt\": \"Who owns the intercompany elimination entries this quarter?\"\n    },\n    {\n      \"complexity\": 0.05,\n      \"prompt\": \"Send me the link to the FY26 opex budget.\"\n    },\n    {\n      \"complexity\": 0.95,\n      \"prompt\": \"Reconcile Q3 deferred revenue against the billing schedules and explain every variance over $5k.\"\n    },\n    {\n      \"complexity\": 0.9,\n      \"prompt\": \"Build the ARR bridge from Q2 to Q3 and tie it back to the GAAP revenue waterfall.\"\n    },\n    {\n      \"complexity\": 0.95,\n      \"prompt\": \"Walk through the ASC 606 treatment of a 3-year ramp deal with a free first quarter.\"\n    }\n  ],\n  \"name\": \"Finance requests\",\n  \"description\": \"What counts as complex for the finance team.\"\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift
import Foundation

let headers = [
  "Authorization": "Bearer <token>",
  "Content-Type": "application/json"
]
let parameters = [
  "examples": [
    [
      "complexity": 0.05,
      "prompt": "What was our ARR at the end of Q3?"
    ],
    [
      "complexity": 0.1,
      "prompt": "Who owns the intercompany elimination entries this quarter?"
    ],
    [
      "complexity": 0.05,
      "prompt": "Send me the link to the FY26 opex budget."
    ],
    [
      "complexity": 0.95,
      "prompt": "Reconcile Q3 deferred revenue against the billing schedules and explain every variance over $5k."
    ],
    [
      "complexity": 0.9,
      "prompt": "Build the ARR bridge from Q2 to Q3 and tie it back to the GAAP revenue waterfall."
    ],
    [
      "complexity": 0.95,
      "prompt": "Walk through the ASC 606 treatment of a 3-year ramp deal with a free first quarter."
    ]
  ],
  "name": "Finance requests",
  "description": "What counts as complex for the finance team."
] as [String : Any]

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

let request = NSMutableURLRequest(url: NSURL(string: "https://api-gateway.merge.dev/v1/classifiers")! 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()
```