> ## Documentation Index
> Fetch the complete documentation index at: https://docs.usenexio.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Headless Engine Setup

> Create and configure an engine entirely via API, validate its config, and submit your first run.

This guide walks through the full engine lifecycle using only the API: no
dashboard required. For request/response schemas, see the
[Engine Management](/api-reference/engines/list-engines) API reference.

## Flow

```mermaid theme={null}
flowchart LR
  A["Create engine"] --> B["Build config"]
  B --> C["Validate"]
  C --> D["Save config"]
  D --> E["Copy contract for agents"]
  E --> F["Submit run"]
  F --> G["Poll results"]
```

## Step 1: Create an engine

Choose an `engine_type` based on your use case: `placement` for ranking provider
offerings into optimal solutions, or `entity_analysis` for gap analysis and recommendations.

<CodeGroup>
  ```bash curl theme={null}
  curl -X POST https://api.usenexio.com/api/v1/engines \
    -H "Authorization: Bearer $NEXIO_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "slug": "my-engine",
      "label": "Product Comparison Engine",
      "description": "Rank offerings from multiple providers.",
      "engine_type": "placement"
    }'
  ```

  ```python Python theme={null}
  import httpx

  resp = httpx.post(
      "https://api.usenexio.com/api/v1/engines",
      headers={"Authorization": f"Bearer {api_key}"},
      json={
          "slug": "my-engine",
          "label": "Product Comparison Engine",
          "description": "Rank offerings from multiple providers.",
          "engine_type": "placement",
      },
  )
  engine = resp.json()
  print(engine["slug"])  # my-engine
  ```

  ```typescript TypeScript theme={null}
  const resp = await fetch("https://api.usenexio.com/api/v1/engines", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${apiKey}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      slug: "my-engine",
      label: "Product Comparison Engine",
      description: "Rank offerings from multiple providers.",
      engine_type: "placement",
    }),
  })
  const engine = await resp.json()
  console.log(engine.slug) // my-engine
  ```
</CodeGroup>

The engine is created with a default configuration and `active` status. The slug
is used in all subsequent endpoint URLs.

## Step 2: Build your config

The config structure depends on `engine_type`. Retrieve the current config to
use the `preset` template as a starting point:

<CodeGroup>
  ```bash curl theme={null}
  # Get the current config (includes preset template)
  curl https://api.usenexio.com/api/v1/engines/my-engine/config \
    -H "Authorization: Bearer $NEXIO_API_KEY"
  ```

  ```python Python theme={null}
  current = httpx.get(
      "https://api.usenexio.com/api/v1/engines/my-engine/config",
      headers={"Authorization": f"Bearer {api_key}"},
  ).json()

  # Use the preset as a starting point
  config = current["preset"]
  config["scoring_dimensions"] = [
      {"key": "completeness", "label": "Completeness", "method": "deterministic", "enabled": True},
      {"key": "pricing", "label": "Pricing", "method": "deterministic", "enabled": True},
      {"key": "quality", "label": "Quality", "method": "deterministic", "enabled": True},
  ]
  config["appetite_weight_profiles"] = [
      {"bucket": "balanced", "label": "Balanced", "weights": {"completeness": 0.34, "pricing": 0.33, "quality": 0.33}},
  ]
  config["default_appetite_bucket"] = "balanced"
  ```

  ```typescript TypeScript theme={null}
  const currentResp = await fetch(
    "https://api.usenexio.com/api/v1/engines/my-engine/config",
    { headers: { Authorization: `Bearer ${apiKey}` } },
  )
  const current = await currentResp.json()

  const config = {
    ...current.preset,
    scoring_dimensions: [
      { key: "completeness", label: "Completeness", method: "deterministic", enabled: true },
      { key: "pricing", label: "Pricing", method: "deterministic", enabled: true },
      { key: "quality", label: "Quality", method: "deterministic", enabled: true },
    ],
    appetite_weight_profiles: [
      { bucket: "balanced", label: "Balanced", weights: { completeness: 0.34, pricing: 0.33, quality: 0.33 } },
    ],
    default_appetite_bucket: "balanced",
  }
  ```
</CodeGroup>

<Note>
  The `preset` field in the config response provides the default template for your
  engine type. Use it as a starting point and modify the fields you need. The preset
  includes a `pack_key` that identifies the domain pack: available packs depend on
  your account configuration.
</Note>

## Step 3: Validate the configuration

Before saving, dry-run your config through validation. The validate endpoint
always returns `200 OK`: check the `valid` field:

