{
  "openapi": "3.0.3",
  "info": {
    "title": "Ansvar Query API",
    "version": "1.0.0",
    "description": "Programmatic access to the Ansvar intelligence engine. Any system that can make an HTTPS request — CI/CD pipelines, compliance tools, AI agents — can query regulations, frameworks, and legal databases through a single endpoint.\n\nEvery response includes citations from authoritative MCP data sources. No silent fallbacks — if an MCP server is unavailable, you get an explicit warning or error, never hallucinated data.",
    "contact": {
      "name": "Ansvar Systems",
      "url": "https://ansvar.eu",
      "email": "support@ansvar.eu"
    },
    "license": {
      "name": "Proprietary"
    }
  },
  "servers": [
    {
      "url": "https://intel.ansvar.eu/api/v1",
      "description": "Production"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "paths": {
    "/query": {
      "post": {
        "operationId": "query",
        "summary": "Query the intelligence engine",
        "description": "Send a compliance, security, or legal question to a specialized AI agent. The agent queries authoritative MCP data sources and returns a cited answer.\n\n**Agent selection:** Pass `agent_id` (slug or UUID) to route your query to a specific expert. Each agent has access to specific MCP data sources — pick the one whose sources match your question. Omit to use the default routing agent.\n\n**Follow-up conversations:** Pass `conversation_id` from a previous response to continue a conversation. The agent receives all prior messages as context.",
        "tags": ["Query"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/QueryRequest"
              },
              "examples": {
                "dora_query": {
                  "summary": "DORA compliance question",
                  "value": {
                    "message": "What does DORA Article 28 require for third-party risk management?",
                    "agent_id": "dora-expert"
                  }
                },
                "nis2_query": {
                  "summary": "NIS2 incident reporting",
                  "value": {
                    "message": "What incident notification timelines does NIS2 require?",
                    "agent_id": "nis2-expert"
                  }
                },
                "follow_up": {
                  "summary": "Follow-up question",
                  "value": {
                    "message": "What are the specific timelines?",
                    "agent_id": "dora-expert",
                    "conversation_id": "ff624e87-da81-4dae-9f65-92a9c7c11402"
                  }
                },
                "gdpr_cicd": {
                  "summary": "CI/CD compliance check",
                  "value": {
                    "message": "We are deploying a new service that processes customer PII to AWS eu-west-1. What GDPR and NIS2 requirements apply?",
                    "agent_id": "gdpr-privacy-expert"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful query with cited response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/QueryResponse"
                },
                "example": {
                  "request_id": "req_cf97a6d2",
                  "conversation_id": "ff624e87-da81-4dae-9f65-92a9c7c11402",
                  "message": "Article 28 — General principles of DORA mandates that financial entities must manage ICT third-party risk as an integral part of their overall ICT risk management framework...",
                  "citations": [
                    {
                      "type": "regulation",
                      "source": "DORA (EU 2022/2554)",
                      "reference": "Article 28",
                      "excerpt": ""
                    }
                  ],
                  "warnings": [],
                  "agents": ["DORA Expert"],
                  "tokens_remaining": 996,
                  "llm_tokens_used": 18207
                }
              }
            }
          },
          "400": {
            "description": "Invalid request — empty message, message exceeds 10,000 characters, or malformed JSON",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "request_id": "req_a1b2c3",
                  "error": "invalid_request",
                  "detail": "Message must not be empty."
                }
              }
            }
          },
          "401": {
            "description": "Invalid API key — missing, revoked, or malformed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "request_id": "req_d4e5f6",
                  "error": "invalid_api_key",
                  "detail": "API key is missing or invalid."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient tokens — organisation credit balance is zero",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "request_id": "req_g7h8i9",
                  "error": "insufficient_tokens",
                  "detail": "Organisation credit balance is zero."
                }
              }
            }
          },
          "404": {
            "description": "Not found — conversation_id does not exist or belongs to a different organisation",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "request_id": "req_j0k1l2",
                  "error": "not_found",
                  "detail": "Conversation not found.",
                  "conversation_id": "ff624e87-da81-4dae-9f65-92a9c7c11402"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited — exceeds 30 requests/second per IP",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "request_id": "req_m3n4o5",
                  "error": "rate_limited",
                  "detail": "Too many requests. Limit: 30 req/s per IP."
                }
              }
            }
          },
          "503": {
            "description": "Service unavailable — agent or MCP data source execution failed. No tokens charged.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "request_id": "req_p6q7r8",
                  "error": "service_unavailable",
                  "detail": "MCP data source 'EU Regulations' is currently unavailable."
                }
              }
            }
          },
          "504": {
            "description": "Query timeout — agent did not complete within 60 seconds. No tokens charged.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "request_id": "req_s9t0u1",
                  "error": "query_timeout",
                  "detail": "Agent did not complete within 60 seconds.",
                  "conversation_id": "ff624e87-da81-4dae-9f65-92a9c7c11402"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "API key with `ak_live_` prefix followed by 32 alphanumeric characters.\n\nKeys are per organisation (not per user), hashed at rest with SHA-256, individually revocable, and audit-logged.\n\nEvery API call is logged with key ID, source IP, query text, agent used, and response time."
      }
    },
    "schemas": {
      "QueryRequest": {
        "type": "object",
        "required": ["message"],
        "properties": {
          "message": {
            "type": "string",
            "maxLength": 10000,
            "description": "The compliance, security, or legal question to ask.",
            "example": "What does DORA Article 28 require for third-party risk management?"
          },
          "agent_id": {
            "type": "string",
            "description": "Agent slug or UUID. Each agent has access to specific MCP data sources — pick the one whose sources match your question. Omit to use the default routing agent.\n\n**Regulatory:** `dora-expert`, `nis2-expert`, `gdpr-privacy-expert`, `ai-act-expert`, `us-compliance-expert`, `latam-regulatory-expert`\n\n**Security:** `cloud-security-expert`, `ot-ics-expert`, `devsecops-expert`, `pentest-expert`, `incident-responder`, `supply-chain-expert`\n\n**Industry:** `financial-services-expert`, `healthcare-expert`, `automotive-expert`, `energy-expert`, `defense-aerospace-expert`\n\n**Mapping:** `controls-mapper`, `risk-assessor`, `tprm-expert`, `legal-research`",
            "example": "dora-expert"
          },
          "conversation_id": {
            "type": "string",
            "format": "uuid",
            "description": "UUID from a previous response. Include to continue a conversation — the agent receives all prior messages as context.",
            "example": "ff624e87-da81-4dae-9f65-92a9c7c11402"
          }
        }
      },
      "QueryResponse": {
        "type": "object",
        "properties": {
          "request_id": {
            "type": "string",
            "description": "Unique identifier for this request. Use for support tickets and audit trails.",
            "example": "req_cf97a6d2"
          },
          "conversation_id": {
            "type": "string",
            "format": "uuid",
            "description": "Conversation UUID. Pass back in the next request to continue the conversation.",
            "example": "ff624e87-da81-4dae-9f65-92a9c7c11402"
          },
          "message": {
            "type": "string",
            "description": "Agent response in markdown format with inline citations.",
            "example": "Article 28 — General principles of DORA mandates that financial entities must manage ICT third-party risk..."
          },
          "citations": {
            "type": "array",
            "description": "Sources the agent cited. Each citation references a specific regulation, article, or uploaded document.",
            "items": {
              "$ref": "#/components/schemas/Citation"
            }
          },
          "warnings": {
            "type": "array",
            "description": "Empty when all data sources responded successfully. Contains details when a source was unavailable — the agent may have answered from a subset of its usual sources.",
            "items": {
              "type": "string"
            },
            "example": []
          },
          "agents": {
            "type": "array",
            "description": "Names of the agents that contributed to the response.",
            "items": {
              "type": "string"
            },
            "example": ["DORA Expert"]
          },
          "tokens_remaining": {
            "type": "integer",
            "description": "Organisation's remaining credit balance after this query.",
            "example": 996
          },
          "llm_tokens_used": {
            "type": "integer",
            "description": "Total LLM tokens consumed by this query (input + output).",
            "example": 18207
          }
        }
      },
      "Citation": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": ["regulation", "org_document"],
            "description": "`regulation` — source is an EU regulation, directive, national law, or security framework from the MCP fleet.\n\n`org_document` — source is a document uploaded by the organisation via the Intelligence Portal."
          },
          "source": {
            "type": "string",
            "description": "Name of the source (e.g. \"DORA (EU 2022/2554)\", \"Swedish Law\").",
            "example": "DORA (EU 2022/2554)"
          },
          "reference": {
            "type": "string",
            "description": "Specific article, section, or provision cited.",
            "example": "Article 28"
          },
          "excerpt": {
            "type": "string",
            "description": "Relevant text excerpt from the source, when available."
          }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "properties": {
          "request_id": {
            "type": "string",
            "description": "Unique identifier for this request.",
            "example": "req_y8g3m2"
          },
          "error": {
            "type": "string",
            "enum": ["invalid_request", "invalid_api_key", "insufficient_tokens", "not_found", "rate_limited", "service_unavailable", "query_timeout"],
            "description": "Machine-readable error code.",
            "example": "query_timeout"
          },
          "detail": {
            "type": "string",
            "description": "Human-readable error description.",
            "example": "Agent did not complete within 60 seconds."
          },
          "conversation_id": {
            "type": "string",
            "description": "Included when the error relates to an existing conversation.",
            "example": "ff624e87-da81-4dae-9f65-92a9c7c11402"
          }
        }
      }
    }
  },
  "tags": [
    {
      "name": "Query",
      "description": "Send compliance, security, and legal questions to specialized AI agents backed by 160+ authoritative MCP data sources. Every response includes citations so you can verify the answer.\n\n## Rate Limits\n\n- **30 requests/second** per IP with burst allowance of 20\n- **60-second timeout** — if the agent does not complete, you get a 504 and any credits are refunded\n\n## Billing\n\n- **API queries** are billed per LLM token usage (`llm_tokens_used` in each response)\n- **Workflows** (threat models, DPIAs) consume credits from the organisation's monthly allocation\n- Regular API queries do not consume workflow credits\n\n## No Silent Fallbacks\n\nIf an MCP data source is unavailable, the response either includes a `warnings` entry (partial success) or returns HTTP 503 (total failure). The agent never answers from LLM training data in place of MCP data."
    }
  ]
}
