{"openapi":"3.1.0","jsonSchemaDialect":"https://json-schema.org/draft/2020-12/schema","info":{"title":"OfficeHubb AI Access","version":"1.0.0","summary":"Let a person's own AI assistant find an insurance agency and request a quote or service.","description":"Six actions for AI assistants acting for a person with an independent insurance agency on OfficeHubb. The same actions are an MCP server at https://www.officehubb.net/api/mcp.\n\nRules: a quote is not coverage; nothing is covered until a licensed agent takes an application and the policy is bound. Requests need the person's consent and the assistant's name. Texting consent cannot be given through an assistant. Social Security, driver license, Medicare, card and bank numbers are refused.\n\nHuman guide: https://www.officehubb.net/docs/ai-access","contact":{"name":"OfficeHubb support","url":"https://www.officehubb.net/contact"}},"servers":[{"url":"https://www.officehubb.net/api/ai-access/v1"}],"tags":[{"name":"Lookups","description":"Public facts. No consent needed."},{"name":"Requests","description":"Sends something to an agency. Needs the person's consent."}],"paths":{"/agencies":{"get":{"operationId":"find_agencies","summary":"Find insurance agencies","description":"Find independent insurance agencies on OfficeHubb that take requests from AI assistants, in a US state, optionally for one line of insurance, nearest first when a ZIP or city is given. Facts only, never a recommendation.","tags":["Lookups"],"responses":{"200":{"description":"The agencies, nearest first when a ZIP or city was given.","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"parameters":[{"name":"state","in":"query","required":true,"description":"Two-letter US state code where the person needs coverage, for example FL.","schema":{"type":"string","pattern":"^[A-Za-z]{2}$"}},{"name":"line","in":"query","required":false,"description":"The line of insurance: home, auto, flood, umbrella, renters, golf_cart, boat, motorcycle, life, medicare, healthcare or commercial.","schema":{"type":"string","enum":["home","auto","flood","umbrella","renters","golf_cart","boat","motorcycle","life","medicare","healthcare","commercial"]}},{"name":"zip","in":"query","required":false,"description":"Five-digit US ZIP code.","schema":{"type":"string","pattern":"^\\d{5}(-\\d{4})?$"}},{"name":"city","in":"query","required":false,"description":"City name, used to put nearby agencies first.","schema":{"type":"string","minLength":1,"maxLength":80}},{"name":"limit","in":"query","required":false,"description":"How many agencies to return, 1 to 25. Default 10.","schema":{"type":"integer","minimum":1,"maximum":25}}]}},"/agencies/{agency}":{"get":{"operationId":"get_agency_profile","summary":"Get an agency profile","description":"An agency's public facts: contact, license and how it was verified, the lines and carriers it writes, languages, office hours, whether quotes can be instant, and how soon an agent quotes when they are not.","tags":["Lookups"],"responses":{"200":{"description":"The agency profile (the same object /agency/{slug}/profile.json serves).","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"parameters":[{"name":"agency","in":"path","required":true,"description":"The agency slug, as find_agencies or the agency profile gives it.","schema":{"type":"string","minLength":1,"maxLength":120,"pattern":"^[A-Za-z0-9][A-Za-z0-9-]*$"}}]}},"/agencies/{agency}/fit":{"get":{"operationId":"check_fit","summary":"Check fit and get the questions","description":"Whether an agency writes a line in a state, whether a quote can be instant there (and if not, why), and the agency's own questions for that line with which ones are required. Call it before request_quote and ask the person those questions.","tags":["Lookups"],"responses":{"200":{"description":"Fit, instant quote availability with reason codes, and the agency's questions for the line.","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"parameters":[{"name":"agency","in":"path","required":true,"description":"The agency slug, as find_agencies or the agency profile gives it.","schema":{"type":"string","minLength":1,"maxLength":120,"pattern":"^[A-Za-z0-9][A-Za-z0-9-]*$"}},{"name":"line","in":"query","required":true,"description":"The line of insurance: home, auto, flood, umbrella, renters, golf_cart, boat, motorcycle, life, medicare, healthcare or commercial.","schema":{"type":"string","enum":["home","auto","flood","umbrella","renters","golf_cart","boat","motorcycle","life","medicare","healthcare","commercial"]}},{"name":"state","in":"query","required":false,"description":"Two-letter US state code, for example FL.","schema":{"type":"string","pattern":"^[A-Za-z]{2}$"}},{"name":"zip","in":"query","required":false,"description":"Five-digit US ZIP code.","schema":{"type":"string","pattern":"^\\d{5}(-\\d{4})?$"}}]}},"/quote-requests":{"post":{"operationId":"request_quote","summary":"Request a quote","description":"Send the person's quote request to the agency, with their answers to check_fit's questions, their consent and which assistant you are. Returns a request_id and whether quotes come instantly or an agent prepares them, with the reason and when. Only after the person agreed. Never send a Social Security, driver license, Medicare, card or bank number.","tags":["Requests"],"responses":{"200":{"description":"The request: request_id, mode (instant or agent), reason (no_rater, product_not_instant, missing_fields, outside_hours, agent_review or existing_client, with missing_fields listed), eta and status_url.","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"parameters":[{"name":"X-AI-Assistant","in":"header","required":false,"description":"Optional: the assistant as Name/version, for rate limits. The body's assistant object is what is stored.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"agency":{"type":"string","minLength":1,"maxLength":120,"pattern":"^[A-Za-z0-9][A-Za-z0-9-]*$","description":"The agency slug, as find_agencies or the agency profile gives it."},"product":{"type":"string","enum":["home","auto","flood","umbrella","renters","golf_cart","boat","motorcycle","life","medicare","healthcare","commercial"],"description":"The line of insurance: home, auto, flood, umbrella, renters, golf_cart, boat, motorcycle, life, medicare, healthcare or commercial."},"answers":{"type":"object","propertyNames":{"type":"string","minLength":1,"maxLength":80},"additionalProperties":{"anyOf":[{"type":"string","maxLength":500},{"type":"number"},{"type":"boolean"},{"maxItems":20,"type":"array","items":{"type":"string","maxLength":200}}]},"description":"The person's answers, keyed by the question keys check_fit returns for this line (full_name, phone, email, address, dob and the line's own questions). Never a Social Security, driver license, Medicare, card or bank number."},"notes":{"description":"Anything else the person asked to pass along to the agent, in their words.","type":"string","maxLength":1000},"assistant":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":80,"description":"The assistant product name, for example Claude."},"version":{"description":"The assistant or model version, when known.","type":"string","maxLength":40}},"required":["name"],"description":"Which AI assistant is relaying this request. Shown to the agency on the lead."},"consent":{"type":"object","properties":{"text":{"type":"string","minLength":20,"maxLength":2000,"description":"The exact words shown to the person before they agreed, for example the consent_text from check_fit."},"agreed":{"type":"boolean","description":"True only when the person said yes to that text. A request without a yes is refused."},"agreed_at":{"type":"string","minLength":10,"maxLength":40,"description":"When the person agreed, as an ISO 8601 time."}},"required":["text","agreed","agreed_at"],"description":"The person agreed to share these details with the agency so a licensed agent can contact them. Never covers texting: the person opts in to texts with the agency directly."},"idempotency_key":{"description":"Send the same key again to get the same request back instead of a second one.","type":"string","minLength":8,"maxLength":100}},"required":["agency","product","answers","assistant","consent"],"additionalProperties":{}}}}}}},"/quote-requests/{request_id}":{"get":{"operationId":"get_quote_status","summary":"Get quote status","description":"Where a request stands, by its request_id: the quotes once they exist, or when an agent will quote, and once the person picks a quote or the agent is working on it, the agent's direct contact. A quote is not coverage.","tags":["Lookups"],"responses":{"200":{"description":"Where the request stands: quotes once they exist, else when an agent will quote; the agent's contact at the application stage.","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"parameters":[{"name":"request_id","in":"path","required":true,"description":"The request_id that request_quote or request_service returned.","schema":{"type":"string","minLength":16,"maxLength":80,"pattern":"^[A-Za-z0-9_-]+$"}}]}},"/service-requests":{"post":{"operationId":"request_service","summary":"Request help with a policy","description":"For an existing client: send the agency a service request (ID cards, billing, a payment question, add or remove a car or driver, an address or lender change, a claim, documents). The office reaches out, usually the same business day. Only after the client agreed. Never send a Social Security, driver license, Medicare, card or bank number.","tags":["Requests"],"responses":{"200":{"description":"The service request: request_id and what happens next.","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"parameters":[{"name":"X-AI-Assistant","in":"header","required":false,"description":"Optional: the assistant as Name/version, for rate limits. The body's assistant object is what is stored.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"agency":{"type":"string","minLength":1,"maxLength":120,"pattern":"^[A-Za-z0-9][A-Za-z0-9-]*$","description":"The agency slug, as find_agencies or the agency profile gives it."},"name":{"type":"string","minLength":1,"maxLength":120,"description":"The client's full name, as on the policy."},"phone":{"description":"A phone number the office can call back. Phone or email is required.","type":"string","maxLength":40},"email":{"description":"An email address the office can write to. Phone or email is required.","type":"string","maxLength":200},"issue_description":{"type":"string","minLength":3,"maxLength":2000,"description":"What the client needs, in their words."},"service_type":{"description":"One of the service types (id_cards, billing, payment, claim, add_remove_vehicle, add_remove_driver, address_change, mortgagee_change, coverage_change, cancel_or_reinstate, documents, certificate, policy_review, vehicle_storage, household_change, document_submission, other). Left out, the office reads it from the description.","type":"string","maxLength":60},"policy_product":{"description":"Which policy: auto, home, flood and so on.","type":"string","maxLength":80},"policy_number":{"description":"The policy number, if the client has it handy.","type":"string","maxLength":60},"carrier":{"description":"The insurance company on the policy.","type":"string","maxLength":120},"date_that_matters":{"description":"A date that matters, in the client's words (a closing, a renewal, the date on a notice).","type":"string","maxLength":120},"urgent":{"description":"True when the client could be left without coverage or needs proof of insurance today.","type":"boolean"},"callback_preference":{"description":"How the client wants to hear back. Texting is not offered here: the client opts in to texts with the agency directly.","type":"string","enum":["call","email"]},"best_time":{"description":"When to reach the client.","type":"string","maxLength":120},"preferred_agent_name":{"description":"An agent the client asked for by name.","type":"string","maxLength":120},"language":{"description":"The language the client prefers.","type":"string","enum":["en","es"]},"assistant":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":80,"description":"The assistant product name, for example Claude."},"version":{"description":"The assistant or model version, when known.","type":"string","maxLength":40}},"required":["name"],"description":"Which AI assistant is relaying this request. Shown to the agency on the lead."},"consent":{"type":"object","properties":{"text":{"type":"string","minLength":20,"maxLength":2000,"description":"The exact words shown to the person before they agreed, for example the consent_text from check_fit."},"agreed":{"type":"boolean","description":"True only when the person said yes to that text. A request without a yes is refused."},"agreed_at":{"type":"string","minLength":10,"maxLength":40,"description":"When the person agreed, as an ISO 8601 time."}},"required":["text","agreed","agreed_at"],"description":"The person agreed to share these details with the agency so a licensed agent can contact them. Never covers texting: the person opts in to texts with the agency directly."},"idempotency_key":{"description":"Send the same key again to get the same request back instead of a second one.","type":"string","minLength":8,"maxLength":100}},"required":["agency","name","issue_description","assistant","consent"],"additionalProperties":{}}}}}}}},"components":{"schemas":{"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","enum":["invalid_input","too_large","not_found","actions_off","line_not_written","line_not_offered_here","missing_contact","consent_required","refused_sensitive_field","rate_limited","unavailable"]},"message":{"type":"string","description":"A plain sentence an assistant can pass on."},"fields":{"type":"array","items":{"type":"string"},"description":"The fields the error is about, when there are any."},"missing_fields":{"type":"array","items":{"type":"string"}},"retry_after_seconds":{"type":"integer"}},"additionalProperties":true}}}},"responses":{"Error":{"description":"A plain refusal with a code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}