{
  "openapi": "3.1.0",
  "info": {
    "title": "TuchSoft site APIs",
    "version": "1.0.0",
    "summary": "The HTTP surface behind the tools registered on tuchsoft.com.",
    "description": "The primary surface for AI agents on tuchsoft.com: four HTTP endpoints, usable by any agent or script, with no browser and no account. The same capabilities are also registered as WebMCP tools for browser agents, but that needs a WebMCP-capable browser and today that is behind a flag, so these endpoints are the ones that work everywhere. All endpoints accept cross-origin calls from https://tuchsoft.com and are public: there is no API key, no account and no rate limit in place today, so a client should behave politely on its own.",
    "contact": {
      "name": "TuchSoft",
      "url": "https://tuchsoft.com/",
      "email": "info@tuchsoft.com"
    }
  },
  "servers": [
    {
      "url": "https://workflow.tuchsoft.com/webhook",
      "description": "Production"
    }
  ],
  "paths": {
    "/search": {
      "post": {
        "operationId": "search",
        "summary": "Search TuchSoft content",
        "description": "Search TuchSoft's articles, software and plugins, and technical documentation. Use it for questions about Moodle administration, upgrades, migration or backup, for the changes in Moodle 5.3, and for how a TuchSoft plugin works.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "query": {
                    "type": "string",
                    "description": "Keywords or a natural-language question. Required; empty means \"list the first items of the corpus\"."
                  },
                  "type": {
                    "type": "string",
                    "enum": [
                      "all",
                      "article",
                      "product",
                      "doc"
                    ],
                    "default": "all"
                  },
                  "limit": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 10,
                    "default": 5
                  }
                },
                "required": [
                  "query"
                ]
              },
              "examples": {
                "articles": {
                  "value": {
                    "query": "backup a Moodle site",
                    "type": "article",
                    "limit": 3
                  }
                },
                "documentation": {
                  "value": {
                    "query": "identity verification settings",
                    "type": "doc"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Search results, ranked. The list may be empty.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "query": {
                      "type": "string"
                    },
                    "type": {
                      "type": "string"
                    },
                    "count": {
                      "type": "integer"
                    },
                    "results": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "type": {
                            "type": "string",
                            "enum": [
                              "article",
                              "product",
                              "doc"
                            ]
                          },
                          "title": {
                            "type": "string"
                          },
                          "url": {
                            "type": "string"
                          },
                          "category": {
                            "type": "string"
                          },
                          "excerpt": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Missing query or an invalid type."
          },
          "503": {
            "description": "The search index is not available."
          }
        }
      }
    },
    "/moodleVersion": {
      "post": {
        "operationId": "identifyMoodleVersion",
        "summary": "Identify the Moodle version of a site",
        "description": "Reads public files of the given site to detect which Moodle version it runs. No login, no registration, no data touched on the target site.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "url": {
                    "type": "string",
                    "description": "Full URL of the Moodle site."
                  }
                },
                "required": [
                  "url"
                ]
              },
              "examples": {
                "basic": {
                  "value": {
                    "url": "https://moodle.example.com"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Three different outcomes share the 200 status, so the client MUST look at the payload and not at the status code.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "title": "detected",
                      "type": "object",
                      "properties": {
                        "result": {
                          "const": "version"
                        },
                        "version": {
                          "type": "string",
                          "examples": [
                            "5.3.0"
                          ]
                        },
                        "year": {
                          "type": "integer"
                        },
                        "steps": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          },
                          "description": "upgrade path towards the latest stable release"
                        },
                        "ssl": {
                          "type": "boolean"
                        },
                        "class": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "result",
                        "version"
                      ]
                    },
                    {
                      "title": "blocked",
                      "type": "object",
                      "properties": {
                        "result": {
                          "const": "blocked"
                        },
                        "reason": {
                          "type": "string",
                          "examples": [
                            "cloudflare",
                            "firewall"
                          ]
                        }
                      },
                      "required": [
                        "result",
                        "reason"
                      ]
                    },
                    {
                      "title": "not detected",
                      "type": "object",
                      "properties": {
                        "result": {
                          "const": "not_detected"
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable reason."
                        }
                      },
                      "required": [
                        "result"
                      ]
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The url field is missing or unusable (not a public HTTP/HTTPS URL). Note that an address that is well formed but unreachable is NOT a 400: it comes back as 200 with result \"not_detected\".",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "result": {
                      "const": "invalid"
                    },
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "result"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/demo-request": {
      "post": {
        "operationId": "requestMoodleDemo",
        "summary": "Request a free temporary Moodle 5.3 platform",
        "description": "Registers a demo request and sends a confirmation email. The platform is created when the recipient opens the confirmation link, and is destroyed automatically together with all its data. NOTE: this endpoint answers with an HTTP 303 redirect to <return_base>/tools/try-moodle-503/?attesa=1 on success, or ?err=1 when the request is rejected, so callers should follow redirects and read the final URL.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "firstname": {
                    "type": "string"
                  },
                  "lastname": {
                    "type": "string"
                  },
                  "email": {
                    "type": "string",
                    "description": "The confirmation link is sent here."
                  },
                  "org": {
                    "type": "string"
                  },
                  "role": {
                    "type": "string"
                  },
                  "plugins": {
                    "type": "string"
                  },
                  "consent": {
                    "type": "string",
                    "enum": [
                      "yes"
                    ],
                    "description": "The user must have accepted https://tuchsoft.com/legal/demo-terms and https://tuchsoft.com/legal/privacy-policy."
                  },
                  "return_base": {
                    "type": "string",
                    "description": "Origin to return to. Defaults to https://tuchsoft.com."
                  }
                },
                "required": [
                  "firstname",
                  "lastname",
                  "email",
                  "org",
                  "consent"
                ]
              },
              "examples": {
                "request": {
                  "value": {
                    "firstname": "Jane",
                    "lastname": "Doe",
                    "email": "jane@example.com",
                    "org": "Acme Academy",
                    "role": "Moodle admin / IT",
                    "plugins": "BigBlueButton",
                    "consent": "yes",
                    "return_base": "https://tuchsoft.com"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "303": {
            "description": "Redirect to the waiting page (?attesa=1) or to the error page (?err=1)."
          }
        }
      }
    },
    "/sendEmail": {
      "post": {
        "operationId": "contactTuchsoft",
        "summary": "Send a message to the TuchSoft team",
        "description": "Sends a message to info@tuchsoft.com. Requires the same request header the site's own forms send.",
        "parameters": [
          {
            "name": "X-Tuchsoft-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Value: WTJsaGJ5QmlaV3hzWVN3Z2FXOGdkR2tnWTI5dWIzTmpieUIwZFNCbWR . This header is a filter against blind form spam, nothing more: the value is published here and in https://tuchsoft.com/llms.txt on purpose, so any agent that reads our documentation can send it. It is not a secret and it is not authentication."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "email": {
                    "type": "string"
                  },
                  "org": {
                    "type": "string"
                  },
                  "message": {
                    "type": "string"
                  },
                  "info": {
                    "type": "object",
                    "description": "Optional context: page URL, timestamp, source."
                  }
                },
                "required": [
                  "name",
                  "email",
                  "message"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Message sent.",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "418": {
            "description": "Missing or invalid request header."
          },
          "500": {
            "description": "The message could not be sent."
          }
        }
      }
    }
  }
}
