{
  "openapi": "3.1.0",
  "info": {
    "title": "InferTheta Agent API",
    "version": "1.0.0",
    "description": "Decision infrastructure for agents: create Bayesian networks, fill CPTs, set evidence, run inference, and return structured explanations for auditable reasoning under uncertainty.",
    "contact": {
      "name": "InferTheta"
    }
  },
  "servers": [
    {
      "url": "https://infertheta-agent-engine-production.up.railway.app",
      "description": "This deployment"
    }
  ],
  "tags": [
    {
      "name": "Discovery"
    },
    {
      "name": "Keys"
    },
    {
      "name": "Networks"
    },
    {
      "name": "Edit"
    },
    {
      "name": "Inference"
    },
    {
      "name": "Policy"
    }
  ],
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "API key issued by POST /v1/keys (prefix ith_…)"
      },
      "apiKeyAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key"
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean",
            "const": false
          },
          "error": {
            "type": "string"
          },
          "code": {
            "type": "string"
          }
        }
      },
      "NetworkMeta": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "tenantId": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "createdAt": {
            "type": "number"
          },
          "updatedAt": {
            "type": "number"
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "domain": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "GraphJson": {
        "type": "object",
        "description": "InferTheta export JSON (nodes, edges, CPTs, scenarios, agent policy).",
        "additionalProperties": true
      }
    }
  },
  "security": [
    {
      "bearerAuth": []
    },
    {
      "apiKeyAuth": []
    }
  ],
  "paths": {
    "/": {
      "get": {
        "tags": [
          "Discovery"
        ],
        "security": [],
        "summary": "Machine-readable entry + endpoint index",
        "responses": {
          "200": {
            "description": "API discovery document"
          }
        }
      }
    },
    "/health": {
      "get": {
        "tags": [
          "Discovery"
        ],
        "security": [],
        "summary": "Liveness",
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/openapi.json": {
      "get": {
        "tags": [
          "Discovery"
        ],
        "security": [],
        "summary": "OpenAPI 3.1 specification",
        "responses": {
          "200": {
            "description": "OpenAPI document"
          }
        }
      }
    },
    "/v1/pricing": {
      "get": {
        "tags": [
          "Keys"
        ],
        "security": [],
        "summary": "Pay-per-call pricing and credit packs",
        "responses": {
          "200": {
            "description": "Pricing"
          }
        }
      }
    },
    "/v1/sandbox": {
      "post": {
        "tags": [
          "Keys"
        ],
        "security": [],
        "summary": "Free sandbox API key + small credit balance (no Auth0)",
        "responses": {
          "201": {
            "description": "Sandbox key"
          }
        }
      }
    },
    "/v1/checkout": {
      "post": {
        "tags": [
          "Keys"
        ],
        "security": [],
        "summary": "Guest Stripe checkout for a credit pack (or topUp with existing key)",
        "responses": {
          "200": {
            "description": "checkoutUrl + sessionId"
          }
        }
      }
    },
    "/v1/checkout/{sessionId}": {
      "get": {
        "tags": [
          "Keys"
        ],
        "security": [],
        "summary": "Claim apiKey once after payment (JSON or HTML)",
        "parameters": [
          {
            "name": "sessionId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Claim result"
          }
        }
      }
    },
    "/v1/keys": {
      "post": {
        "tags": [
          "Keys"
        ],
        "security": [],
        "summary": "Create an API key (requires bootstrap secret when auth is on)",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "tenantId": {
                    "type": "string"
                  },
                  "bootstrapSecret": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Raw key returned once"
          },
          "403": {
            "description": "Bootstrap not allowed"
          }
        }
      }
    },
    "/v1/keys/me": {
      "get": {
        "tags": [
          "Keys"
        ],
        "summary": "Current key + tenant usage/quotas",
        "responses": {
          "200": {
            "description": "Key info"
          }
        }
      }
    },
    "/v1/policy": {
      "get": {
        "tags": [
          "Policy"
        ],
        "security": [],
        "summary": "Quotas and high-stakes domain rules",
        "responses": {
          "200": {
            "description": "Policy summary"
          }
        }
      }
    },
    "/v1/networks": {
      "get": {
        "tags": [
          "Networks"
        ],
        "summary": "List persisted networks for this tenant",
        "responses": {
          "200": {
            "description": "Network list"
          }
        }
      },
      "post": {
        "tags": [
          "Networks"
        ],
        "summary": "Create a network (empty or from export JSON)",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "title": {
                    "type": "string"
                  },
                  "json": {
                    "$ref": "#/components/schemas/GraphJson"
                  },
                  "tags": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "domain": {
                    "type": "string",
                    "description": "e.g. weather, healthcare — high-stakes domains need risk ack for CPT edits"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created"
          }
        }
      }
    },
    "/v1/networks/{networkId}": {
      "get": {
        "tags": [
          "Networks"
        ],
        "summary": "Get network metadata + full graph JSON",
        "parameters": [
          {
            "name": "networkId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Network"
          },
          "404": {
            "description": "Not found"
          }
        }
      },
      "put": {
        "tags": [
          "Networks"
        ],
        "summary": "Replace graph JSON (structure/CPT write)",
        "parameters": [
          {
            "name": "networkId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Updated"
          }
        }
      },
      "delete": {
        "tags": [
          "Networks"
        ],
        "summary": "Delete a persisted network",
        "parameters": [
          {
            "name": "networkId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted"
          }
        }
      }
    },
    "/v1/networks/{networkId}/build": {
      "post": {
        "tags": [
          "Edit"
        ],
        "summary": "Build/replace graph from nodes+edges+optional CPTs",
        "parameters": [
          {
            "name": "networkId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Built"
          }
        }
      }
    },
    "/v1/networks/{networkId}/nodes": {
      "post": {
        "tags": [
          "Edit"
        ],
        "summary": "Add a Bayes or decision node",
        "parameters": [
          {
            "name": "networkId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Added"
          }
        }
      }
    },
    "/v1/networks/{networkId}/edges": {
      "post": {
        "tags": [
          "Edit"
        ],
        "summary": "Connect parent → child",
        "parameters": [
          {
            "name": "networkId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Connected"
          }
        }
      }
    },
    "/v1/networks/{networkId}/cpt": {
      "post": {
        "tags": [
          "Edit"
        ],
        "summary": "Set a node CPT (rows = parent configs, cols = child states; rows sum to 1)",
        "parameters": [
          {
            "name": "networkId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "CPT set"
          },
          "403": {
            "description": "High-stakes ack required"
          }
        }
      }
    },
    "/v1/networks/{networkId}/evidence": {
      "post": {
        "tags": [
          "Inference"
        ],
        "summary": "Set or clear hard evidence for this network session",
        "parameters": [
          {
            "name": "networkId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Evidence updated"
          }
        }
      }
    },
    "/v1/networks/{networkId}/inference": {
      "post": {
        "tags": [
          "Inference"
        ],
        "summary": "Run inference → marginals + P(evidence)",
        "parameters": [
          {
            "name": "networkId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Posteriors"
          }
        }
      }
    },
    "/v1/networks/{networkId}/evaluate-decision": {
      "post": {
        "tags": [
          "Inference"
        ],
        "summary": "Score decision alternatives vs outcome probability or expected utility",
        "parameters": [
          {
            "name": "networkId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Decision evaluation"
          }
        }
      }
    },
    "/v1/networks/{networkId}/explain": {
      "post": {
        "tags": [
          "Inference"
        ],
        "summary": "Structured explanation of P(node=state | evidence) via total probability / CPT terms",
        "parameters": [
          {
            "name": "networkId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "node",
                  "state"
                ],
                "properties": {
                  "node": {
                    "type": "string"
                  },
                  "state": {
                    "type": "string"
                  },
                  "set": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Optional evidence Label=State before explaining"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Provenance explanation"
          }
        }
      }
    }
  }
}