{
  "openapi": "3.0.3",
  "info": {
    "title": "법마디(Lawmadi) OS — Korean Legal AI API",
    "description": "법마디(Lawmadi) OS — Korean Legal AI with 60 specialized agents and real-time statute verification via law.go.kr. Login grants 10 free credits one time (non-recurring). Korean & English.",
    "version": "60.0.1",
    "contact": {
      "email": "admin@lawmadi.com"
    },
    "termsOfService": "https://lawmadi.com/terms"
  },
  "servers": [
    {
      "url": "https://lawmadi.com",
      "description": "Production"
    }
  ],
  "paths": {
    "/ask": {
      "post": {
        "operationId": "askLegalQuestion",
        "summary": "Submit a legal question",
        "description": "Routes query to the most relevant specialist agent among 60 legal domains. Returns verified legal analysis with statute citations. Login required; each user gets 10 free credits one time on login (non-recurring), then must purchase credits.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "query"
                ],
                "properties": {
                  "query": {
                    "type": "string",
                    "description": "Legal question in Korean or English",
                    "example": "부당해고를 당했는데 어떻게 해야 하나요?"
                  },
                  "lang": {
                    "type": "string",
                    "enum": [
                      "ko",
                      "en"
                    ],
                    "default": "ko",
                    "description": "Response language"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Legal analysis response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "response": {
                      "type": "string",
                      "description": "Legal analysis with verified statute citations"
                    },
                    "leader": {
                      "type": "string",
                      "description": "Specialist agent name that handled the query"
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "success",
                        "error"
                      ]
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "model": {
                          "type": "string",
                          "description": "LLM model used"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Out of credits (login grants 10 free credits one time, non-recurring)"
          }
        },
        "security": [
          {
            "apiKey": []
          },
          {
            "oauth2": [
              "mcp"
            ]
          }
        ]
      }
    },
    "/ask-stream": {
      "post": {
        "operationId": "askLegalQuestionStream",
        "summary": "Submit a legal question (streaming)",
        "description": "Same as /ask but returns Server-Sent Events (SSE) for streaming responses.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "query"
                ],
                "properties": {
                  "query": {
                    "type": "string",
                    "description": "Legal question in Korean or English"
                  },
                  "lang": {
                    "type": "string",
                    "enum": [
                      "ko",
                      "en"
                    ],
                    "default": "ko"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "SSE stream of legal analysis chunks",
            "content": {
              "text/event-stream": {}
            }
          },
          "429": {
            "description": "Rate limit exceeded"
          }
        },
        "security": [
          {
            "apiKey": []
          },
          {
            "oauth2": [
              "mcp"
            ]
          }
        ]
      }
    },
    "/.well-known/mcp.json": {
      "get": {
        "tags": [
          "Agent discovery"
        ],
        "summary": "MCP discovery document",
        "description": "Server description, tool count, auth type and the tools callable without a key.",
        "responses": {
          "200": {
            "description": "Metadata document (JSON)"
          }
        }
      }
    },
    "/.well-known/oauth-authorization-server": {
      "get": {
        "tags": [
          "Agent discovery"
        ],
        "summary": "OAuth 2.0 authorization server metadata (RFC 8414)",
        "description": "Endpoints, grant types and `code_challenge_methods_supported` (S256 only).",
        "responses": {
          "200": {
            "description": "Metadata document (JSON)"
          }
        }
      }
    },
    "/mcp/.well-known/oauth-protected-resource": {
      "get": {
        "tags": [
          "Agent discovery"
        ],
        "summary": "OAuth 2.0 protected resource metadata (RFC 9728)",
        "description": "What MCP clients read before `tools/call`. Also served at /.well-known/oauth-protected-resource.",
        "responses": {
          "200": {
            "description": "Metadata document (JSON)"
          }
        }
      }
    },
    "/.well-known/agent-card.json": {
      "get": {
        "tags": [
          "Agent discovery"
        ],
        "summary": "A2A agent card",
        "description": "Skills, security schemes and capabilities. `streaming` and `pushNotifications` are false — this agent completes tasks synchronously. Also served at /.well-known/agent.json (legacy path).",
        "responses": {
          "200": {
            "description": "Metadata document (JSON)"
          }
        }
      }
    },
    "/.well-known/x402": {
      "get": {
        "tags": [
          "Agent discovery"
        ],
        "summary": "x402 machine-payment discovery",
        "description": "**Returns 404 while no on-chain wallet is configured** — implemented but not enabled. The 404 body says so and points at the browser checkout. We do not advertise a capability we cannot honour.",
        "responses": {
          "200": {
            "description": "Metadata document (JSON)"
          }
        }
      }
    },
    "/plans": {
      "get": {
        "tags": [
          "Pricing"
        ],
        "summary": "Pricing as machine-readable JSON",
        "description": "Credit packs, the one-time sign-in bonus, and the fact that anonymous queries are not allowed. This is the pricing source of truth for clients.",
        "responses": {
          "200": {
            "description": "Metadata document (JSON)"
          }
        }
      }
    },
    "/oauth/register": {
      "post": {
        "tags": [
          "Agent discovery"
        ],
        "summary": "Dynamic client registration (RFC 7591)",
        "description": "Open to any client — registration is a client describing itself, not resource access; access is created by a human approving at /oauth/authorize. Rate limited per source. `redirect_uris` must be https, a loopback http URI (RFC 8252), or a reverse-domain custom scheme.",
        "responses": {
          "201": {
            "description": "Client registered"
          },
          "400": {
            "description": "invalid_redirect_uri / invalid_client_metadata"
          },
          "429": {
            "description": "Registration limit reached for this source"
          }
        }
      }
    },
    "/oauth/token": {
      "post": {
        "tags": [
          "Agent discovery"
        ],
        "summary": "Token endpoint — authorization_code (PKCE S256) and refresh_token",
        "description": "Returns an `lmk_live_…` access token plus a rotating refresh token. Reusing an authorization code or a rotated refresh token revokes the whole grant (RFC 6749 §10.5).",
        "responses": {
          "200": {
            "description": "Access token issued"
          },
          "400": {
            "description": "invalid_grant / invalid_request"
          },
          "401": {
            "description": "invalid_client"
          }
        }
      }
    },
    "/a2a": {
      "post": {
        "tags": [
          "Agent discovery"
        ],
        "summary": "A2A JSON-RPC — message/send, tasks/get, tasks/cancel",
        "description": "Skills map to the same MCP tools and pass through the same auth, quota and billing gate — there is no separate metered path here. `message/stream` and push notifications are refused with the spec code because the agent card declares them false.",
        "security": [
          {},
          {
            "apiKey": []
          },
          {
            "oauth2": [
              "mcp"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "JSON-RPC result (a terminal Task) or JSON-RPC error"
          }
        }
      }
    },
    "/x402/credits": {
      "post": {
        "tags": [
          "Pricing"
        ],
        "summary": "Buy credits with an on-chain payment (x402)",
        "description": "**Returns 501 while no on-chain wallet is configured.** When enabled: authenticate first (401 comes before 402 — paying before we can identify an account would take the payment with nothing to credit), then the first call returns 402 with paymentRequirements and you retry with the `X-PAYMENT` header. Each payment proof credits exactly once; a reused proof gets 409, not another 402.",
        "security": [
          {
            "apiKey": []
          },
          {
            "oauth2": [
              "mcp"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "Credits added"
          },
          "401": {
            "description": "Authentication required before payment"
          },
          "402": {
            "description": "Payment required — body carries paymentRequirements"
          },
          "409": {
            "description": "This payment proof was already used"
          },
          "501": {
            "description": "x402 is implemented but not configured on this server"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "apiKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "Customer API key — `Authorization: Bearer lmk_live_…`. Issue one after email sign-in at https://lawmadi.com/mcp-key-guide-en, or obtain one through the OAuth flow below (an OAuth access token IS such a key, so quotas and billing behave identically). Costs are not duplicated here: GET /plans returns the current pricing as JSON, and the MCP tool `get_pricing` needs no auth."
      },
      "oauth2": {
        "type": "oauth2",
        "description": "Authorization code + PKCE (S256 only). Dynamic client registration is open (RFC 7591). Scope `mcp:read` cannot spend the user's credits. Server metadata: https://lawmadi.com/.well-known/oauth-authorization-server (RFC 8414); protected resource metadata: https://lawmadi.com/mcp/.well-known/oauth-protected-resource (RFC 9728).",
        "flows": {
          "authorizationCode": {
            "authorizationUrl": "https://lawmadi.com/oauth/authorize",
            "tokenUrl": "https://lawmadi.com/oauth/token",
            "scopes": {
              "mcp": "Call any tool, including tools that spend credits.",
              "mcp:read": "Call tools that never spend credits."
            }
          }
        }
      }
    }
  }
}
