{
  "openapi": "3.0.3",
  "info": {
    "title": "Infinity Custom Preset Web API Contract",
    "version": "1.1.0",
    "description": "Fixed request contract that a customer-hosted web API MUST implement to be used as an Infinity `custom` preset. The Infinity Preset Executor proxies each execution to the customer endpoint (the preset's RequestUrl) using this contract.\n\nThe REQUEST format is the fixed part of this contract. The RESPONSE is only a thin envelope (`output` / `error`, and `results` for batch); the field-level shape of your output is defined by your preset type's OutputSchema (JSON Schema), which the Preset Executor validates at runtime.\n\nBatch split/merge is OWNED BY YOUR SERVER: when the Preset Executor sends a batch (see `x-infinity-batch-request`), your endpoint MUST accept the whole batch, split/fan-out internally as needed, and return one order-preserving merged response with exactly one result per input item. Conformance to the batch contract is verified at preset registration time and enforced at runtime.\n\nThis document is published unauthenticated at https://schemas.infinity.com/presets/custom/v1/openapi.json (also available as https://schemas.infinity.com/presets/custom/latest/openapi.json).",
    "contact": {
      "name": "Infinity",
      "url": "https://schemas.infinity.com/presets/custom/v1/openapi.json"
    }
  },
  "servers": [
    {
      "url": "{customerEndpoint}",
      "description": "Customer-hosted endpoint from the preset RequestUrl.",
      "variables": {
        "customerEndpoint": {
          "default": "https://your-service.example.com/infinity/execute"
        }
      }
    }
  ],
  "tags": [
    {
      "name": "Custom Preset",
      "description": "The single execute operation a customer-hosted custom preset endpoint implements."
    }
  ],
  "paths": {
    "/": {
      "post": {
        "operationId": "executeCustomPreset",
        "tags": ["Custom Preset"],
        "summary": "Execute a custom preset for one Infinity input object, or a batch of them.",
        "description": "The Preset Executor POSTs either a single execution (`{ \"data\": { ... } }`) or, when `x-infinity-batch-request: true`, a batch (`{ \"batch\": [ { \"id\": \"...\", \"data\": { ... } }, ... ] }`). Your service returns the customer-authored output (single) or an order-preserving `{ \"results\": [ ... ] }` array (batch).",
        "parameters": [
          {
            "name": "api-key",
            "in": "header",
            "required": false,
            "schema": { "type": "string" },
            "description": "Customer API key. The header name is configurable per preset with AccessKeyHeaderName and defaults to api-key."
          },
          {
            "name": "x-infinity-account",
            "in": "header",
            "required": false,
            "schema": { "type": "string" },
            "description": "Infinity account name for the execution."
          },
          {
            "name": "x-infinity-preset",
            "in": "header",
            "required": false,
            "schema": { "type": "string" },
            "description": "Preset instance name being executed."
          },
          {
            "name": "x-infinity-batch-request",
            "in": "header",
            "required": false,
            "schema": { "type": "boolean", "default": false },
            "description": "When true, the request body is a BatchExecuteRequest and the response MUST be a BatchExecuteResponse. Your server owns splitting the batch internally and merging results back in the same order. When absent or false, the body is a single ExecuteRequest."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  { "$ref": "#/components/schemas/ExecuteRequest" },
                  { "$ref": "#/components/schemas/BatchExecuteRequest" }
                ]
              },
              "examples": {
                "single": {
                  "summary": "Single execution (x-infinity-batch-request absent/false)",
                  "value": {
                    "data": { "body": "Some content to process", "title": "Doc 1" }
                  }
                },
                "batch": {
                  "summary": "Batch execution (x-infinity-batch-request: true)",
                  "value": {
                    "batch": [
                      { "id": "0", "data": { "body": "First", "title": "Doc 1" } },
                      { "id": "1", "data": { "body": "Second", "title": "Doc 2" } }
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Customer-authored JSON. For a single request return either bare output fields or an object nested under `output`; for a batch request return `results` with exactly one entry per input item, in the same order. An error object signals failure of an item (or the whole request) even with HTTP 200.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    { "$ref": "#/components/schemas/ExecuteResponse" },
                    { "$ref": "#/components/schemas/BatchExecuteResponse" }
                  ]
                },
                "examples": {
                  "bareOutput": {
                    "summary": "Single: bare customer JSON",
                    "value": { "label": "positive", "score": 0.98 }
                  },
                  "nestedOutput": {
                    "summary": "Single: nested under output",
                    "value": { "output": { "label": "positive", "score": 0.98 } }
                  },
                  "error": {
                    "summary": "Single: error envelope",
                    "value": { "error": { "code": "bad_input", "message": "The body field is required." } }
                  },
                  "batch": {
                    "summary": "Batch: order-preserving results with a per-item error",
                    "value": {
                      "results": [
                        { "id": "0", "output": { "label": "positive", "score": 0.98 } },
                        { "id": "1", "error": { "code": "bad_input", "message": "The body field is required." } }
                      ]
                    }
                  }
                }
              }
            }
          },
          "4XX": {
            "description": "Client error. Non-2xx responses fail the preset execution (the whole batch, if batched).",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          },
          "5XX": {
            "description": "Server error. Non-2xx responses fail the preset execution (the whole batch, if batched).",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "ExecuteRequest": {
        "type": "object",
        "required": ["data"],
        "additionalProperties": false,
        "description": "A single execution. Sent when x-infinity-batch-request is absent or false.",
        "properties": {
          "data": {
            "type": "object",
            "additionalProperties": true,
            "description": "Bound Infinity input parameters for one execution."
          }
        }
      },
      "BatchExecuteRequest": {
        "type": "object",
        "required": ["batch"],
        "additionalProperties": false,
        "description": "A batch of executions. Sent when x-infinity-batch-request is true. Your server MUST split/process every item and return one BatchResult per input item, in the same order. The number of items never exceeds the maxBatchSize your preset declared at registration time.",
        "properties": {
          "batch": {
            "type": "array",
            "minItems": 1,
            "description": "Ordered list of input items. Order is significant and MUST be preserved in the response.",
            "items": { "$ref": "#/components/schemas/BatchItem" }
          }
        }
      },
      "BatchItem": {
        "type": "object",
        "required": ["id", "data"],
        "additionalProperties": false,
        "description": "One input item within a batch.",
        "properties": {
          "id": {
            "type": "string",
            "description": "Opaque per-item correlation id assigned by the Preset Executor. Echo it back on the matching result. Ids are unique within a batch."
          },
          "data": {
            "type": "object",
            "additionalProperties": true,
            "description": "Bound Infinity input parameters for this item (same shape as ExecuteRequest.data)."
          }
        }
      },
      "ExecuteResponse": {
        "description": "Response to a single ExecuteRequest.",
        "anyOf": [
          { "$ref": "#/components/schemas/OutputResponse" },
          { "$ref": "#/components/schemas/BareCustomerJson" },
          { "$ref": "#/components/schemas/ErrorResponse" }
        ]
      },
      "BatchExecuteResponse": {
        "type": "object",
        "required": ["results"],
        "additionalProperties": false,
        "description": "Response to a BatchExecuteRequest. MUST contain exactly one result per input item, in the same order as the request batch.",
        "properties": {
          "results": {
            "type": "array",
            "minItems": 1,
            "description": "Order-preserving results, one per input item.",
            "items": { "$ref": "#/components/schemas/BatchResult" }
          }
        }
      },
      "BatchResult": {
        "type": "object",
        "description": "One result within a batch response. Provide exactly one of output/bare-fields or error per item; an item-level error fails only that item, not the whole batch.",
        "properties": {
          "id": {
            "type": "string",
            "description": "The id echoed from the matching BatchItem. Recommended for robust correlation even though order is authoritative."
          },
          "output": {
            "type": "object",
            "additionalProperties": true,
            "description": "Customer result object for this item. Omit when error is present."
          },
          "error": { "$ref": "#/components/schemas/Error" }
        },
        "additionalProperties": true
      },
      "OutputResponse": {
        "type": "object",
        "required": ["output"],
        "properties": {
          "output": {
            "type": "object",
            "additionalProperties": true,
            "description": "Customer result object to return directly to Infinity."
          }
        },
        "additionalProperties": true
      },
      "BareCustomerJson": {
        "type": "object",
        "description": "Customer result object. The Preset Executor wraps this shape under output before returning to Infinity.",
        "additionalProperties": true
      },
      "Error": {
        "type": "object",
        "required": ["code", "message"],
        "additionalProperties": true,
        "properties": {
          "code": { "type": "string" },
          "message": { "type": "string" }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "required": ["error"],
        "additionalProperties": false,
        "properties": {
          "error": { "$ref": "#/components/schemas/Error" }
        }
      }
    }
  }
}