<CodeGroup>
  ```bash curl theme={null}
  curl -X POST https://api.usenexio.com/api/v1/engines/my-engine/config/validate \
    -H "Authorization: Bearer $NEXIO_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "config": {
        "schema_version": 1,
        "pack_key": "insurance-personal-lines",
        "pack_version": 1,
        "scoring_dimensions": [
          { "key": "completeness", "label": "Completeness", "method": "deterministic", "enabled": true },
          { "key": "pricing", "label": "Pricing", "method": "deterministic", "enabled": true },
          { "key": "quality", "label": "Quality", "method": "deterministic", "enabled": true }
        ],
        "appetite_weight_profiles": [
          {
            "bucket": "balanced",
            "label": "Balanced",
            "weights": { "completeness": 0.34, "pricing": 0.33, "quality": 0.33 }
          }
        ],
        "default_appetite_bucket": "balanced"
      }
    }'
  ```

  ```python Python theme={null}
  resp = httpx.post(
      "https://api.usenexio.com/api/v1/engines/my-engine/config/validate",
      headers={"Authorization": f"Bearer {api_key}"},
      json={"config": config},
  )
  result = resp.json()
  if result["valid"]:
      print("Config is valid")
  else:
      for err in result["errors"]:
          print(f"  {err['path']}: {err['message']}")
  ```

  ```typescript TypeScript theme={null}
  const resp = await fetch(
    "https://api.usenexio.com/api/v1/engines/my-engine/config/validate",
    {
      method: "POST",
      headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" },
      body: JSON.stringify({ config }),
    },
  )
  const result = await resp.json()
  if (result.valid) {
    console.log("Config is valid")
  } else {
    result.errors.forEach((e: { path: string; message: string }) =>
      console.log(`  ${e.path}: ${e.message}`),
    )
  }
  ```
</CodeGroup>

A valid response:

```json theme={null}
{ "valid": true, "errors": [] }
```

An invalid response:

```json theme={null}
{
  "valid": false,
  "errors": [
    { "path": "scoring_dimensions", "message": "at least one scoring dimension is required" }
  ]
}
```

## Step 4: Save the configuration

Once validation passes, save the config with a full replacement PUT:

<CodeGroup>
  ```bash curl theme={null}
  curl -X PUT https://api.usenexio.com/api/v1/engines/my-engine/config \
    -H "Authorization: Bearer $NEXIO_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "config": {
        "schema_version": 1,
        "pack_key": "insurance-personal-lines",
        "pack_version": 1,
        "scoring_dimensions": [
          { "key": "completeness", "label": "Completeness", "method": "deterministic", "enabled": true },
          { "key": "pricing", "label": "Pricing", "method": "deterministic", "enabled": true },
          { "key": "quality", "label": "Quality", "method": "deterministic", "enabled": true }
        ],
        "appetite_weight_profiles": [
          {
            "bucket": "balanced",
            "label": "Balanced",
            "weights": { "completeness": 0.34, "pricing": 0.33, "quality": 0.33 }
          }
        ],
        "default_appetite_bucket": "balanced"
      }
    }'
  ```

  ```python Python theme={null}
  resp = httpx.put(
      "https://api.usenexio.com/api/v1/engines/my-engine/config",
      headers={"Authorization": f"Bearer {api_key}"},
      json={"config": config},
  )
  ```

  ```typescript TypeScript theme={null}
  await fetch("https://api.usenexio.com/api/v1/engines/my-engine/config", {
    method: "PUT",
    headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" },
    body: JSON.stringify({ config }),
  })
  ```
</CodeGroup>

## Step 5: Copy the integration contract

Open your engine's **Contract** page on
[platform.usenexio.com](https://platform.usenexio.com) and click
**Copy for agents**. You get a single Markdown document with the typed request
schema, scoring dimensions, weight profiles, an example request/response payload,
and polling instructions: everything a downstream consumer or AI coding agent
needs to build a correct integration. Paste it into the agent's context and let
it generate the client.

The Contract page is regenerated from your engine's saved config, so the document
always matches what the API expects on the next run.

## Step 6: Submit a run

With the engine configured, submit runs using the engine slug:

```
POST /api/v1/engines/my-engine/runs
```

See the [Integration Guide](/guides/integration) for the full submission flow,
including how to structure offerings, poll for results, and handle failures.

## Managing engines

After initial setup, use these endpoints to manage your engines:

| Task                          | Endpoint                                                                                           |
| ----------------------------- | -------------------------------------------------------------------------------------------------- |
| List all engines              | [GET /api/v1/engines](/api-reference/engines/list-engines)                                         |
| View engine details           | [GET /api/v1/engines/{slug}](/api-reference/engines/get-engine)                                    |
| Rename or update description  | [PATCH /api/v1/engines/{slug}](/api-reference/engines/update-engine)                               |
| Archive an engine             | [PATCH /api/v1/engines/{slug}](/api-reference/engines/update-engine) with `{"status": "archived"}` |
| Reactivate an archived engine | [PATCH /api/v1/engines/{slug}](/api-reference/engines/update-engine) with `{"status": "active"}`   |

<Warning>
  Archiving an engine prevents config updates but does not affect in-flight runs
  or the ability to submit new runs. Reactivate the engine to resume config
  changes.
</Warning>
