{
  "openapi": "3.1.0",
  "info": {
    "title": "HealthSherpa Public API",
    "version": "0.1.0",
    "description": "Machine-readable contract for the currently available public HealthSherpa endpoints: GET /v1/ping, GET /v1/reference/counties, GET /v1/reference/issuers, POST /v1/quotes, and the approval-gated POST /v1/enrollment-sessions. Object schemas remain additive and clients should ignore response fields they do not recognize.\n\nAll error responses follow the unified `ErrorResponse` schema: `{ \"error\": { \"code\": string, \"message\": string, \"details\"?: object } }`. Bodies returned by the infrastructure layer use the same shape as bodies returned by the backend."
  },
  "servers": [
    {
      "url": "https://api.one.healthsherpa.com",
      "description": "Production"
    }
  ],
  "tags": [
    {
      "name": "Utility"
    },
    {
      "name": "Reference"
    },
    {
      "name": "Quotes"
    },
    {
      "name": "Enrollment Sessions"
    }
  ],
  "security": [
    {
      "ApiKeyAuth": []
    }
  ],
  "paths": {
    "/v1/ping": {
      "get": {
        "tags": [
          "Utility"
        ],
        "summary": "Confirm API reachability and key validity",
        "operationId": "ping",
        "responses": {
          "200": {
            "description": "API request reached the partner API edge and the supplied API key was accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PingResponse"
                },
                "example": {
                  "environment": "production",
                  "ok": true
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          },
          "504": {
            "$ref": "#/components/responses/GatewayTimeout"
          }
        }
      }
    },
    "/v1/reference/counties": {
      "get": {
        "tags": [
          "Reference"
        ],
        "summary": "List counties for a ZIP code",
        "description": "Returns the counties that overlap the supplied ZIP code. Use the selected fips_code in subsequent quote requests.",
        "operationId": "listCounties",
        "parameters": [
          {
            "name": "zip_code",
            "in": "query",
            "required": true,
            "description": "Five-digit ZIP code to resolve.",
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{5}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One or more counties found for the ZIP code.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CountiesResponse"
                },
                "example": {
                  "counties": [
                    {
                      "fips_code": "12086",
                      "name": "Miami-Dade County",
                      "state": "FL"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          },
          "504": {
            "$ref": "#/components/responses/GatewayTimeout"
          }
        }
      }
    },
    "/v1/reference/issuers": {
      "get": {
        "tags": [
          "Reference"
        ],
        "summary": "List QHP issuers active in a state",
        "description": "Returns the QHP issuers active in the requested state and plan year. Each entry combines a sortable display name (issuer marketing name when present, legal name otherwise) with the canonical 5-digit HIOS issuer ID for use in subsequent quote filters.\n\n**Plan year:** the optional `plan_year` query parameter pins the lookup to a specific year and defaults to the current ACA plan year (open enrollment for 2027 begins November 1 2026). Specify `plan_year` explicitly when reconciling enrollments from a prior year or when shopping the next year before the rollover.\n\n**Response ordering:** entries are sorted by `name` (case-insensitive) and then by `hios_issuer_id` as a stable tiebreaker. Clients can iterate the array directly without re-sorting.",
        "operationId": "listIssuers",
        "parameters": [
          {
            "name": "state",
            "in": "query",
            "required": true,
            "description": "Two-letter uppercase US state code (e.g. `FL`). Lowercase values are rejected with `400 invalid_request` — clients must upcase before sending.",
            "example": "FL",
            "schema": {
              "type": "string",
              "pattern": "^[A-Z]{2}$"
            }
          },
          {
            "name": "plan_year",
            "in": "query",
            "required": false,
            "description": "ACA plan year to scope the issuer list to. Defaults to the current ACA plan year when omitted.",
            "schema": {
              "type": "integer",
              "minimum": 2020,
              "maximum": 2099
            },
            "example": 2026
          }
        ],
        "responses": {
          "200": {
            "description": "One or more issuers found for the state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IssuersResponse"
                },
                "example": {
                  "issuers": [
                    {
                      "name": "Gulf Coast Coverage Co.",
                      "hios_issuer_id": "33333"
                    },
                    {
                      "name": "Sunshine State Health",
                      "hios_issuer_id": "12345"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          },
          "504": {
            "$ref": "#/components/responses/GatewayTimeout"
          }
        }
      }
    },
    "/v1/quotes": {
      "post": {
        "tags": [
          "Quotes"
        ],
        "summary": "Search plans for one coverage type",
        "description": "Returns a homogeneous list of quote results for exactly one coverage_type. Send one request for one market and one coverage_type at a time.",
        "operationId": "createQuote",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/QuoteRequest"
              },
              "example": {
                "context": {
                  "product": "aca",
                  "exchange": "on_exchange",
                  "coverage_family": "medical",
                  "coverage_type": "medical",
                  "plan_year": 2026
                },
                "location": {
                  "zip_code": "30301",
                  "fips_code": "13121",
                  "state": "GA"
                },
                "household": {
                  "household_size": 1,
                  "annual_income": 52000,
                  "effective_date": "2026-05-01",
                  "applicants": [
                    {
                      "member_id": "primary",
                      "age": 40,
                      "date_of_birth": "1986-05-01",
                      "relationship": "primary",
                      "uses_tobacco": false,
                      "pregnant": false,
                      "blind_or_disabled": false,
                      "native_american": false
                    }
                  ]
                },
                "sort": {
                  "field": "premium",
                  "direction": "asc"
                },
                "page": {
                  "number": 1,
                  "size": 20
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Quotes returned successfully.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/QuoteResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          },
          "504": {
            "$ref": "#/components/responses/GatewayTimeout"
          }
        }
      }
    },
    "/v1/enrollment-sessions": {
      "post": {
        "tags": [
          "Enrollment Sessions"
        ],
        "summary": "Start an enrollment session",
        "description": "Returns URLs to continue enrollment in a browser-mediated HealthSherpa flow. This endpoint always returns deep links and does not create downstream application records.\n\nBoth agent-assisted and consumer self-service use cases are supported. Set `context.flow` to `agent_assisted` for an agent walking a client through enrollment, or to `self_service` for a consumer enrolling themselves. The `campaign.*` block and the top-level `plan_id` field are only accepted in self-service flows.\n\nThe entire `context` object and every field inside it is required so partners declare product, exchange, coverage, plan year, flow, and locale on every request rather than relying on hidden defaults. In `self_service`, supply at least one of `location.state` or top-level `plan_id`. In `agent_assisted`, `location.state` is required.",
        "operationId": "createEnrollmentSession",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Optional partner-supplied request identifier (1–255 chars, `A-Z`, `a-z`, `0-9`, `-`, `_`). Scoped by API key and retained for 24 hours.\n\n- First call: processed normally; the response is captured.\n- Replay (same key + same body): returns the original response verbatim with `Idempotent-Replay: true`.\n- Same key + different body: `422 idempotency_mismatch`.\n- Concurrent retry while the first call is still in flight: `409 idempotency_in_progress`.\n- `429` responses are not stored, so partners can back off and retry transparently.\n- `5xx` responses **are** stored. Because the upstream service does not natively deduplicate, retrying a 5xx with the same Idempotency-Key would risk creating duplicate downstream records. Partners who believe a 5xx was transient must generate a fresh Idempotency-Key to retry.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_\\-]{1,255}$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EnrollmentSessionRequest"
              },
              "example": {
                "external_id": "crm-lead-abc-123",
                "context": {
                  "product": "aca",
                  "exchange": "on_exchange",
                  "coverage_family": "medical",
                  "coverage_type": "medical",
                  "plan_year": 2026,
                  "flow": "self_service",
                  "locale": "en-US"
                },
                "plan_id": "12345NY0010001",
                "location": {
                  "zip_code": "10001",
                  "fips_code": "36061",
                  "state": "NY"
                },
                "household": {
                  "annual_income": 42000,
                  "household_size": 1,
                  "applicants": [
                    {
                      "relationship": "primary",
                      "first_name": "Jane",
                      "last_name": "Doe",
                      "email": "jane@example.com",
                      "phone_number": "5551234567",
                      "date_of_birth": "1990-01-01",
                      "sex": "female",
                      "uses_tobacco": false
                    }
                  ]
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Enrollment session started successfully.",
            "headers": {
              "X-Request-Id": {
                "description": "HealthSherpa ONE request id for tracing and support.",
                "schema": {
                  "type": "string"
                }
              },
              "Idempotent-Replay": {
                "description": "Present and set to `true` only when this response is being replayed from a prior call that supplied the same `Idempotency-Key` and request body.",
                "schema": {
                  "type": "string",
                  "enum": [ "true" ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EnrollmentSessionResponse"
                },
                "example": {
                  "external_id": "crm-lead-abc-123",
                  "links": {
                    "shopping_url": "https://healthsherpa.com/public/shop?_agent_id=agent_admin_42&external_id=crm-lead-abc-123&fip_code=36061&household_income=42000&household_size=1&people%5Bprimary%5D%5Bage%5D=36&people%5Bprimary%5D%5Bgender%5D=female&people%5Bprimary%5D%5Btobacco%5D=false&state=NY&user_type=consumer&year=2026&zip_code=10001",
                    "client_apply_url": "https://healthsherpa.com/public/apply?_agent_id=agent_admin_42&external_id=crm-lead-abc-123&fip_code=36061&household_income=42000&household_size=1&people%5Bprimary%5D%5Bage%5D=36&people%5Bprimary%5D%5Bgender%5D=female&people%5Bprimary%5D%5Btobacco%5D=false&plan_hios_id=12345NY0010001&state=NY&user_type=consumer&year=2026&zip_code=10001"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "Returned when this API key is not authorized to call this endpoint, or when the developer's HealthSherpa Marketplace setup is not in the state the requested flow needs.\n\n- `context.flow = \"agent_assisted\"` requires a healthy HealthSherpa Marketplace OAuth link (account approved, integration `active`, on-exchange capability `ready`, and the access token unexpired or refreshable).\n- `context.flow = \"self_service\"` requires approved D2C deep-link access (`d2cDeepLinkApiRequestApprovalStatus = \"approved\"`) and a configured deeplink agent ID.\n\nThe self-service gate does not consult the OAuth link, and the agent-assisted gate does not consult the D2C/deeplink configuration. Each flow only fails when the gate it actually uses is not satisfied.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This API key is not authorized to access this endpoint."
                  }
                }
              }
            }
          },
          "409": {
            "$ref": "#/components/responses/IdempotencyInProgress"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          },
          "422": {
            "$ref": "#/components/responses/IdempotencyMismatch"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          },
          "504": {
            "$ref": "#/components/responses/GatewayTimeout"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiKeyAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "x-api-key"
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Request validation failed. The response body's `error.details` map contains per-field messages when the backend produced the error; edge-generated 400s omit `details`.\n\nA malformed `Idempotency-Key` header is also rejected here with `code: idempotency_key_invalid`.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "error": {
                "code": "invalid_request",
                "message": "Validation failed.",
                "details": {
                  "zip_code": ["ZIP code must be 5 digits"]
                }
              }
            }
          }
        }
      },
      "IdempotencyInProgress": {
        "description": "A previous request with the same `Idempotency-Key` is still being processed by the API. The partner should wait briefly and retry. The response is not produced by the upstream service — the in-flight request from the first call will succeed or fail on its own.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "error": {
                "code": "idempotency_in_progress",
                "message": "A request with this Idempotency-Key is already being processed. Retry once it completes."
              }
            }
          }
        }
      },
      "IdempotencyMismatch": {
        "description": "The `Idempotency-Key` has been used before within the 24-hour retention window, but the current request body is not byte-for-byte identical to the original. To resolve, either resubmit the exact original payload or generate a fresh `Idempotency-Key` for the new request.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "error": {
                "code": "idempotency_mismatch",
                "message": "This Idempotency-Key has already been used with a different request body."
              }
            }
          }
        }
      },
      "Forbidden": {
        "description": "The API key is missing, invalid, not authorized for this API, or the request was blocked at the API edge. Public API requests may receive this edge-generated response before the backend can return a runtime 401. When a request reaches the backend, 403 may also mean the developer account or integration is not in the state required for that operation. For `POST /v1/enrollment-sessions`, that operation documents its own flow-scoped 403 requirements (`agent_assisted` OAuth link vs `self_service` deep-link configuration) instead of using this shared response reference.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "error": {
                "code": "forbidden",
                "message": "The supplied API key is missing, invalid, or not authorized for this API."
              }
            }
          }
        }
      },
      "NotFound": {
        "description": "The requested resource could not be found. Emitted by the backend when no supported data matches the request (for example, no counties for a ZIP), and by the API edge for unknown paths.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "error": {
                "code": "not_found",
                "message": "No counties found for ZIP 12345."
              }
            }
          }
        }
      },
      "PayloadTooLarge": {
        "description": "The request body exceeded the maximum size accepted by the API edge.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "error": {
                "code": "payload_too_large",
                "message": "The request payload exceeded the maximum allowed size."
              }
            }
          }
        }
      },
      "UnsupportedMediaType": {
        "description": "The request `Content-Type` is not supported by the endpoint.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "error": {
                "code": "unsupported_media_type",
                "message": "The request Content-Type is not supported by this endpoint."
              }
            }
          }
        }
      },
      "RateLimited": {
        "description": "Rate limit exceeded. Clients should back off and retry after the delay advertised in the Retry-After header.",
        "headers": {
          "Retry-After": {
            "description": "Number of seconds the client should wait before retrying.",
            "schema": {
              "type": "integer"
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "error": {
                "code": "rate_limited",
                "message": "Request rate limit exceeded. Please slow down and retry shortly."
              }
            }
          }
        }
      },
      "InternalError": {
        "description": "An unexpected error occurred.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "error": {
                "code": "internal_error",
                "message": "An unexpected error occurred."
              }
            }
          }
        }
      },
      "BadGateway": {
        "description": "The API edge received an invalid response from the backend.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "error": {
                "code": "bad_gateway",
                "message": "The API edge received an invalid response from the backend. Please try again later."
              }
            }
          }
        }
      },
      "ServiceUnavailable": {
        "description": "The API is temporarily unable to serve the request. This may be returned by the API edge when the backend is unhealthy, or by the backend when an upstream catalog, quoting, or lookup service is unavailable.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "error": {
                "code": "service_unavailable",
                "message": "The service is temporarily unavailable. Please try again later."
              }
            }
          }
        }
      },
      "GatewayTimeout": {
        "description": "The API edge did not receive a timely response from the backend.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "error": {
                "code": "gateway_timeout",
                "message": "The API edge did not receive a timely response from the backend. Please try again later."
              }
            }
          }
        }
      }
    },
    "schemas": {
      "PingResponse": {
        "type": "object",
        "additionalProperties": true,
        "required": [
          "environment",
          "ok"
        ],
        "properties": {
          "environment": {
            "type": "string"
          },
          "ok": {
            "type": "boolean"
          }
        }
      },
      "CountySummary": {
        "type": "object",
        "additionalProperties": true,
        "required": [
          "fips_code",
          "name",
          "state"
        ],
        "properties": {
          "fips_code": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "state": {
            "type": "string"
          }
        }
      },
      "CountiesResponse": {
        "type": "object",
        "additionalProperties": true,
        "required": [
          "counties"
        ],
        "properties": {
          "counties": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CountySummary"
            }
          }
        }
      },
      "IssuerSummary": {
        "type": "object",
        "additionalProperties": true,
        "required": [
          "name",
          "hios_issuer_id"
        ],
        "properties": {
          "name": {
            "type": "string",
            "description": "Issuer display name."
          },
          "hios_issuer_id": {
            "type": "string",
            "pattern": "^[0-9]{5}$",
            "description": "Five-digit HIOS issuer ID."
          }
        }
      },
      "IssuersResponse": {
        "type": "object",
        "additionalProperties": true,
        "required": [
          "issuers"
        ],
        "properties": {
          "issuers": {
            "type": "array",
            "description": "Issuers active in the requested state, sorted by `name` (case-insensitive) and then by `hios_issuer_id` as a stable tiebreaker. One entry per HIOS issuer.",
            "items": {
              "$ref": "#/components/schemas/IssuerSummary"
            }
          }
        }
      },
      "QuoteRequest": {
        "type": "object",
        "additionalProperties": true,
        "required": [
          "context",
          "location",
          "household"
        ],
        "description": "Canonical quote request for new integrations. Legacy `include` input is accepted for backward compatibility but ignored.",
        "properties": {
          "context": {
            "$ref": "#/components/schemas/QuoteContext"
          },
          "location": {
            "$ref": "#/components/schemas/LocationInput"
          },
          "household": {
            "$ref": "#/components/schemas/HouseholdQuoteInput"
          },
          "filters": {
            "$ref": "#/components/schemas/QuoteFilters"
          },
          "sort": {
            "$ref": "#/components/schemas/SortInput"
          },
          "page": {
            "$ref": "#/components/schemas/PageInput"
          },
          "include": {
            "deprecated": true,
            "description": "Deprecated and ignored. Accepted for backward compatibility."
          }
        }
      },
      "QuoteFilters": {
        "type": "object",
        "additionalProperties": true,
        "properties": {
          "issuer_ids": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "premium_min": {
            "type": "number",
            "minimum": 0
          },
          "premium_max": {
            "type": "number",
            "minimum": 0
          },
          "effective_date": {
            "type": "string",
            "format": "date"
          },
          "network_types": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "medical": {
            "$ref": "#/components/schemas/MedicalFilters"
          }
        }
      },
      "MedicalFilters": {
        "type": "object",
        "additionalProperties": true,
        "properties": {
          "metal_levels": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "bronze",
                "expanded_bronze",
                "silver",
                "gold",
                "platinum",
                "catastrophic"
              ]
            }
          },
          "plan_types": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "hmo",
                "ppo",
                "epo",
                "pos",
                "indemnity"
              ]
            }
          },
          "hsa_eligible": {
            "type": "boolean"
          },
          "standardized_only": {
            "type": "boolean"
          }
        }
      },
      "QuoteContext": {
        "type": "object",
        "additionalProperties": true,
        "required": [
          "product",
          "exchange",
          "coverage_family",
          "coverage_type"
        ],
        "properties": {
          "product": {
            "type": "string",
            "enum": [
              "aca",
              "ichra"
            ]
          },
          "exchange": {
            "type": "string",
            "enum": [
              "on_exchange",
              "off_exchange"
            ]
          },
          "coverage_family": {
            "type": "string",
            "enum": [
              "medical",
              "ancillary"
            ]
          },
          "coverage_type": {
            "type": "string",
            "enum": [
              "medical",
              "dental",
              "vision",
              "supplemental_other"
            ]
          },
          "plan_year": {
            "type": "integer",
            "minimum": 2020
          }
        }
      },
      "LocationInput": {
        "type": "object",
        "additionalProperties": true,
        "required": [
          "zip_code",
          "fips_code"
        ],
        "properties": {
          "zip_code": {
            "type": "string",
            "pattern": "^[0-9]{5}$"
          },
          "fips_code": {
            "type": "string",
            "pattern": "^[0-9]{5}$"
          },
          "state": {
            "type": "string",
            "pattern": "^[A-Z]{2}$",
            "description": "Quoteable state code for one of the 50 states or DC."
          }
        }
      },
      "HouseholdQuoteInput": {
        "type": "object",
        "additionalProperties": true,
        "required": [
          "applicants",
          "household_size"
        ],
        "properties": {
          "applicants": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/ApplicantInput"
            }
          },
          "annual_income": {
            "type": "number",
            "minimum": 0
          },
          "household_size": {
            "type": "integer",
            "minimum": 1
          },
          "effective_date": {
            "type": "string",
            "format": "date"
          }
        }
      },
      "ApplicantInput": {
        "type": "object",
        "additionalProperties": true,
        "required": [
          "member_id",
          "age",
          "relationship",
          "uses_tobacco"
        ],
        "properties": {
          "member_id": {
            "type": "string"
          },
          "age": {
            "type": "integer",
            "minimum": 0
          },
          "date_of_birth": {
            "type": "string",
            "format": "date"
          },
          "relationship": {
            "type": "string",
            "enum": [
              "primary",
              "spouse",
              "dependent"
            ]
          },
          "uses_tobacco": {
            "type": "boolean"
          },
          "pregnant": {
            "type": "boolean"
          },
          "blind_or_disabled": {
            "type": "boolean"
          },
          "native_american": {
            "type": "boolean"
          }
        }
      },
      "SortInput": {
        "type": "object",
        "additionalProperties": true,
        "properties": {
          "field": {
            "type": "string"
          },
          "direction": {
            "type": "string",
            "enum": [
              "asc",
              "desc"
            ]
          }
        }
      },
      "PageInput": {
        "type": "object",
        "additionalProperties": true,
        "properties": {
          "number": {
            "type": "integer",
            "minimum": 1,
            "default": 1
          },
          "size": {
            "type": "integer",
            "minimum": 1,
            "maximum": 500,
            "default": 20
          }
        }
      },
      "QuoteResponse": {
        "type": "object",
        "additionalProperties": true,
        "required": [
          "plans",
          "meta"
        ],
        "properties": {
          "plans": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PlanQuoteResult"
            }
          },
          "meta": {
            "$ref": "#/components/schemas/QuoteResponseMeta"
          }
        }
      },
      "PlanQuoteResult": {
        "type": "object",
        "additionalProperties": true,
        "required": [
          "plan_id",
          "coverage_family",
          "coverage_type",
          "name",
          "context",
          "issuer",
          "pricing",
          "documents",
          "details",
          "release"
        ],
        "properties": {
          "plan_id": {
            "type": "string"
          },
          "variant_id": {
            "type": "string"
          },
          "external_plan_id": {
            "type": "string"
          },
          "coverage_family": {
            "type": "string"
          },
          "coverage_type": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "display_name": {
            "type": "string"
          },
          "context": {
            "type": "object",
            "additionalProperties": true,
            "required": [
              "product",
              "exchange",
              "coverage_family",
              "coverage_type"
            ],
            "properties": {
              "product": {
                "type": "string",
                "enum": [
                  "aca",
                  "ichra"
                ]
              },
              "exchange": {
                "type": "string",
                "enum": [
                  "on_exchange",
                  "off_exchange"
                ]
              },
              "coverage_family": {
                "type": "string",
                "enum": [
                  "medical",
                  "ancillary"
                ]
              },
              "coverage_type": {
                "type": "string",
                "enum": [
                  "medical",
                  "dental",
                  "vision",
                  "supplemental_other"
                ]
              },
              "plan_year": {
                "type": "integer",
                "minimum": 2020
              }
            }
          },
          "issuer": {
            "type": "object",
            "additionalProperties": true,
            "required": [
              "issuer_id",
              "name"
            ],
            "properties": {
              "issuer_id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "state": {
                "type": "string",
                "nullable": true,
                "pattern": "^[A-Z]{2}$",
                "description": "Two-letter US state code where the issuer is licensed."
              },
              "payment_phone": {
                "type": "string",
                "nullable": true,
                "description": "Phone number for member premium-payment inquiries."
              },
              "customer_service_phone": {
                "type": "string",
                "nullable": true,
                "description": "Phone number for general customer-service inquiries."
              }
            }
          },
          "network": {
            "type": "object",
            "additionalProperties": true,
            "nullable": true,
            "properties": {
              "network_id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "type": {
                "type": "string",
                "nullable": true
              },
              "network_url": {
                "type": "string",
                "format": "uri",
                "nullable": true
              }
            }
          },
          "pricing": {
            "type": "object",
            "additionalProperties": true,
            "required": [
              "gross_premium",
              "currency"
            ],
            "properties": {
              "gross_premium": {
                "type": "number"
              },
              "ehb_premium": {
                "type": "number"
              },
              "max_aptc": {
                "type": "number"
              },
              "subsidy_applied": {
                "type": "number"
              },
              "net_premium": {
                "type": "number"
              },
              "currency": {
                "type": "string",
                "enum": [
                  "USD"
                ]
              },
              "billing_period": {
                "type": "string",
                "enum": [
                  "monthly"
                ]
              }
            }
          },
          "documents": {
            "type": "object",
            "additionalProperties": true,
            "description": "Canonical document slots. Carrier-specific source URLs are mapped into these stable fields.",
            "properties": {
              "sbc_url": {
                "type": "string",
                "format": "uri",
                "nullable": true,
                "description": "Summary of Benefits and Coverage document URL."
              },
              "formulary_url": {
                "type": "string",
                "format": "uri",
                "nullable": true
              },
              "brochure_url": {
                "type": "string",
                "format": "uri",
                "nullable": true
              },
              "network_url": {
                "type": "string",
                "format": "uri",
                "nullable": true
              },
              "payment_url": {
                "type": "string",
                "format": "uri",
                "nullable": true,
                "description": "Issuer-hosted page for making a premium payment."
              }
            }
          },
          "availability": {
            "type": "object",
            "additionalProperties": true,
            "description": "Resolved geographic availability lineage produced after county-first location resolution.",
            "properties": {
              "state": {
                "type": "string",
                "pattern": "^[A-Z]{2}$"
              },
              "service_area_id": {
                "type": "string",
                "nullable": true
              },
              "rating_area": {
                "type": "string",
                "nullable": true
              }
            }
          },
          "details": {
            "type": "object",
            "additionalProperties": true,
            "required": [
              "type"
            ],
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "medical",
                  "dental",
                  "vision",
                  "supplemental_other"
                ]
              },
              "metal_level": {
                "type": "string",
                "description": "Present for medical quote results.",
                "enum": [
                  "bronze",
                  "expanded_bronze",
                  "silver",
                  "gold",
                  "platinum",
                  "catastrophic"
                ]
              },
              "plan_type": {
                "type": "string",
                "description": "Present for medical quote results.",
                "enum": [
                  "hmo",
                  "ppo",
                  "epo",
                  "pos",
                  "indemnity"
                ]
              },
              "hsa_eligible": {
                "type": "boolean",
                "nullable": true,
                "description": "Present for medical quote results."
              },
              "is_standardized": {
                "type": "boolean",
                "nullable": true,
                "description": "Whether the plan follows a CMS- or state-defined standardized design. Present for medical quote results."
              },
              "adult_dental": {
                "type": "boolean",
                "nullable": true,
                "description": "Whether the medical plan embeds adult dental coverage. Present for medical quote results."
              },
              "child_dental": {
                "type": "boolean",
                "nullable": true,
                "description": "Whether the medical plan embeds pediatric (child) dental coverage. Present for medical quote results."
              },
              "deductible_individual": {
                "type": "number",
                "nullable": true,
                "description": "Individual annual deductible (USD). Present for medical quote results."
              },
              "deductible_family": {
                "type": "number",
                "nullable": true,
                "description": "Family annual deductible (USD). Present for medical quote results."
              },
              "moop_individual": {
                "type": "number",
                "nullable": true,
                "description": "Individual maximum out-of-pocket (USD). Present for medical quote results."
              },
              "moop_family": {
                "type": "number",
                "nullable": true,
                "description": "Family maximum out-of-pocket (USD). Present for medical quote results."
              },
              "csr_level": {
                "type": "string",
                "nullable": true,
                "enum": [
                  "off_exchange",
                  "standard",
                  "csr_zero_cost",
                  "csr_limited",
                  "csr73",
                  "csr87",
                  "csr94",
                  "csr77"
                ],
                "description": "CMS CSR variation derived from the 2-digit HIOS variant suffix. Source: PlanAttributes PUF CSRVariationType."
              },
              "primary_care_summary": {
                "type": "string",
                "nullable": true,
                "description": "Cost-share summary for a primary-care visit (e.g. \"$25 Copay\")."
              },
              "specialist_summary": {
                "type": "string",
                "nullable": true,
                "description": "Cost-share summary for a specialist visit."
              },
              "urgent_care_summary": {
                "type": "string",
                "nullable": true,
                "description": "Cost-share summary for an urgent-care visit."
              },
              "generic_rx_summary": {
                "type": "string",
                "nullable": true,
                "description": "Cost-share summary for generic prescription drugs."
              }
            }
          },
          "release": {
            "type": "object",
            "additionalProperties": true,
            "required": [
              "release_id"
            ],
            "properties": {
              "release_id": {
                "type": "string"
              },
              "plan_year": {
                "type": "integer"
              }
            }
          }
        }
      },
      "QuoteResponseMeta": {
        "type": "object",
        "additionalProperties": true,
        "required": [
          "coverage_type",
          "page_number",
          "page_size",
          "result_count",
          "warnings"
        ],
        "properties": {
          "coverage_type": {
            "type": "string"
          },
          "page_number": {
            "type": "integer"
          },
          "page_size": {
            "type": "integer"
          },
          "result_count": {
            "type": "integer"
          },
          "warnings": {
            "type": "array",
            "description": "Non-fatal advisories for the request. Includes an include deprecation warning when legacy `include` is supplied.",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "EnrollmentSessionRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "context"
        ],
        "description": "POST /v1/enrollment-sessions request body. Unsupported fields anywhere in the body are rejected with `400 invalid_request`. In `self_service`, supply at least one of `location.state` or top-level `plan_id`. In `agent_assisted`, `location.state` is required and `plan_id` is not accepted.",
        "properties": {
          "external_id": {
            "type": "string",
            "description": "Partner-supplied identifier echoed in the response and forwarded to HealthSherpa for CRM correlation. Strongly recommended; must not contain PII."
          },
          "plan_id": {
            "type": "string",
            "description": "Plan ID (HIOS ID). Available only for the `self_service` flow, where it is forwarded to HealthSherpa as the deep link `plan_hios_id` parameter. Invalid for `agent_assisted` — requests carrying `plan_id` with `context.flow` set to `agent_assisted` are rejected with `400 invalid_request`."
          },
          "notes": {
            "type": "string",
            "description": "Free-form note the agent attaches to the intake. Forwarded to the agent-assisted intake flow only; ignored on self-service deep links. Capped at 500 characters to match the EZ Intake UI; longer values are rejected with `400 invalid_request`.",
            "maxLength": 500
          },
          "providers": {
            "type": "array",
            "description": "Provider identifiers (NPI strings) the household cares about. Forwarded to the agent-assisted intake flow only; ignored on self-service deep links. Providers feed plan-network ranking at the household level, not per-applicant formulary matching, so this is intentionally a flat array rather than nested under each applicant.",
            "items": {
              "type": "string",
              "description": "Ten-digit National Provider Identifier (NPI).",
              "pattern": "^[0-9]{10}$"
            }
          },
          "context": {
            "$ref": "#/components/schemas/EnrollmentSessionContext"
          },
          "client": {
            "$ref": "#/components/schemas/EnrollmentSessionClient"
          },
          "location": {
            "$ref": "#/components/schemas/EnrollmentSessionLocation"
          },
          "household": {
            "$ref": "#/components/schemas/EnrollmentSessionHousehold"
          },
          "enrollment": {
            "$ref": "#/components/schemas/EnrollmentSessionEnrollment"
          },
          "campaign": {
            "$ref": "#/components/schemas/EnrollmentSessionCampaign"
          }
        }
      },
      "EnrollmentSessionContext": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "product",
          "exchange",
          "coverage_family",
          "coverage_type",
          "plan_year",
          "flow",
          "locale"
        ],
        "properties": {
          "product": {
            "type": "string",
            "enum": [
              "aca"
            ]
          },
          "exchange": {
            "type": "string",
            "enum": [
              "on_exchange"
            ]
          },
          "coverage_family": {
            "type": "string",
            "enum": [
              "medical"
            ]
          },
          "coverage_type": {
            "type": "string",
            "enum": [
              "medical"
            ]
          },
          "plan_year": {
            "type": "integer",
            "minimum": 2020,
            "maximum": 2099
          },
          "flow": {
            "type": "string",
            "enum": [
              "agent_assisted",
              "self_service"
            ],
            "description": "Mapped to the deep link's `user_type` (`agent_assisted` -> `agent`, `self_service` -> `consumer`)."
          },
          "locale": {
            "type": "string",
            "enum": [
              "en-US",
              "es-MX"
            ],
            "description": "`es-MX` enables the Spanish flow via the deep link's `ljs` parameter."
          }
        }
      },
      "EnrollmentSessionClient": {
        "type": "object",
        "additionalProperties": false,
        "deprecated": true,
        "description": "DEPRECATED legacy contact block. Every property here has a 1:1 replacement on `household.applicants[]` and is preferred when both are supplied: `first_name` → `household.applicants[primary].first_name`, `last_name` → `household.applicants[primary].last_name`, `email` → `household.applicants[primary].email`, `phone_number` → `household.applicants[primary].phone_number`. Each field that is still supplied here surfaces a `deprecated_field` entry in the response's `warnings[]` array. The block remains accepted for backwards compatibility but may be removed at any time; migrate to the applicant-level fields.",
        "properties": {
          "first_name": {
            "type": "string",
            "deprecated": true,
            "description": "DEPRECATED. Send as `household.applicants[primary].first_name` instead.",
            "maxLength": 50
          },
          "last_name": {
            "type": "string",
            "deprecated": true,
            "description": "DEPRECATED. Send as `household.applicants[primary].last_name` instead.",
            "maxLength": 50
          },
          "email": {
            "type": "string",
            "deprecated": true,
            "description": "DEPRECATED. Send as `household.applicants[primary].email` instead.",
            "maxLength": 50
          },
          "phone_number": {
            "type": "string",
            "deprecated": true,
            "description": "DEPRECATED. Send as `household.applicants[primary].phone_number` instead.",
            "maxLength": 50
          }
        }
      },
      "EnrollmentSessionLocation": {
        "type": "object",
        "additionalProperties": false,
        "description": "Routing geography plus optional street address. `zip_code`, `fips_code`, and `state` route the request; `address_line_1`, `address_line_2`, and `city` are forwarded to the agent-assisted intake flow only and ignored on self-service deep links.",
        "properties": {
          "zip_code": {
            "type": "string",
            "pattern": "^[0-9]{5}$"
          },
          "fips_code": {
            "type": "string",
            "pattern": "^[0-9]{5}$",
            "description": "Five-digit county FIPS code. Mapped to the deep link's legacy `fip_code` parameter."
          },
          "state": {
            "type": "string",
            "description": "Two-letter US state code (50 states plus DC).",
            "pattern": "^[A-Za-z]{2}$"
          },
          "address_line_1": {
            "type": "string",
            "description": "First line of the street address (number and street). Forwarded to the agent-assisted intake flow as `address`.",
            "maxLength": 50
          },
          "address_line_2": {
            "type": "string",
            "description": "Optional second line of the street address (apartment, suite). Forwarded to the agent-assisted intake flow as `address_2`.",
            "maxLength": 50
          },
          "city": {
            "type": "string",
            "description": "City of the street address. Forwarded to the agent-assisted intake flow as `city`; ignored on self-service deep links.",
            "maxLength": 50
          }
        }
      },
      "EnrollmentSessionHousehold": {
        "type": "object",
        "additionalProperties": false,
        "description": "`household_size` must be at least 1. Applicants can include at most one `primary` and one `spouse`.",
        "properties": {
          "annual_income": {
            "type": "number",
            "minimum": 0
          },
          "household_size": {
            "type": "integer",
            "minimum": 1
          },
          "someone_has_employer_coverage": {
            "type": "boolean"
          },
          "applicants": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EnrollmentSessionApplicant"
            }
          }
        }
      },
      "EnrollmentSessionApplicant": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "relationship"
        ],
        "description": "`date_of_birth` and `age` are mutually exclusive on the same applicant, and `date_of_birth` must not be in the future. `sex` accepts `male` and `female`. `first_name` / `last_name` are accepted on every applicant so non-primary members can carry their own identity for the agent-assisted intake flow. `email` and `phone_number` are accepted only on the applicant whose `relationship` is `primary` — supplying them on a spouse or dependent is rejected.",
        "properties": {
          "relationship": {
            "type": "string",
            "enum": [
              "primary",
              "spouse",
              "dependent"
            ]
          },
          "first_name": {
            "type": "string",
            "description": "Given name. Forwarded to the agent-assisted intake flow only; ignored on self-service deep links. Composed with `last_name` into upstream `tax_household_members[].name` and `projected_income_members[].name`; the primary applicant's `first_name` also populates the upstream top-level `first_name`.",
            "maxLength": 50
          },
          "last_name": {
            "type": "string",
            "description": "Family name. Forwarded to the agent-assisted intake flow only; ignored on self-service deep links. Composed with `first_name` into upstream `tax_household_members[].name` and `projected_income_members[].name`; the primary applicant's `last_name` also populates the upstream top-level `last_name`.",
            "maxLength": 50
          },
          "email": {
            "type": "string",
            "description": "Email for the primary applicant. Forwarded as `email` upstream to the agent-assisted intake flow (and used to look the lead up later). Replaces the deprecated `client.email`; only accepted when `relationship` is `primary`.",
            "pattern": "^[^@\\s]+@[^@\\s]+\\.[^@\\s]+$",
            "maxLength": 50
          },
          "phone_number": {
            "type": "string",
            "description": "Phone number for the primary applicant. Forwarded as `phone_number` upstream to the agent-assisted intake flow. Replaces the deprecated `client.phone_number`; only accepted when `relationship` is `primary`. Permissive shape — digits with optional spaces, dots, parentheses, hyphens, and a leading `+` (7–50 characters); upstream Intake performs the canonical normalization.",
            "pattern": "^[0-9\\s().+\\-]{7,50}$"
          },
          "date_of_birth": {
            "type": "string",
            "format": "date"
          },
          "age": {
            "type": "integer",
            "minimum": 0,
            "maximum": 130
          },
          "sex": {
            "type": "string",
            "enum": [
              "male",
              "female"
            ]
          },
          "uses_tobacco": {
            "type": "boolean"
          },
          "pregnant": {
            "type": "boolean"
          },
          "parent_caretaker": {
            "type": "boolean"
          },
          "rejected_by_medicaid_or_chip": {
            "type": "boolean"
          },
          "unemployment": {
            "type": "boolean"
          },
          "has_existing_coverage": {
            "type": "boolean"
          },
          "ichra": {
            "$ref": "#/components/schemas/EnrollmentSessionApplicantIchra"
          },
          "prescriptions": {
            "type": "array",
            "description": "Medications this applicant takes. Forwarded to the agent-assisted intake flow only; ignored on self-service deep links. Nested under the applicant rather than carrying an `applicant_index` linkage field.",
            "items": {
              "$ref": "#/components/schemas/EnrollmentSessionApplicantPrescription"
            }
          },
          "income_sources": {
            "type": "array",
            "description": "Income lines attributed to this applicant. Forwarded to the agent-assisted intake flow only; ignored on self-service deep links. When any applicant supplies `income_sources`, the per-applicant entries replace the household-level `annual_income` aggregation in the agent-assisted payload; `annual_income` continues to drive the self-service deep link regardless.",
            "items": {
              "$ref": "#/components/schemas/EnrollmentSessionApplicantIncomeSource"
            }
          }
        }
      },
      "EnrollmentSessionApplicantPrescription": {
        "type": "object",
        "additionalProperties": false,
        "description": "Medication identification used for Rx-matched plan ranking. At least one of `id` or `rx_norm_identifier` must be supplied — entries with neither are rejected with `400 invalid_request` because they would otherwise be silently dropped from the upstream payload.",
        "properties": {
          "id": {
            "type": "string",
            "description": "HealthSherpa medication catalog identifier."
          },
          "duration": {
            "type": "integer",
            "description": "Days-of-supply per fill (informational; not used to filter plans).",
            "minimum": 0
          },
          "rx_norm_identifier": {
            "type": "string",
            "description": "RxNorm CUI for the medication."
          }
        }
      },
      "EnrollmentSessionApplicantIncomeSource": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "amount"
        ],
        "description": "One income line attributed to this applicant. `amount` is required — entries without an amount would emit a zero-value `projected_income_members[]` row upstream with no usable information.",
        "properties": {
          "employer": {
            "type": "string",
            "description": "Employer or payer attributed to this income line. Forwarded to upstream `projected_income_members[].employer`.",
            "maxLength": 50
          },
          "amount": {
            "type": "number",
            "description": "Annual income from this source in dollars.",
            "minimum": 0
          }
        }
      },
      "EnrollmentSessionApplicantIchra": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "offered": {
            "type": "boolean"
          },
          "offered_cafeteria": {
            "type": "boolean"
          },
          "employee_amount": {
            "type": "number",
            "minimum": 0
          },
          "family_amount": {
            "type": "number",
            "minimum": 0
          }
        }
      },
      "EnrollmentSessionEnrollment": {
        "type": "object",
        "additionalProperties": false,
        "description": "Accepts `hra`. Other enrollment subobjects (`special_enrollment_period`, `communication_preferences`) are not supported and are rejected with `400 invalid_request`.",
        "properties": {
          "hra": {
            "$ref": "#/components/schemas/EnrollmentSessionEnrollmentHra"
          }
        }
      },
      "EnrollmentSessionEnrollmentHra": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "amount"
        ],
        "description": "When supplied, `amount` is required and must be greater than or equal to 0. `0` means the consumer declined available HRA funding; a positive value means funding was accepted. `frequency` is required when `amount > 0` and is omitted from the deep link when `amount == 0`.",
        "properties": {
          "amount": {
            "type": "number",
            "minimum": 0
          },
          "frequency": {
            "type": "string",
            "enum": [
              "annually",
              "monthly",
              "quarterly",
              "one_time"
            ]
          }
        }
      },
      "EnrollmentSessionCampaign": {
        "type": "object",
        "additionalProperties": false,
        "description": "Marketing attribution. Only accepted when `context.flow` is `self_service`; sending any field with `flow: \"agent_assisted\"` is rejected with `400 invalid_request`.",
        "properties": {
          "cid": {
            "type": "string"
          },
          "utm_source": {
            "type": "string"
          },
          "utm_medium": {
            "type": "string"
          },
          "utm_campaign": {
            "type": "string"
          },
          "utm_term": {
            "type": "string"
          },
          "utm_content": {
            "type": "string"
          },
          "display_phone_number": {
            "type": "string",
            "pattern": "^\\D?(\\d{3})\\D?\\D?(\\d{3})\\D?(\\d{4})$",
            "description": "Phone number HealthSherpa renders in the page header. Must be a 10-digit US phone number (any of `8005551234`, `800-555-1234`, `800.555.1234`, `(800) 555-1234` are accepted); `+1`-prefixed and non-10-digit values are rejected with `400 invalid_request`. Forwarded to the deep link's `call` parameter unchanged."
          }
        }
      },
      "EnrollmentSessionResponse": {
        "type": "object",
        "additionalProperties": true,
        "required": [
          "links"
        ],
        "description": "Response envelope. Fields may be null when the request omits optional inputs (for example, `external_id`). Clients must tolerate new top-level keys appearing additively over time. `warnings` is emitted only when the request used a deprecated field; clients should treat its absence as 'no warnings'.",
        "properties": {
          "external_id": {
            "type": "string",
            "nullable": true,
            "description": "Echoed from the request when supplied; otherwise null."
          },
          "links": {
            "$ref": "#/components/schemas/EnrollmentSessionResponseLinks"
          },
          "warnings": {
            "type": "array",
            "description": "Non-fatal warnings about the request. Today only the legacy `client.*` contact block emits warnings — one entry per deprecated field that was supplied. The key is omitted entirely when there are no warnings. Clients that want to detect deprecations programmatically should branch on `warnings[].code`.",
            "items": {
              "$ref": "#/components/schemas/EnrollmentSessionResponseWarning"
            }
          }
        }
      },
      "EnrollmentSessionResponseWarning": {
        "type": "object",
        "additionalProperties": true,
        "required": [
          "code",
          "field",
          "message"
        ],
        "description": "One non-fatal warning about a single request field. New `code` values may be introduced additively over time; clients should treat unknown codes as 'log and continue'.",
        "properties": {
          "code": {
            "type": "string",
            "description": "Stable, machine-readable warning category. Currently only `deprecated_field` is emitted (when the request uses a `client.*` contact field that has been replaced by a `household.applicants[]` equivalent)."
          },
          "field": {
            "type": "string",
            "description": "Dotted request path of the field this warning is about (for example, `client.email`)."
          },
          "message": {
            "type": "string",
            "description": "Human-readable explanation. For deprecation warnings, includes the suggested replacement field path."
          }
        }
      },
      "EnrollmentSessionResponseLinks": {
        "type": "object",
        "additionalProperties": true,
        "required": [
          "shopping_url",
          "client_apply_url"
        ],
        "properties": {
          "shopping_url": {
            "type": "string",
            "format": "uri",
            "description": "HealthSherpa public shop URL (https://healthsherpa.com/public/shop?...)."
          },
          "client_apply_url": {
            "type": "string",
            "format": "uri",
            "description": "HealthSherpa public apply URL (https://healthsherpa.com/public/apply?...). Always present for enrollment-session responses."
          }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "description": "Canonical error envelope returned by every HealthSherpa API endpoint, infrastructure filter, and backend service. Clients should treat `error.code` as the stable programmatic identifier and surface `error.message` to humans. Recognized codes include:\n- `unauthorized` (401) - backend runtime authentication failure when a request reaches a runtime that performs its own authentication\n- `forbidden` (403) - missing/invalid/unauthorized API key at the API edge, or edge policy deny\n- `invalid_request` (400) - request body or parameter validation failed\n- `not_found` (404) - resource or route not found\n- `payload_too_large` (413) - request body exceeded edge limits\n- `unsupported_media_type` (415) - unsupported Content-Type\n- `rate_limited` (429) - edge rate-limiting\n- `service_unavailable` (503) - the edge is failing to reach the backend, or an upstream catalog/quoting/lookup service is unavailable\n- `bad_gateway` (502) - the edge received an invalid response from the backend\n- `gateway_timeout` (504) - the edge did not receive a timely response from the backend\n- `internal_error` (500) - unexpected server error",
        "additionalProperties": true,
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "additionalProperties": true,
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "string",
                "description": "Stable, machine-readable identifier for the error class (see ErrorResponse description for recognized values). Clients should branch on this field rather than on `message` or HTTP status alone."
              },
              "message": {
                "type": "string",
                "description": "Human-readable explanation of the error, suitable for logging or surfacing to an end user."
              },
              "details": {
                "type": "object",
                "description": "Optional per-field validation details. Keys are dotted/indexed paths (e.g. `household.applicants[0].age`) and values are arrays of full-sentence error messages.",
                "additionalProperties": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}
