{"openapi":"3.1.0","info":{"title":"Boatwork Public API","version":"1.0.0","description":"Programmatic access to Boatwork's contractor network and content. Built for partners, marketplace integrations, and AI agents indexing marine services.","contact":{"name":"Boatwork API","email":"support@boatwork.co","url":"https://developers.boatwork.co"},"license":{"name":"Boatwork API Terms","url":"https://developers.boatwork.co/terms"}},"servers":[{"url":"https://boatwork.co","description":"Production"},{"url":"https://developers.boatwork.co","description":"Developer portal (shares the same /api host)"}],"security":[{"bearer":[]},{}],"tags":[{"name":"Agents","description":"Self-registration + role discovery for AI agents."},{"name":"Contractors","description":"Search, retrieve, and explore marine contractor profiles."},{"name":"Search MCP","description":"Owner-consented, owner-verified request creation for the public Search MCP."},{"name":"Content","description":"Marine industry articles and blog posts."}],"paths":{"/api/agents/register":{"post":{"tags":["Agents"],"summary":"Register a new agent identity","description":"Public, no-auth. Creates a User with isAgent=true, mints an initial bw_public_* API key, returns the plaintext key ONCE. To upgrade to admin-tier (bw_live_*), ask the Boatwork admin to elevate the agent at /admin/agents/<id>.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"firstName":{"type":"string"},"lastName":{"type":"string"},"email":{"type":"string","format":"email"},"password":{"type":"string","minLength":10},"purpose":{"type":"string","description":"Optional — what this agent does."}},"required":["firstName","lastName","email","password"]}}}},"responses":{"200":{"description":"Agent created. Save the apiKey value immediately.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","properties":{"agent":{"type":"object","properties":{"id":{"type":"string"},"firstName":{"type":"string"},"lastName":{"type":"string"},"email":{"type":"string"},"isAdmin":{"type":"boolean"},"isAgent":{"type":"boolean"}}},"credentials":{"type":"object","properties":{"email":{"type":"string"},"apiKey":{"type":"string","example":"bw_public_abcdef1234567890"},"apiKeyPrefix":{"type":"string"},"apiBase":{"type":"string"},"howToUse":{"type":"string"}}}}}},"required":["success","data"]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"409":{"description":"A user with this email already exists."}}}},"/api/account/me":{"get":{"tags":["Agents"],"summary":"Get current user role + capabilities","description":"Returns the signed-in user, including isAgent, isAdmin, and a canMintAdminKeys convenience flag. Returns data:null if unauthenticated. Use to poll for admin elevation after registration.","responses":{"200":{"description":"Current user (or null if unauthenticated).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"data":{"oneOf":[{"type":"null"},{"type":"object","properties":{"id":{"type":"string"},"firstName":{"type":"string"},"lastName":{"type":"string"},"email":{"type":"string"},"isAdmin":{"type":"boolean"},"isAgent":{"type":"boolean"},"canMintAdminKeys":{"type":"boolean"}}}]}},"required":["success"]}}}}}}},"/api/v1/public/contractors/search":{"get":{"tags":["Contractors"],"summary":"Search contractors","description":"Keyword + filter search across the contractor network. Supports specialty, city, state filters.","parameters":[{"name":"q","in":"query","schema":{"type":"string"},"description":"Free-text query (matches name, services, marina)."},{"name":"specialty","in":"query","schema":{"type":"string"},"description":"Specialty slug (see /specialties)."},{"name":"city","in":"query","schema":{"type":"string"}},{"name":"state","in":"query","schema":{"type":"string","minLength":2,"maxLength":2},"description":"US state code (2 letters)."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}},{"name":"cursor","in":"query","schema":{"type":"string"},"description":"Opaque cursor returned by the previous page."}],"responses":{"200":{"description":"Paginated contractor result.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContractorPage"}}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/public/contractors/geo-search":{"get":{"tags":["Contractors"],"summary":"Geo-radius contractor search","description":"Find contractors within a radius of a latitude/longitude.","parameters":[{"name":"lat","in":"query","required":true,"schema":{"type":"number","format":"double"}},{"name":"lng","in":"query","required":true,"schema":{"type":"number","format":"double"}},{"name":"radiusMiles","in":"query","schema":{"type":"number","minimum":1,"maximum":250,"default":25}},{"name":"specialty","in":"query","schema":{"type":"string"}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}],"responses":{"200":{"description":"Contractors sorted by distance ascending.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContractorPage"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/public/contractors/specialties":{"get":{"tags":["Contractors"],"summary":"List specialties","description":"Every marine service specialty available across the network.","responses":{"200":{"description":"Array of specialty descriptors.","content":{"application/json":{"schema":{"type":"object","properties":{"specialties":{"type":"array","items":{"type":"object","properties":{"slug":{"type":"string","example":"hull-cleaning"},"label":{"type":"string","example":"Hull Cleaning"},"contractorCount":{"type":"integer"}},"required":["slug","label","contractorCount"]}}},"required":["specialties"]}}}}}}},"/api/v1/public/contractors/{slug}":{"get":{"tags":["Contractors"],"summary":"Get contractor profile by slug","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Full contractor profile.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Contractor"}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api/v1/public/contractors/by-id/{id}":{"get":{"tags":["Contractors"],"summary":"Get contractor profile by id","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Full contractor profile.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Contractor"}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api/v1/public/search-mcp/service-requests":{"post":{"tags":["Search MCP"],"summary":"Start a Search MCP service request","description":"Public Search MCP transaction step 1. Requires explicit owner consent. Behavior depends on the owner-verification toggle. With the toggle OFF (default): the Opportunity and per-pro RequestedQuote records are created and the selected pros are contacted immediately — the response status is \"created\", no code is emailed and no confirm step is required. With the toggle ON: a DRAFT FunnelSession is created and a verification code is emailed to the owner (status \"owner_verification_required\") — no Opportunity is created and no pros are contacted until the owner confirms via step 2. All created records carry source demand-side-search-mcp.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchMcpServiceRequestStart"}}}},"responses":{"201":{"description":"Toggle OFF (default): Opportunity created and selected pros contacted (status \"created\"). Toggle ON: draft created and owner verification email sent (status \"owner_verification_required\").","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchMcpServiceRequestStartResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/public/search-mcp/service-requests/{requestId}/confirm":{"post":{"tags":["Search MCP"],"summary":"Confirm a Search MCP service request","description":"Public Search MCP transaction step 2. With the owner-verification toggle ON, requires the owner verification code/token sent by email. With the toggle OFF (default), the code/token is optional and confirm is idempotent: if step 1 already created the Opportunity it returns the existing records (status \"already_confirmed\"). On success, promotes the draft, creates the owner Opportunity and per-pro RequestedQuote records, wires internal lifecycle events, and contacts selected pros through existing lead rails. Created records carry source demand-side-search-mcp.","parameters":[{"name":"requestId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchMcpServiceRequestConfirm"}}}},"responses":{"200":{"description":"Request confirmed and opportunity/quotes created, or already confirmed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchMcpServiceRequestConfirmResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"description":"Invalid verification code or token."},"404":{"$ref":"#/components/responses/NotFound"},"410":{"description":"Verification or request draft expired."},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/public/search-mcp/owner/opportunities":{"get":{"tags":["Search MCP"],"summary":"List owner-verified Opportunities","description":"Returns the single Opportunity scoped by the owner access token from the verified request email/recovery flow. The token can be supplied as ownerAccessToken, x-boatwork-owner-access-token, or a non-public Bearer token.","parameters":[{"name":"ownerAccessToken","in":"query","schema":{"type":"string"},"description":"Owner-scoped recovery token."}],"responses":{"200":{"description":"Owner-scoped Opportunity list.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchMcpOwnerOpportunityListResponse"}}}},"401":{"description":"Missing owner access token."},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api/v1/public/search-mcp/owner/opportunities/{opportunityId}":{"get":{"tags":["Search MCP"],"summary":"Read an owner Opportunity","parameters":[{"name":"opportunityId","in":"path","required":true,"schema":{"type":"string"}},{"name":"ownerAccessToken","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Owner-scoped Opportunity detail.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchMcpOwnerOpportunityResponse"}}}},"401":{"description":"Missing owner access token."},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api/v1/public/search-mcp/owner/opportunities/{opportunityId}/status":{"get":{"tags":["Search MCP"],"summary":"Track Opportunity status across pros","parameters":[{"name":"opportunityId","in":"path","required":true,"schema":{"type":"string"}},{"name":"ownerAccessToken","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Per-pro Opportunity status.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchMcpOwnerStatusResponse"}}}},"401":{"description":"Missing owner access token."},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api/v1/public/search-mcp/owner/opportunities/{opportunityId}/messages":{"post":{"tags":["Search MCP"],"summary":"Message a pro as the verified owner","description":"Confirm-gated write. Without confirm:true the API returns a 202 preview and performs no write.","parameters":[{"name":"opportunityId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchMcpOwnerMessageRequest"}}}},"responses":{"200":{"description":"Message sent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchMcpOwnerWriteResponse"}}}},"202":{"description":"Confirmation required; no write performed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchMcpOwnerConfirmationPreview"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"description":"Missing owner access token."},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api/v1/public/search-mcp/owner/opportunities/{opportunityId}/missing-info":{"post":{"tags":["Search MCP"],"summary":"Answer a pro missing-info request","description":"Confirm-gated write. Sends structured owner answers into the pro thread after confirm:true.","parameters":[{"name":"opportunityId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchMcpOwnerMissingInfoRequest"}}}},"responses":{"200":{"description":"Answers sent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchMcpOwnerWriteResponse"}}}},"202":{"description":"Confirmation required; no write performed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchMcpOwnerConfirmationPreview"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"description":"Missing owner access token."},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api/v1/public/search-mcp/owner/opportunities/{opportunityId}/visit-options":{"get":{"tags":["Search MCP"],"summary":"Review proposed visit options","parameters":[{"name":"opportunityId","in":"path","required":true,"schema":{"type":"string"}},{"name":"ownerAccessToken","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Proposed visit options for the verified owner.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchMcpOwnerVisitOptionsResponse"}}}},"401":{"description":"Missing owner access token."},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api/v1/public/search-mcp/owner/opportunities/{opportunityId}/select-visit-time":{"post":{"tags":["Search MCP"],"summary":"Select a proposed visit time","description":"Confirm-gated write. selectedTime must match one of the pro-proposed ISO datetime options.","parameters":[{"name":"opportunityId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchMcpOwnerSelectVisitTimeRequest"}}}},"responses":{"200":{"description":"Visit time selected.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchMcpOwnerWriteResponse"}}}},"202":{"description":"Confirmation required; no write performed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchMcpOwnerConfirmationPreview"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"description":"Missing owner access token."},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api/v1/public/search-mcp/owner/opportunities/{opportunityId}/accept-estimate":{"post":{"tags":["Search MCP"],"summary":"Accept an estimate","description":"Confirm-gated write. Accepting an estimate awards the work to that pro and closes the Opportunity to other submitted estimates.","parameters":[{"name":"opportunityId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchMcpOwnerAcceptEstimateRequest"}}}},"responses":{"200":{"description":"Estimate accepted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchMcpOwnerWriteResponse"}}}},"202":{"description":"Confirmation required; no write performed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchMcpOwnerConfirmationPreview"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"description":"Missing owner access token."},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api/v1/public/search-mcp/owner/opportunities/{opportunityId}/mark-complete":{"post":{"tags":["Search MCP"],"summary":"Mark awarded work complete","description":"Confirm-gated write. Only the accepted pro thread can be completed by the owner token.","parameters":[{"name":"opportunityId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchMcpOwnerQuoteWriteRequest"}}}},"responses":{"200":{"description":"Work marked complete.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchMcpOwnerWriteResponse"}}}},"202":{"description":"Confirmation required; no write performed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchMcpOwnerConfirmationPreview"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"description":"Missing owner access token."},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api/v1/public/search-mcp/owner/opportunities/{opportunityId}/review":{"post":{"tags":["Search MCP"],"summary":"Leave a review for the accepted pro","description":"Confirm-gated write. The review is linked to the awarded quote and flows to the pro profile.","parameters":[{"name":"opportunityId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchMcpOwnerReviewRequest"}}}},"responses":{"200":{"description":"Review created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchMcpOwnerWriteResponse"}}}},"202":{"description":"Confirmation required; no write performed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchMcpOwnerConfirmationPreview"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"description":"Missing owner access token."},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Review already exists."}}}},"/api/v1/public/articles":{"get":{"tags":["Content"],"summary":"List published articles","parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}},{"name":"cursor","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Paginated article list.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArticlePage"}}}}}}},"/api/v1/public/blog":{"get":{"tags":["Content"],"summary":"List blog posts","parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}},{"name":"cursor","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Paginated blog post list.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlogPage"}}}}}}}},"components":{"securitySchemes":{"bearer":{"type":"http","scheme":"bearer","bearerFormat":"bw_public_*","description":"Public API key minted at /developers/api-keys. Required for higher rate limits; anonymous reads are allowed but throttled."}},"responses":{"BadRequest":{"description":"Invalid request — see body for details.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"error":{"type":"string"}},"required":["success","error"]}}}},"NotFound":{"description":"Resource not found.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"error":{"type":"string"}},"required":["success","error"]}}}},"Unauthorized":{"description":"Missing or invalid Authorization header.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"error":{"type":"string"}},"required":["success","error"]}}}},"Forbidden":{"description":"Authenticated but lacks the required scope.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"error":{"type":"string"}},"required":["success","error"]}}}},"RateLimited":{"description":"Rate limit exceeded. Retry after the value in the `Retry-After` header.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"error":{"type":"string"}},"required":["success","error"]}}}}},"schemas":{"Contractor":{"type":"object","properties":{"id":{"type":"string"},"slug":{"type":"string"},"name":{"type":"string"},"city":{"type":"string","nullable":true},"state":{"type":"string","nullable":true},"latitude":{"type":"number","format":"double","nullable":true},"longitude":{"type":"number","format":"double","nullable":true},"specialties":{"type":"array","items":{"type":"string"}},"rating":{"type":"number","nullable":true},"reviewCount":{"type":"integer"},"phone":{"type":"string","nullable":true},"website":{"type":"string","nullable":true}},"required":["id","slug","name","specialties","reviewCount"]},"ContractorPage":{"type":"object","properties":{"contractors":{"type":"array","items":{"$ref":"#/components/schemas/Contractor"}},"nextCursor":{"type":"string","nullable":true}},"required":["contractors"]},"Article":{"type":"object","properties":{"id":{"type":"string"},"slug":{"type":"string"},"title":{"type":"string"},"excerpt":{"type":"string","nullable":true},"publishedAt":{"type":"string","format":"date-time"},"url":{"type":"string"}},"required":["id","slug","title","publishedAt","url"]},"ArticlePage":{"type":"object","properties":{"articles":{"type":"array","items":{"$ref":"#/components/schemas/Article"}},"nextCursor":{"type":"string","nullable":true}},"required":["articles"]},"BlogPost":{"$ref":"#/components/schemas/Article"},"BlogPage":{"type":"object","properties":{"posts":{"type":"array","items":{"$ref":"#/components/schemas/BlogPost"}},"nextCursor":{"type":"string","nullable":true}},"required":["posts"]},"SearchMcpServiceRequestStart":{"type":"object","properties":{"owner":{"type":"object","properties":{"firstName":{"type":"string"},"lastName":{"type":"string"},"email":{"type":"string","format":"email"},"phone":{"type":"string"}},"required":["firstName","email"]},"project":{"type":"object","properties":{"specialtySlug":{"type":"string","example":"boat-mechanics-engine-repair"},"location":{"type":"string","example":"Fort Lauderdale, FL"},"description":{"type":"string","minLength":20}},"required":["specialtySlug","location","description"]},"contractorSlugs":{"type":"array","minItems":1,"maxItems":3,"items":{"type":"string"}},"ownerConsent":{"type":"object","properties":{"confirmed":{"type":"boolean","const":true},"statement":{"type":"string"}},"required":["confirmed"]},"clientRequestId":{"type":"string"}},"required":["owner","project","contractorSlugs","ownerConsent"]},"SearchMcpServiceRequestStartResponse":{"type":"object","properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","description":"Toggle OFF (default): status \"created\" with the per-pro quotes (no verification block). Toggle ON: status \"owner_verification_required\" with a verification block and selectedPros.","properties":{"status":{"type":"string","enum":["owner_verification_required","created","already_confirmed"]},"requestId":{"type":"string"},"opportunityId":{"type":"string"},"source":{"type":"string","const":"demand-side-search-mcp"},"verification":{"type":"object","description":"Present only when the owner-verification toggle is ON."},"selectedPros":{"type":"array","items":{"type":"object"},"description":"Present only when the owner-verification toggle is ON."},"quotes":{"type":"array","description":"Present when the toggle is OFF and the Opportunity was created immediately.","items":{"type":"object"}}},"required":["status","requestId","source"]}},"required":["success","data"]},"SearchMcpServiceRequestConfirm":{"type":"object","description":"With the owner-verification toggle ON a verificationCode or verificationToken is required. With the toggle OFF (default) both are optional and confirm is idempotent.","properties":{"verificationCode":{"type":"string","minLength":6},"verificationToken":{"type":"string","minLength":32}}},"SearchMcpServiceRequestConfirmResponse":{"type":"object","properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","properties":{"status":{"type":"string","enum":["created","already_confirmed"]},"requestId":{"type":"string"},"opportunityId":{"type":"string"},"source":{"type":"string","const":"demand-side-search-mcp"},"quotes":{"type":"array","items":{"type":"object","properties":{"quoteId":{"type":"string"},"contractorSlug":{"type":"string"},"contractorName":{"type":"string"},"opportunityId":{"type":"string"},"threadStatus":{"type":"string"}},"required":["quoteId","contractorSlug","contractorName","opportunityId","threadStatus"]}}},"required":["status","requestId","opportunityId","source","quotes"]}},"required":["success","data"]},"SearchMcpOwnerOpportunity":{"type":"object","properties":{"opportunityId":{"type":"string"},"status":{"type":"string","enum":["waiting_on_pros","needs_owner_info","visit_options","quoted","closed","awarded","completed","reviewed"]},"owner":{"type":"object"},"project":{"type":"object"},"pros":{"type":"array","items":{"type":"object","properties":{"quoteId":{"type":"string"},"contractorId":{"type":"string"},"contractorSlug":{"type":"string"},"contractorName":{"type":"string"},"quoteStatus":{"type":"string"},"threadStatus":{"type":"string","nullable":true},"conversation":{"type":["object","null"]},"estimates":{"type":"array","items":{"type":"object"}},"visits":{"type":"array","items":{"type":"object"}},"review":{"type":["object","null"]}},"required":["quoteId","contractorId","contractorSlug","contractorName","quoteStatus","estimates","visits"]}}},"required":["opportunityId","status","owner","project","pros"]},"SearchMcpOwnerOpportunityListResponse":{"type":"object","properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","properties":{"opportunities":{"type":"array","items":{"$ref":"#/components/schemas/SearchMcpOwnerOpportunity"}},"ownerAccessScope":{"type":"string","const":"single_opportunity"}},"required":["opportunities","ownerAccessScope"]}},"required":["success","data"]},"SearchMcpOwnerOpportunityResponse":{"type":"object","properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/SearchMcpOwnerOpportunity"}},"required":["success","data"]},"SearchMcpOwnerStatusResponse":{"type":"object","properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","properties":{"opportunityId":{"type":"string"},"status":{"type":"string"},"pros":{"type":"array","items":{"type":"object"}}},"required":["opportunityId","status","pros"]}},"required":["success","data"]},"SearchMcpOwnerVisitOptionsResponse":{"type":"object","properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","properties":{"opportunityId":{"type":"string"},"visits":{"type":"array","items":{"type":"object"}}},"required":["opportunityId","visits"]}},"required":["success","data"]},"SearchMcpOwnerConfirmationPreview":{"type":"object","properties":{"success":{"type":"boolean","const":true},"confirmationRequired":{"type":"boolean","const":true},"writesPerformed":{"type":"boolean","const":false},"action":{"type":"string"},"detail":{"type":"object"}},"required":["success","confirmationRequired","writesPerformed","action","detail"]},"SearchMcpOwnerWriteResponse":{"type":"object","properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","properties":{"opportunityId":{"type":"string"}},"required":["opportunityId"]}},"required":["success","data"]},"SearchMcpOwnerQuoteWriteRequest":{"type":"object","properties":{"ownerAccessToken":{"type":"string"},"quoteId":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true to perform the write; omitted/false returns a no-write preview."}},"required":["quoteId"]},"SearchMcpOwnerMessageRequest":{"allOf":[{"$ref":"#/components/schemas/SearchMcpOwnerQuoteWriteRequest"},{"type":"object","properties":{"content":{"type":"string","minLength":1,"maxLength":5000}},"required":["content"]}]},"SearchMcpOwnerMissingInfoRequest":{"allOf":[{"$ref":"#/components/schemas/SearchMcpOwnerQuoteWriteRequest"},{"type":"object","properties":{"answers":{"type":"array","minItems":1,"maxItems":20,"items":{"type":"string","minLength":1,"maxLength":1000}}},"required":["answers"]}]},"SearchMcpOwnerSelectVisitTimeRequest":{"allOf":[{"$ref":"#/components/schemas/SearchMcpOwnerQuoteWriteRequest"},{"type":"object","properties":{"visitId":{"type":"string"},"selectedTime":{"type":"string","format":"date-time"}},"required":["visitId","selectedTime"]}]},"SearchMcpOwnerAcceptEstimateRequest":{"type":"object","properties":{"ownerAccessToken":{"type":"string"},"estimateId":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true to perform the write; omitted/false returns a no-write preview."}},"required":["estimateId"]},"SearchMcpOwnerReviewRequest":{"allOf":[{"$ref":"#/components/schemas/SearchMcpOwnerQuoteWriteRequest"},{"type":"object","properties":{"rating":{"type":"number","minimum":1,"maximum":5},"review":{"type":"string","minLength":3,"maxLength":2000}},"required":["rating","review"]}]}}}}