{
  "openapi": "3.1.0",
  "info": {
    "title": "Taskquatch Muse Connector API",
    "version": "1.0.0",
    "description": "Partner API for Muse to search Taskquatch services in Middle Tennessee, quote full price (base + add-ons + service fee), start a phone-verified task request, and check status. Payment method setup and final charge happen in the Taskquatch app after the task is completed. Never report a request as booked until payment method setup is done; use submitted_needs_payment_method after verify."
  },
  "servers": [
    {
      "url": "https://api.taskquatch.app/v1/muse",
      "description": "Production"
    }
  ],
  "security": [
    {
      "ApiKeyAuth": []
    }
  ],
  "components": {
    "securitySchemes": {
      "ApiKeyAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "x-api-key",
        "description": "Dedicated Muse API key issued by Taskquatch."
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "error": { "type": "string" }
        },
        "required": ["error"]
      },
      "Service": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "slug": { "type": "string" },
          "name": { "type": "string" },
          "price": { "type": "number" },
          "price_flat": { "type": "number", "nullable": true },
          "price_hr": { "type": "number", "nullable": true },
          "scope": { "type": "string" },
          "description": { "type": "string" },
          "terms": { "type": "string" },
          "page_url": { "type": "string", "format": "uri" },
          "booking_url": { "type": "string", "format": "uri" },
          "area_served": {
            "type": "array",
            "items": { "type": "string" }
          },
          "add_ons": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": { "type": "string", "format": "uuid" },
                "name": { "type": "string" },
                "price": { "type": "number" }
              }
            }
          },
          "payment_timing": { "type": "string" },
          "tool_class": {
            "type": "string",
            "enum": ["read", "write", "sensitive_write"],
            "description": "Muse tool annotation: read / write / sensitive_write"
          }
        }
      },
      "Quote": {
        "type": "object",
        "properties": {
          "quote_token": { "type": "string" },
          "expires_at": { "type": "string", "format": "date-time" },
          "line_items": { "type": "array", "items": { "type": "object" } },
          "subtotal": { "type": "number" },
          "service_fee": { "type": "number" },
          "fee_rate": { "type": "number" },
          "total": { "type": "number" },
          "currency": { "type": "string", "enum": ["USD"] },
          "payment_timing": { "type": "string" },
          "cancellation_terms": { "type": "string" },
          "tool_class": { "type": "string", "enum": ["read"] }
        },
        "required": ["quote_token", "total", "service_fee", "currency"]
      },
      "TaskRequestStatus": {
        "type": "string",
        "enum": [
          "verification_required",
          "submitted_needs_payment_method",
          "finding_taskquatcher",
          "matched",
          "in_progress",
          "completed",
          "cancelled",
          "failed"
        ]
      }
    }
  },
  "paths": {
    "/services": {
      "get": {
        "operationId": "listServices",
        "summary": "Search services by free text",
        "description": "Read. Matches a customer request to Taskquatch specialties (LLM-assisted) and returns the best match plus up to 4 alternatives in the same category, with prices and add-ons.",
        "x-muse-tool-class": "read",
        "parameters": [
          {
            "name": "query",
            "in": "query",
            "required": true,
            "schema": { "type": "string", "minLength": 3 },
            "description": "Natural language description of help needed"
          },
          {
            "name": "city",
            "in": "query",
            "required": false,
            "schema": { "type": "string" },
            "description": "Optional city filter (Nashville area only)"
          }
        ],
        "responses": {
          "200": {
            "description": "Match and alternatives",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "query": { "type": "string" },
                    "match": { "$ref": "#/components/schemas/Service" },
                    "alternatives": {
                      "type": "array",
                      "items": { "$ref": "#/components/schemas/Service" }
                    },
                    "area_served": {
                      "type": "array",
                      "items": { "type": "string" }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid query or outside service area",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" }
              }
            }
          },
          "401": { "description": "Missing or invalid API key" },
          "429": { "description": "Rate limited" }
        }
      }
    },
    "/services/{slug}": {
      "get": {
        "operationId": "getService",
        "summary": "Get one service by slug",
        "description": "Read. Returns a single specialty with add-ons, scope, terms, and area served.",
        "x-muse-tool-class": "read",
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": { "type": "string" }
          }
        ],
        "responses": {
          "200": {
            "description": "Service detail",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "service": { "$ref": "#/components/schemas/Service" }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" }
              }
            }
          }
        }
      }
    },
    "/quotes": {
      "post": {
        "operationId": "createQuote",
        "summary": "Build a price quote",
        "description": "Read (no side effects). Returns line items, 15% service fee, total, cancellation terms, payment timing, and a signed quote_token (30 minute expiry) that must be used to start a task request.",
        "x-muse-tool-class": "read",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["slug"],
                "properties": {
                  "slug": { "type": "string" },
                  "add_on_ids": {
                    "type": "array",
                    "items": { "type": "string", "format": "uuid" }
                  },
                  "city": { "type": "string" },
                  "timing": {
                    "type": "string",
                    "enum": ["asap", "scheduled"]
                  },
                  "scheduled_date": { "type": "string" },
                  "scheduled_time": { "type": "string" }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Quote",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Quote" }
              }
            }
          },
          "400": {
            "description": "Invalid add-ons or area",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" }
              }
            }
          },
          "404": { "description": "Service not found" }
        }
      }
    },
    "/task-requests": {
      "post": {
        "operationId": "startTaskRequest",
        "summary": "Start a task request (sends SMS code)",
        "description": "Sensitive write. Validates the quote_token, stores a pending request, and texts a 6-digit code to the customer phone. Does not create a lead or task until verify.",
        "x-muse-tool-class": "sensitive_write",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": { "type": "string" },
            "description": "Optional key to safely retry without sending a second SMS"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "quote_token",
                  "name",
                  "phone",
                  "email",
                  "service_address"
                ],
                "properties": {
                  "quote_token": { "type": "string" },
                  "name": { "type": "string" },
                  "phone": {
                    "type": "string",
                    "description": "US phone; E.164 preferred"
                  },
                  "email": { "type": "string", "format": "email" },
                  "service_address": { "type": "string" },
                  "drop_off_address": { "type": "string" },
                  "notes": { "type": "string" }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Verification required",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "request_id": { "type": "string", "format": "uuid" },
                    "status": {
                      "type": "string",
                      "enum": ["verification_required"]
                    },
                    "expires_at": { "type": "string", "format": "date-time" },
                    "tool_class": {
                      "type": "string",
                      "enum": ["sensitive_write"]
                    }
                  }
                }
              }
            }
          },
          "400": { "description": "Invalid quote or fields" },
          "429": { "description": "Phone daily cap" },
          "503": { "description": "SMS send failed" }
        }
      }
    },
    "/task-requests/{id}/verify": {
      "post": {
        "operationId": "verifyTaskRequest",
        "summary": "Verify SMS code and create lead/task",
        "description": "Sensitive write. Max 5 attempts. Ensures an Appwrite user with verified phone, creates a Taskquatch lead and unpaid task, and returns a status_token. Next step: customer adds a payment method in the Taskquatch app before matching.",
        "x-muse-tool-class": "sensitive_write",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": { "type": "string", "format": "uuid" }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["code"],
                "properties": {
                  "code": {
                    "type": "string",
                    "pattern": "^[0-9]{6}$"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Submitted; needs payment method",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "request_id": { "type": "string" },
                    "status": {
                      "type": "string",
                      "enum": ["submitted_needs_payment_method"]
                    },
                    "status_token": { "type": "string" },
                    "continuation_url": { "type": "string", "format": "uri" },
                    "next_step": { "type": "string" },
                    "tool_class": {
                      "type": "string",
                      "enum": ["sensitive_write"]
                    }
                  }
                }
              }
            }
          },
          "400": { "description": "Incorrect code" },
          "410": { "description": "Code expired" },
          "429": { "description": "Too many attempts" }
        }
      }
    },
    "/task-requests/{id}": {
      "get": {
        "operationId": "getTaskRequestStatus",
        "summary": "Check task request status",
        "description": "Read. Requires status_token from verify. Maps internal task state to Muse-friendly statuses. There is no cancel endpoint in v1.",
        "x-muse-tool-class": "read",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": { "type": "string", "format": "uuid" }
          },
          {
            "name": "status_token",
            "in": "query",
            "required": true,
            "schema": { "type": "string" }
          }
        ],
        "responses": {
          "200": {
            "description": "Status",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "request_id": { "type": "string" },
                    "status": { "$ref": "#/components/schemas/TaskRequestStatus" },
                    "next_step": { "type": "string" },
                    "tool_class": { "type": "string", "enum": ["read"] }
                  }
                }
              }
            }
          },
          "403": { "description": "Invalid status_token" },
          "404": { "description": "Not found" }
        }
      }
    }
  },
  "x-rate-limits": {
    "requests_per_second": 20,
    "burst": 40,
    "daily_quota": 20000,
    "notes": "Dedicated Muse usage plan. Phone verification is capped separately (5 leads per phone per 24h)."
  },
  "x-service-area": {
    "region": "Middle Tennessee",
    "cities": [
      "Nashville",
      "Franklin",
      "Brentwood",
      "Hendersonville",
      "Murfreesboro",
      "Nolensville",
      "Spring Hill",
      "Mount Juliet"
    ]
  },
  "x-known-gap": "After verify, the customer must add a payment method in the Taskquatch app before a Taskquatcher is matched. Payment is captured after completion. Muse should report submitted_needs_payment_method, never booked, until that step is done."
}
