{"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 and a trusted client IP. Always creates a DRAFT FunnelSession and emails the owner a request-bound verification code (status \"owner_verification_required\"). Only credential hashes and sent-at are stored on that exact session; concurrent requests cannot overwrite or authorize each other. The email discloses the service, location, project description, and exact selected Service Pros. No Opportunity is completed, no rescue workflow starts, and no Service Pro is contacted until the owner confirms via step 2. An empty contractorSlugs array records a pending no-coverage request that is routed to Boatwork only after owner verification. All created records carry source demand-side-search-mcp.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchMcpServiceRequestStart"}}}},"responses":{"201":{"description":"Draft created and owner verification email sent (status \"owner_verification_required\"); no Service Pro contacted.","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":{"get":{"tags":["Search MCP"],"summary":"Open the owner confirmation form","description":"Navigation-only email-link endpoint. Validates the exact request-bound token, then renders a script-free, no-store form showing the authoritative service, location, project description, and selected Service Pro names. GET never confirms or mutates a request. The owner must explicitly submit the form, which POSTs the token to the confirmation operation below.","parameters":[{"name":"requestId","in":"path","required":true,"schema":{"type":"string"}},{"name":"token","in":"query","required":true,"schema":{"type":"string","minLength":32}}],"responses":{"200":{"description":"Script-free explicit-confirmation form."},"307":{"description":"Missing token redirect."}}},"post":{"tags":["Search MCP"],"summary":"Confirm a Search MCP service request","description":"Public Search MCP transaction step 2. Requires a trusted client IP and the code/token hashed into this exact FunnelSession; a credential issued for another request is rejected. On success, promotes the draft, creates the owner Opportunity and per-pro RequestedQuote records, wires internal lifecycle events, and contacts only the bound selected pros through existing lead rails. For a verified no-coverage request, creates the zero-quote Opportunity and routes it to Boatwork coverage without contacting a pro. GET requests are navigation-only and never confirm or mutate a request.","parameters":[{"name":"requestId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchMcpServiceRequestConfirm"}}}},"responses":{"200":{"description":"Owner-verified request confirmed and opportunity/quotes created, or verified no-coverage request routed.","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 Search MCP Opportunity scoped by the owner access token from its verified request flow. Read credentials are accepted only in x-boatwork-owner-access-token or a non-public Bearer header, never in the URL. Access expires 90 days after completion.","parameters":[{"name":"x-boatwork-owner-access-token","in":"header","required":true,"schema":{"type":"string","pattern":"^[0-9a-fA-F]{64}$"},"description":"Search MCP owner capability. A non-public Bearer header is also accepted."}],"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":"x-boatwork-owner-access-token","in":"header","required":true,"schema":{"type":"string","pattern":"^[0-9a-fA-F]{64}$"}}],"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":"x-boatwork-owner-access-token","in":"header","required":true,"schema":{"type":"string","pattern":"^[0-9a-fA-F]{64}$"}}],"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":"x-boatwork-owner-access-token","in":"header","required":true,"schema":{"type":"string","pattern":"^[0-9a-fA-F]{64}$"}}],"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":0,"maxItems":3,"items":{"type":"string"},"description":"Selected eligible Service Pro slugs. An empty array means no coverage was found; owner verification is still required before Boatwork routes the request."},"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":"Always status \"owner_verification_required\" with a verification block. No Service Pro has been contacted.","properties":{"status":{"type":"string","enum":["owner_verification_required"]},"requestId":{"type":"string"},"source":{"type":"string","const":"demand-side-search-mcp"},"verification":{"type":"object","description":"Owner verification delivery and expiry details."},"selectedPros":{"type":"array","items":{"type":"object"},"description":"Selected pros; empty for the pending no-coverage path."}},"required":["status","requestId","source"]}},"required":["success","data"]},"SearchMcpServiceRequestConfirm":{"type":"object","description":"At least one owner-held credential, verificationCode or verificationToken, is required.","properties":{"verificationCode":{"type":"string","minLength":6},"verificationToken":{"type":"string","minLength":32}},"anyOf":[{"required":["verificationCode"]},{"required":["verificationToken"]}]},"SearchMcpServiceRequestConfirmResponse":{"type":"object","properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","properties":{"status":{"type":"string","enum":["created","no_coverage","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"]}]}}}}