{
  "openapi": "3.1.0",
  "info": {
    "title": "Aslan Interactive — Agent API",
    "version": "1.0.0",
    "summary": "Tools an AI agent can use on its user’s behalf: learn what Aslan does, check fit, book a call, request a quote.",
    "description": "Public, rate-limited endpoints designed for AI agents acting for a human. The same tools are available over MCP (Streamable HTTP) at https://aslaninteractive.com/api/mcp and, in-browser, via WebMCP (navigator.modelContext) on every page of https://aslaninteractive.com.\n\nRules of the road: read tools are free to call. Consequential actions (book_call, request_quote) require `userConfirmed: true`, meaning the agent has shown the user exactly what will happen and the user agreed. Please send a Signature-Agent header (Web Bot Auth) if your platform supports it.\n\nExisting Aslan clients: your agent should use the client portal MCP server at https://portal.aslan.digital/api/mcp (OAuth or a scoped token from https://portal.aslan.digital/dashboard/api-tokens) — see GET /api/agent/portal-access.\n\nHuman documentation: https://aslaninteractive.com/for-agents",
    "contact": {
      "name": "Aslan Interactive",
      "email": "hello@aslaninteractive.com",
      "url": "https://aslaninteractive.com"
    }
  },
  "servers": [
    {
      "url": "https://aslaninteractive.com"
    }
  ],
  "x-mcp-server": "https://aslaninteractive.com/api/mcp",
  "x-llms-txt": "https://aslaninteractive.com/llms.txt",
  "paths": {
    "/api/agent/services": {
      "get": {
        "operationId": "get_services",
        "summary": "List Aslan’s services with summaries, inclusions, and page URLs.",
        "responses": {
          "200": {
            "description": "Services, verticals, pricing model, and company facts."
          }
        }
      }
    },
    "/api/agent/case-studies": {
      "get": {
        "operationId": "get_case_studies",
        "summary": "List client case studies (client, industry, challenge, solution, since).",
        "parameters": [
          {
            "name": "vertical",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "music-ip-licensing",
                "automotive-b2b"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Case studies."
          }
        }
      }
    },
    "/api/agent/fit": {
      "post": {
        "operationId": "check_fit",
        "summary": "Deterministic assessment of whether a project is a good fit for Aslan, with reasons.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "industry": {
                    "description": "Industry or business type, e.g. \"music publisher\", \"auto parts distributor\"",
                    "type": "string",
                    "maxLength": 200
                  },
                  "projectType": {
                    "description": "What needs building or fixing, e.g. \"customer portal\", \"licensing platform rebuild\", \"AI intake\"",
                    "type": "string",
                    "maxLength": 200
                  },
                  "description": {
                    "description": "Free-text description of the situation and goals",
                    "type": "string",
                    "maxLength": 4000
                  },
                  "budgetRange": {
                    "description": "Budget band if known",
                    "type": "string",
                    "maxLength": 100
                  },
                  "timeline": {
                    "description": "When the work is needed",
                    "type": "string",
                    "maxLength": 100
                  }
                },
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Fit assessment."
          },
          "400": {
            "description": "Invalid input."
          }
        }
      }
    },
    "/api/agent/availability": {
      "get": {
        "operationId": "check_availability",
        "summary": "Open 20-minute technical-call slots with a founder over the next 1–7 days.",
        "parameters": [
          {
            "name": "days",
            "in": "query",
            "required": false,
            "schema": {
              "description": "How many days ahead to look (1–7, default 7)",
              "type": "integer",
              "minimum": 1,
              "maximum": 7
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Available slots (ISO 8601, UTC)."
          },
          "503": {
            "description": "Scheduling not configured."
          }
        }
      }
    },
    "/api/agent/book": {
      "post": {
        "operationId": "book_call",
        "summary": "Book a 20-minute technical call. Requires userConfirmed=true.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "startTime": {
                    "type": "string",
                    "format": "date-time",
                    "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$",
                    "description": "An ISO 8601 startTime returned by check_availability"
                  },
                  "name": {
                    "type": "string",
                    "minLength": 2,
                    "maxLength": 120,
                    "description": "Full name of the person the call is for"
                  },
                  "email": {
                    "type": "string",
                    "maxLength": 200,
                    "format": "email",
                    "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$",
                    "description": "Email address of the person the call is for"
                  },
                  "timezone": {
                    "description": "IANA timezone of the attendee, e.g. America/Chicago",
                    "type": "string",
                    "maxLength": 80
                  },
                  "notes": {
                    "description": "What they want to discuss — helps the founder prepare",
                    "type": "string",
                    "maxLength": 2000
                  },
                  "userConfirmed": {
                    "type": "boolean",
                    "enum": [
                      true
                    ],
                    "description": "Must be true. The agent must have shown the user the exact time and obtained their explicit confirmation before calling this tool."
                  }
                },
                "required": [
                  "startTime",
                  "name",
                  "email",
                  "userConfirmed"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Booking confirmed, with cancel/reschedule links."
          },
          "400": {
            "description": "Invalid input or missing user confirmation."
          },
          "409": {
            "description": "Slot no longer available."
          }
        }
      }
    },
    "/api/agent/quote": {
      "post": {
        "operationId": "request_quote",
        "summary": "Submit a project brief; a founder replies with a written quote before any work begins. Requires userConfirmed=true.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "minLength": 2,
                    "maxLength": 120,
                    "description": "Contact name"
                  },
                  "email": {
                    "type": "string",
                    "maxLength": 200,
                    "format": "email",
                    "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$",
                    "description": "Contact email — the written quote is sent here"
                  },
                  "company": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200,
                    "description": "Company or organization"
                  },
                  "phone": {
                    "type": "string",
                    "maxLength": 40
                  },
                  "role": {
                    "description": "Contact’s role, e.g. COO, Director of Operations",
                    "type": "string",
                    "maxLength": 120
                  },
                  "industry": {
                    "type": "string",
                    "maxLength": 200
                  },
                  "projectType": {
                    "type": "string",
                    "minLength": 2,
                    "maxLength": 200,
                    "description": "What needs building, e.g. \"B2B ordering portal\", \"royalty reporting rebuild\", \"AI intake for support requests\""
                  },
                  "problem": {
                    "type": "string",
                    "minLength": 10,
                    "maxLength": 6000,
                    "description": "The business problem and what success looks like. More detail = more accurate quote."
                  },
                  "existingSystems": {
                    "description": "Current systems, stack, or vendors involved",
                    "type": "string",
                    "maxLength": 2000
                  },
                  "budgetRange": {
                    "description": "Budget band if the user has one",
                    "type": "string",
                    "maxLength": 100
                  },
                  "timeline": {
                    "description": "Target timeline",
                    "type": "string",
                    "maxLength": 100
                  },
                  "userConfirmed": {
                    "type": "boolean",
                    "enum": [
                      true
                    ],
                    "description": "Must be true. The agent must have shown the user the brief and obtained their explicit confirmation to submit it."
                  }
                },
                "required": [
                  "name",
                  "email",
                  "company",
                  "projectType",
                  "problem",
                  "userConfirmed"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Receipt with a quote reference."
          },
          "400": {
            "description": "Invalid input."
          }
        }
      }
    },
    "/api/agent/portal-access": {
      "get": {
        "operationId": "get_client_portal_access",
        "summary": "How an existing client’s agent connects to the Aslan client portal (MCP URL, OAuth discovery, token page, scopes).",
        "responses": {
          "200": {
            "description": "Portal connection details."
          }
        }
      }
    }
  }
}