{
  "openapi": "3.0.3",
  "info": {
    "title": "AdvisorFind Matching API",
    "version": "1.0.0"
  },
  "servers": [
    {
      "url": "https://platform.advisorfind.com"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer"
      }
    },
    "schemas": {
      "Client": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "ageRange",
          "hasRetirementAccounts",
          "married",
          "childrenUnder18",
          "retirement",
          "approach",
          "assetBand",
          "priorities"
        ],
        "properties": {
          "ageRange": {
            "type": "string",
            "enum": [
              "under35",
              "35to44",
              "45to54",
              "55to64",
              "65plus"
            ]
          },
          "hasRetirementAccounts": {
            "type": "boolean"
          },
          "married": {
            "type": "boolean"
          },
          "childrenUnder18": {
            "type": "boolean"
          },
          "retirement": {
            "type": "string",
            "enum": [
              "notsoon",
              "preparing",
              "retired"
            ]
          },
          "approach": {
            "type": "string",
            "enum": [
              "preservation",
              "balanced",
              "growth"
            ]
          },
          "assetBand": {
            "type": "string",
            "enum": [
              "under250",
              "250to500",
              "500to2",
              "2to5",
              "over5"
            ]
          },
          "priorities": {
            "type": "array",
            "minItems": 1,
            "maxItems": 5,
            "uniqueItems": true,
            "items": {
              "type": "string",
              "enum": [
                "enough",
                "income",
                "risk",
                "tax",
                "aligned"
              ]
            }
          },
          "firstName": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100,
            "description": "Optional; nonblank, no control characters. Returned as metadata, not used to rank."
          },
          "notes": {
            "type": "string",
            "maxLength": 2200,
            "description": "Optional free-form survey answer, used by AI matching."
          },
          "investableAssets": {
            "type": "integer",
            "minimum": 0,
            "description": "Optional exact USD assets; must be within assetBand. Bands: under250 [0,250000); 250to500 [250000,500000); 500to2 [500000,2000000); 2to5 [2000000,5000000); over5 [5000000,infinity)."
          },
          "state": {
            "type": "string",
            "pattern": "^[A-Z]{2}$",
            "description": "Legacy US state code. Omit this field; location does not influence matching.",
            "enum": [
              "AK",
              "AL",
              "AR",
              "AZ",
              "CA",
              "CO",
              "CT",
              "DC",
              "DE",
              "FL",
              "GA",
              "HI",
              "IA",
              "ID",
              "IL",
              "IN",
              "KS",
              "KY",
              "LA",
              "MA",
              "MD",
              "ME",
              "MI",
              "MN",
              "MO",
              "MS",
              "MT",
              "NC",
              "ND",
              "NE",
              "NH",
              "NJ",
              "NM",
              "NV",
              "NY",
              "OH",
              "OK",
              "OR",
              "PA",
              "RI",
              "SC",
              "SD",
              "TN",
              "TX",
              "UT",
              "VA",
              "VT",
              "WA",
              "WI",
              "WV",
              "WY"
            ]
          }
        }
      },
      "MatchResponse": {
        "type": "object",
        "required": [
          "requestId",
          "advisorIds",
          "matches",
          "status",
          "firstName",
          "eligibleCount",
          "provider",
          "model",
          "fallbackUsed",
          "warnings",
          "elapsedMs"
        ],
        "properties": {
          "requestId": {
            "type": "string"
          },
          "advisorIds": {
            "type": "array",
            "maxItems": 3,
            "uniqueItems": true,
            "items": {
              "type": "string",
              "pattern": "^[0-9]{2,}$"
            }
          },
          "matches": {
            "type": "array",
            "maxItems": 3,
            "items": {
              "type": "object",
              "required": [
                "advisorId",
                "rank",
                "fitScore"
              ],
              "properties": {
                "advisorId": {
                  "type": "string",
                  "pattern": "^[0-9]{2,}$"
                },
                "rank": {
                  "type": "integer",
                  "minimum": 1,
                  "maximum": 3
                },
                "fitScore": {
                  "type": "number",
                  "nullable": true,
                  "minimum": 0,
                  "maximum": 100
                }
              }
            }
          },
          "status": {
            "type": "string",
            "enum": [
              "matched",
              "insufficient_matches"
            ]
          },
          "firstName": {
            "type": "string",
            "nullable": true
          },
          "eligibleCount": {
            "type": "integer",
            "minimum": 0
          },
          "provider": {
            "type": "string",
            "enum": [
              "typesafe",
              "openai"
            ]
          },
          "model": {
            "type": "string",
            "nullable": true
          },
          "fallbackUsed": {
            "type": "boolean"
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "elapsedMs": {
            "type": "integer",
            "minimum": 0
          }
        }
      },
      "Error": {
        "type": "object",
        "required": [
          "error",
          "requestId"
        ],
        "properties": {
          "requestId": {
            "type": "string"
          },
          "error": {
            "type": "object",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "string"
              },
              "message": {
                "type": "string"
              }
            }
          }
        }
      }
    }
  },
  "paths": {
    "/v1/matches": {
      "post": {
        "summary": "Match a prospect with up to three eligible advisors",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "client"
                ],
                "properties": {
                  "client": {
                    "$ref": "#/components/schemas/Client"
                  }
                }
              },
              "example": {
                "client": {
                  "ageRange": "55to64",
                  "hasRetirementAccounts": true,
                  "married": true,
                  "childrenUnder18": false,
                  "retirement": "preparing",
                  "approach": "balanced",
                  "assetBand": "500to2",
                  "priorities": [
                    "income",
                    "tax"
                  ],
                  "firstName": "Alex",
                  "notes": "I own a business and want help planning retirement income and reducing tax surprises."
                }
              }
            }
          }
        },
        "responses": {
          "400": {
            "description": "Invalid JSON or client fields",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or revoked token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Advisor availability changed; retry",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request body exceeds 32 KB",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "415": {
            "description": "Content-Type must be application/json",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit or another match in progress; honor Retry-After",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server failure",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Matching unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "200": {
            "description": "Matching completed; may include fewer than three results",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MatchResponse"
                },
                "example": {
                  "requestId": "example-request-id",
                  "advisorIds": [
                    "01",
                    "07",
                    "12"
                  ],
                  "matches": [
                    {
                      "advisorId": "01",
                      "rank": 1,
                      "fitScore": 92
                    },
                    {
                      "advisorId": "07",
                      "rank": 2,
                      "fitScore": 85
                    },
                    {
                      "advisorId": "12",
                      "rank": 3,
                      "fitScore": 78
                    }
                  ],
                  "status": "matched",
                  "firstName": "Alex",
                  "eligibleCount": 8,
                  "provider": "typesafe",
                  "model": "jev-latest",
                  "fallbackUsed": false,
                  "warnings": [],
                  "elapsedMs": 180
                }
              }
            }
          }
        }
      }
    },
    "/v1/token": {
      "get": {
        "summary": "Verify a token without running matching",
        "responses": {
          "200": {
            "description": "Active token"
          },
          "401": {
            "description": "Invalid token"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    }
  }
}
