{
    "openapi": "3.1.0",
    "info": {
        "title": "Ledger Botje - Exact Online MCP",
        "version": "1.1.4",
        "summary": "MCP server that connects AI assistants to Exact Online ERP.",
        "description": "Ledger Botje exposes 294 MCP tools (124 read-only, 170 write) and 57 MCP prompts for Exact Online: sales, purchasing, inventory, manufacturing, projects, CRM and financials. The programmable surface is the MCP endpoint (JSON-RPC 2.0 over Streamable HTTP) - there is intentionally no separate REST API. Authentication uses OAuth 2.1 with mandatory PKCE and supports dynamic client registration (POST https://ledgerbotje.nl/app/mcp/oauth/register, RFC 7591). Rate limits are informative, never blocking: every tool response carries a rateLimit object and X-RateLimit-* headers. Getting started: create an account at https://ledgerbotje.nl/app/ (14-day free trial, no credit card), connect Exact Online, then add the MCP server to your AI client - see https://ledgerbotje.nl/mcp-koppelen.",
        "termsOfService": "https://ledgerbotje.nl/app/acceptterms.php",
        "contact": {
            "name": "Industrial IT",
            "email": "support@industrialit.nl",
            "url": "https://ledgerbotje.nl/contact"
        }
    },
    "servers": [
        {
            "url": "https://ledgerbotje.nl"
        }
    ],
    "paths": {
        "/app/mcp": {
            "post": {
                "operationId": "mcpJsonRpc",
                "summary": "MCP endpoint (JSON-RPC 2.0 over Streamable HTTP)",
                "description": "Single entry point for the Model Context Protocol. Call initialize for the handshake, tools/list for the tool catalog and tools/call to invoke a tool. Responses are JSON or an SSE stream (text/event-stream), depending on the Accept header and the operation.",
                "security": [
                    {
                        "oauth2": [
                            "mcp:tools"
                        ]
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/JsonRpcRequest"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "JSON-RPC response or SSE stream",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/JsonRpcResponse"
                                }
                            },
                            "text/event-stream": {
                                "schema": {
                                    "type": "string"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Missing, expired or revoked token. The WWW-Authenticate header carries a resource_metadata URL (RFC 9728) pointing at the protected-resource metadata.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/OAuthError"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/app/documentuploadapi.php": {
            "put": {
                "operationId": "uploadDocumentPut",
                "summary": "Upload a document body for a pending upload token",
                "description": "Second step of the document-upload flow: the MCP tool documents_request_upload_url issues a single-use token, this endpoint receives the file bytes, and the MCP tool documents_upload consumes the token as fileReference.",
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "pattern": "^[a-f0-9]{64}$"
                        },
                        "description": "Single-use upload token issued by the MCP tool documents_request_upload_url."
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/octet-stream": {
                            "schema": {
                                "type": "string",
                                "format": "binary"
                            }
                        },
                        "multipart/form-data": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "file": {
                                        "type": "string",
                                        "format": "binary"
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Upload stored",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/UploadResult"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Invalid or unknown token",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/UploadError"
                                }
                            }
                        }
                    },
                    "413": {
                        "description": "File too large",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/UploadError"
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "operationId": "uploadDocumentPost",
                "summary": "Upload a document body for a pending upload token (POST variant)",
                "description": "Identical to the PUT variant; provided for clients that cannot send PUT.",
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "pattern": "^[a-f0-9]{64}$"
                        },
                        "description": "Single-use upload token issued by the MCP tool documents_request_upload_url."
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/octet-stream": {
                            "schema": {
                                "type": "string",
                                "format": "binary"
                            }
                        },
                        "multipart/form-data": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "file": {
                                        "type": "string",
                                        "format": "binary"
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Upload stored",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/UploadResult"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Invalid or unknown token",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/UploadError"
                                }
                            }
                        }
                    },
                    "413": {
                        "description": "File too large",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/UploadError"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/.well-known/oauth-protected-resource": {
            "get": {
                "operationId": "getProtectedResourceMetadata",
                "summary": "OAuth protected-resource metadata (RFC 9728)",
                "description": "Names the MCP resource, its authorization servers, supported scopes and bearer methods.",
                "responses": {
                    "200": {
                        "description": "Metadata document",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/.well-known/oauth-authorization-server": {
            "get": {
                "operationId": "getAuthorizationServerMetadata",
                "summary": "OAuth authorization-server metadata (RFC 8414)",
                "description": "Authorization, token and dynamic-registration endpoints, PKCE methods and scopes.",
                "responses": {
                    "200": {
                        "description": "Metadata document",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/.well-known/mcp/server-card.json": {
            "get": {
                "operationId": "getMcpServerCard",
                "summary": "MCP server card",
                "description": "Machine-readable description of the MCP server: transport, authentication and capabilities.",
                "responses": {
                    "200": {
                        "description": "Server card",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object"
                                }
                            }
                        }
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "JsonRpcRequest": {
                "type": "object",
                "description": "JSON-RPC 2.0 request envelope (MCP). Discover the available methods and tools via the MCP handshake (initialize, tools/list).",
                "required": [
                    "jsonrpc",
                    "method"
                ],
                "properties": {
                    "jsonrpc": {
                        "type": "string",
                        "const": "2.0"
                    },
                    "id": {
                        "oneOf": [
                            {
                                "type": "string"
                            },
                            {
                                "type": "integer"
                            },
                            {
                                "type": "null"
                            }
                        ]
                    },
                    "method": {
                        "type": "string",
                        "description": "MCP method, e.g. initialize, tools/list, tools/call, prompts/list, prompts/get"
                    },
                    "params": {
                        "type": "object",
                        "additionalProperties": true
                    }
                }
            },
            "JsonRpcResponse": {
                "type": "object",
                "description": "JSON-RPC 2.0 response envelope (MCP).",
                "required": [
                    "jsonrpc"
                ],
                "properties": {
                    "jsonrpc": {
                        "type": "string",
                        "const": "2.0"
                    },
                    "id": {
                        "oneOf": [
                            {
                                "type": "string"
                            },
                            {
                                "type": "integer"
                            },
                            {
                                "type": "null"
                            }
                        ]
                    },
                    "result": {
                        "type": "object",
                        "additionalProperties": true
                    },
                    "error": {
                        "type": "object",
                        "properties": {
                            "code": {
                                "type": "integer"
                            },
                            "message": {
                                "type": "string"
                            },
                            "data": {
                                "additionalProperties": true
                            }
                        }
                    }
                }
            },
            "OAuthError": {
                "type": "object",
                "description": "OAuth 2.0 error body (RFC 6749 section 5.2), also carried on 401 responses together with a WWW-Authenticate header that includes resource_metadata (RFC 9728).",
                "required": [
                    "error"
                ],
                "properties": {
                    "error": {
                        "type": "string",
                        "examples": [
                            "invalid_request",
                            "invalid_token"
                        ]
                    },
                    "error_description": {
                        "type": "string"
                    }
                }
            },
            "UploadResult": {
                "type": "object",
                "required": [
                    "success"
                ],
                "properties": {
                    "success": {
                        "type": "boolean",
                        "const": true
                    },
                    "token": {
                        "type": "string"
                    },
                    "fileName": {
                        "type": "string"
                    },
                    "message": {
                        "type": "string"
                    }
                }
            },
            "UploadError": {
                "type": "object",
                "required": [
                    "success",
                    "error"
                ],
                "properties": {
                    "success": {
                        "type": "boolean",
                        "const": false
                    },
                    "error": {
                        "type": "string"
                    }
                }
            }
        },
        "securitySchemes": {
            "oauth2": {
                "type": "oauth2",
                "description": "OAuth 2.1 with mandatory PKCE (S256). Dynamic client registration via POST https://ledgerbotje.nl/app/mcp/oauth/register (RFC 7591). Access tokens live 1 hour; refresh tokens 30 days, rotating.",
                "flows": {
                    "authorizationCode": {
                        "authorizationUrl": "https://ledgerbotje.nl/app/mcp/oauth/authorize",
                        "tokenUrl": "https://ledgerbotje.nl/app/mcp/oauth/token",
                        "refreshUrl": "https://ledgerbotje.nl/app/mcp/oauth/token",
                        "scopes": {
                            "mcp:tools": "Call the Exact Online MCP tools on behalf of the user"
                        }
                    }
                }
            }
        }
    },
    "externalDocs": {
        "description": "Connect the MCP server to your AI client",
        "url": "https://ledgerbotje.nl/mcp-koppelen"
    }
}
