# HealthSherpa ❮ONE❯ API Docs

> Reference for current public endpoints and approval-gated enrollment workflows in the HealthSherpa developer portal.

## Authentication

- Public API requests use the `x-api-key` header.
- The OpenAPI contract is available at `https://one.healthsherpa.com/openapi.json`.

## Available now

### GET /v1/ping

- Confirms API reachability and key validity.

### GET /v1/reference/counties

- Input: `zip_code` query parameter.
- Returns county options with `name`, `fips_code`, and `state`. A ZIP code can cross state lines; each county's `state` matches its `fips_code`.
- Use the selected `fips_code` in quote requests.

### GET /v1/reference/issuers

- Inputs: required `state` (two-letter uppercase US code; lowercase is rejected with `400 invalid_request`), optional `plan_year` (integer 2020..2099, defaults to the current ACA plan year).
- Returns one entry per active HIOS issuer with `name` and 5-digit `hios_issuer_id`.
- Entries are sorted by `name` (case-insensitive) and then `hios_issuer_id` as a stable tiebreaker.
- Use the returned `hios_issuer_id` to build issuer filters or validate inbound quote requests.

### GET /v1/reference/providers

- Inputs: required `query` (provider or facility name), `zip_code` (five-digit ZIP used for the near-ZIP search), and `exchange` (`on_exchange` or `off_exchange`), plus optional `page[number]` (defaults to 1) and `page[size]` (defaults to 50, max 50) — the same nested `page` model as quoting.
- Returns a `providers[]` array; each entry includes the 10-digit `npi`, `display_name`, `entity_type`, `specialty`, and address fields. Pagination lives in `meta` (`page_number`, `page_size`, `result_count`), matching the quoting response.
- Search only: there is no list-all mode, and a search with no matches returns `providers: []`.
- Use the returned 10-digit `npi` when referencing a provider in later requests.

### POST /v1/quotes

- Inputs include `context`, `location`, and `household`.
- `household.applicants[].member_id` is a required caller-supplied applicant identifier. Use a stable non-empty string from your system, such as `applicant-1`; it is separate from `relationship`, which identifies the applicant as `primary`, `spouse`, or `dependent`.
- Required quote applicant fields are `member_id`, `age`, `relationship`, and `uses_tobacco`. Optional applicant fields include `gender` and marketplace screening flags.
- Returns a homogeneous `plans[]` array for the requested `coverage_type`.
- Quotes always return the canonical payload shape.
- Each plan includes `api_enrollable`. `true` means the quoted plan can be used with the direct off-exchange enrollment API at quote time. `false` means use quote/display only or another enrollment path. This is not consumer ACA eligibility and does not guarantee successful submission after applicant and carrier validation.
- Legacy `include` is deprecated and ignored; when supplied, `meta.warnings` includes a deprecation message.
- Use filters, sorting, and pagination to control result selection and order.
- Current docs include examples for medical ACA quoting.

## Compatibility rules

- Response objects are intentionally open and may gain new optional fields.
- Clients should ignore unknown properties.
- Clients should not rely on object property order.

## Approval-gated workflows

### POST /v1/enrollment-sessions

- Approval-gated endpoint. Request access in the developer portal at `https://one.healthsherpa.com/portal.html` so HealthSherpa can enable your account for enrollment sessions. Portal access is separate from the per-request authorization described under `403 forbidden` below: each call is checked only against the marketplace link or deep-link configuration that the chosen `context.flow` actually uses.
- Use this endpoint to send the browser to a HealthSherpa enrollment flow for guided shopping, application preparation, and enrollment completion.
- On-exchange enrollment approval is required for both flows and must be requested in the developer portal before use.
- Successful responses include `links.shopping_url` and `links.client_apply_url`. The endpoint does not create direct enrollment application records.
- Optional `Idempotency-Key` header is treated as unique within a 24-hour window.
- The entire `context` object is required (`product`, `exchange`, `coverage_family`, `coverage_type`, `plan_year`, `flow`, `locale`).
- `agent_assisted` callers must supply `location.state`. `self_service` callers must supply at least one of `location.state` or top-level `plan_id`; `plan_id` is only accepted for `self_service`.
- Strict body: unsupported fields anywhere in the body are rejected with `400 invalid_request`.
- `403 forbidden` can mean the key was rejected at the API edge, or that the developer's HealthSherpa Marketplace setup is not yet in the state the requested flow needs. The check is flow-scoped and both flows require approved on-exchange enrollment access: `agent_assisted` also requires a healthy HealthSherpa Marketplace link (active OAuth connection with an unexpired or refreshable access token) and an OAuth-linked agent whose agency is approved for enrollment deeplink URL generation; `self_service` also requires a configured deeplink agent ID. Each flow only fails when the gate it actually uses is not satisfied.
- `context.flow`: use `agent_assisted` when an agent is helping the shopper; the agent must sign in to HealthSherpa in the browser before continuing. Use `self_service` when the shopper is completing the flow without an agent sign-in. Approval for On-Exchange Enrollment access is required before using either flow.
- `context.locale` of `es-MX` renders the enrollment page in Spanish.
- `campaign` (UTM, `cid`, `display_phone_number`) is only accepted when `context.flow` is `self_service`.
- `enrollment.hra.amount` is required when `hra` is supplied; `frequency` is required when `amount > 0` (`annually`, `monthly`, `quarterly`, `one_time`).
- `household.household_size` must be positive. Applicants support `relationship`, `date_of_birth` (xor `age`), `sex` (`male`/`female`), `uses_tobacco`, and other screening flags. A household can include at most one `primary` and one `spouse`.

### POST /v1/enrollments

- Approval-gated direct enrollment API. This is the application-create option for partners that need API-level control over off-exchange enrollment.
- Include `context.product = "ichra"` and `context.exchange = "off_exchange"`. Other products and exchanges are not supported for direct enrollment at this time; use `POST /v1/enrollment-sessions` for on-exchange enrollment.
- Supply the application JSON object at the request root, alongside the HealthSherpa ONE `context` object. Required create fields are `context.product = "ichra"`, `context.exchange = "off_exchange"`, `context.plan_year`, `plan_hios_id`, `applicants.primary`, and `residential_address`.
- HealthSherpa ONE uses `context` only for routing and sets the application `plan_year` from `context.plan_year`, and applies `_agent_id` and `tpa_slug` from your approved account setup. Do not send root `_agent_id`, root `tpa_slug`, `actor.agent_id`, or `agent_of_record`; HealthSherpa ONE rejects those server-owned fields. Caller-supplied root `plan_year` is overwritten from `context.plan_year`.
- `Idempotency-Key` is required for create requests.
- If you omit `external_id`, HealthSherpa ONE uses your `Idempotency-Key` as the `external_id` so a retried create is deduplicated instead of creating a second application.
- The request contract includes applicant identity, demographic, eligibility, contact, existing-coverage, guardian, responsible-party, translator, HRA, employer, SEP, attestation, signature, communication-preference, address, mailing-address, and analytics fields. Use `openapi.json` for the exhaustive field list, enum values, and response schemas.
- Successful responses include the application data, payment instructions, policies, events when available, `next_actions[]` when actions are currently available, and the current submission-readiness `errors[]` array. `next_actions[].href` values use public `/v1/enrollments` routes. An empty `errors[]` array means the draft is ready to submit. Service failures (validation, idempotency-key, authorization, service availability) use top-level `errors[]` (each entry has `code`, `message`, and optional `field`). Failures blocked at the API edge — most importantly a missing or invalid API key (`403`), plus `413`/`415`, edge rate limiting, and gateway `502`/`504` — use the standard `error` envelope instead.

### GET /v1/enrollments

- Approval-gated direct enrollment API for listing off-exchange applications for your approved account.
- Send required query parameters `product=ichra` and `exchange=off_exchange` so HealthSherpa ONE can validate the direct-enrollment routing channel.
- Supported filters are `policy_status`, `external_id`, `plan_year`, `issuer_hios_id`, `plan_hios_id`, `employer_external_id`, and `updated_since`.
- Use `limit` and `offset` for pagination. `limit` must be 1-100 and defaults to 25; `offset` must be 0 or greater and defaults to 0.
- The response includes `applications[]` summary rows and a `pagination` object with `limit`, `offset`, and `total`.
- Do not send unsupported query parameters such as `include_events`; unsupported list controls return `400 invalid_request`.

### GET /v1/policy-status/applications

- Alpha release. Not every application returns policy status data yet, and returned values can be partial. Coverage, accuracy, and completeness improve continuously as HealthSherpa works with more carriers, so treat missing data as expected rather than an error.
- Approval-gated on-exchange policy status API for listing HealthSherpa Marketplace applications visible to the OAuth-linked agent.
- Send required query parameters `exchange=on_exchange` and `plan_year`. Optional pagination parameters are `limit` and `offset`; `limit` must be 1-100 and `offset` must be 0 or greater.
- Do not send `product` or off-exchange filters such as `policy_status`, `external_id`, `issuer_hios_id`, `plan_hios_id`, `employer_external_id`, or `updated_since`.
- The response includes `applications[]` summary rows and `pagination`. Each application row includes the Marketplace `confirmation_id` when available.

### GET /v1/policy-status/applications/{confirmation_id}

- Alpha release. Policy status fields are populated only when the carrier reports them, and carrier coverage is expanding over time.
- Approval-gated on-exchange policy status API for reading policy statuses for one HealthSherpa Marketplace application.
- Send required query parameters `exchange=on_exchange` and `plan_year`. The path id is the Marketplace application `confirmation_id` returned by `GET /v1/policy-status/applications`.
- The response contains `policy_statuses[]` with exchange policy ids, issuer ids, status, payment status, balance, paid-through, grace-period, and update fields when available.
- Service failures use the standard `error` envelope.

### PUT /v1/enrollments/{enrollment_id}

- Approval-gated direct enrollment API for updating an off-exchange application.
- Send the HealthSherpa ONE `context` object with `product = "ichra"`, `exchange = "off_exchange"`, and `plan_year`.
- Treat `PUT` as a full replacement-style update. Send the full current application payload, including unchanged fields you want to preserve. When you include `applicants.primary`, include the full current primary applicant object; omitted primary fields may be cleared.
- HealthSherpa ONE maps `context.plan_year` to the application `plan_year`; `context` is not part of the stored application payload.
- Before submission, all application fields may be updated. After submission, updates depend on carrier support. Check `supports_changes`, `can_change_plan`, and `can_report_change` on `GET /v1/enrollments/{enrollment_id}?product=ichra&exchange=off_exchange` before attempting post-enrollment changes.
- HealthSherpa ONE applies `_agent_id` and `tpa_slug` from your approved account setup. Send plan year as `context.plan_year`, not root `plan_year`. Do not send root `_agent_id`, root `tpa_slug`, `actor.agent_id`, or `agent_of_record`; HealthSherpa ONE rejects those server-owned fields.
- `Idempotency-Key` is not required for update requests.
- Successful responses include the updated application data, `next_actions[]` when actions are currently available, and the current submission-readiness `errors[]` array. An empty `errors[]` array means the application is ready to submit.

### GET /v1/enrollments/{enrollment_id}

- Approval-gated direct enrollment API for reading an application.
- Send required query parameters `product=ichra` and `exchange=off_exchange` so HealthSherpa ONE can validate the direct-enrollment routing channel.
- HealthSherpa ONE returns the application details for the supplied id, including `next_actions[]` when actions are currently available. Service failures use top-level `errors[]`; failures blocked at the API edge (such as a missing or invalid API key) use the standard `error` envelope.
- Do not send unsupported read query parameters such as `include_events`; only `product` and `exchange` are supported.
- Do not send `plan_year` on GET. Applications are read by id, and the application `plan_year` is returned in the response.

### POST /v1/enrollments/{enrollment_id}/cancellations

- Approval-gated direct enrollment API for cancelling an off-exchange application that is pending effectuation.
- Not all carriers support cancellation. Read the application first and check for `next_actions[].rel = "cancel"` or the returned carrier capabilities before calling.
- Send the HealthSherpa ONE `context` object with `product = "ichra"` and `exchange = "off_exchange"`.
- A successful call returns `202 Accepted` with `application_id`, `policy_status`, optional `effective_date`, and `updated_at`.
- If a network timeout or other unknown-result failure occurs after calling cancel, poll `GET /v1/enrollments/{enrollment_id}?product=ichra&exchange=off_exchange` before retrying so an already-accepted cancellation does not come back as a misleading not-allowed/no-op retry response.
- Service failures use top-level `errors[]`; `400` means cancellation is not allowed for the application or carrier. Failures blocked at the API edge use the standard `error` envelope.

### POST /v1/enrollments/{enrollment_id}/terminations

- Approval-gated direct enrollment API for terminating an active off-exchange policy before its natural expiration date.
- Not all carriers support termination. Read the application first and check for `next_actions[].rel = "terminate"` or the returned carrier capabilities before calling.
- Send the HealthSherpa ONE `context` object with `product = "ichra"` and `exchange = "off_exchange"`.
- A successful call returns `202 Accepted` with `application_id`, `policy_status`, optional `effective_date`, and `updated_at`.
- If a network timeout or other unknown-result failure occurs after calling terminate, poll `GET /v1/enrollments/{enrollment_id}?product=ichra&exchange=off_exchange` before retrying so an already-accepted termination does not come back as a misleading not-allowed/no-op retry response.
- Service failures use top-level `errors[]`; `400` means termination is not allowed for the application or carrier. Failures blocked at the API edge use the standard `error` envelope.

### POST /v1/enrollments/{enrollment_id}/submissions

- Approval-gated direct enrollment API for submitting an off-exchange application to the carrier.
- Send the HealthSherpa ONE `context` object with `product = "ichra"` and `exchange = "off_exchange"`. `plan_year` is not required for submission.
- Before calling, read the application and check `errors[]`. An empty `errors[]` array means the application is ready to submit; outstanding errors cause submission to fail with `422`.
- A successful call returns `202 Accepted`. Submission processing can continue asynchronously, so poll `GET /v1/enrollments/{enrollment_id}?product=ichra&exchange=off_exchange` until `policy_status` reflects the final outcome.
- If a network timeout or other unknown-result failure occurs after calling submit, poll readback before retrying so you do not turn an already-accepted submission into a duplicate/no-change response.
- For carriers that support post-enrollment changes, call `PUT /v1/enrollments/{enrollment_id}` to send supported changes, then call this endpoint again to resubmit the tracked changes. The API returns `422` if no changes have been made since the last submission.
- Service failures use top-level `errors[]`; failures blocked at the API edge use the standard `error` envelope.

### GET /v1/enrollments/{enrollment_id}/payment_redirect

- Approval-gated direct enrollment API for retrieving the carrier payment redirect data for an off-exchange application.
- Send required query parameters `product=ichra` and `exchange=off_exchange` so HealthSherpa ONE can validate the direct-enrollment routing channel.
- Use this when the application response includes `payment_instructions.payment_redirect_supported = true`.
- The response includes `method = "POST"`, the carrier `endpoint`, and `fields[]` entries with `name` and `value`.
- Build a browser form POST to `endpoint` and include every returned field exactly as provided as a hidden input. Do not filter, rename, interpret, or modify carrier fields.
- Service failures use top-level `errors[]`; `422` means payment redirect is not supported for this carrier. Failures blocked at the API edge use the standard `error` envelope.

### POST /v1/enrollments/{enrollment_id}/supporting_documentation

- Approval-gated direct enrollment API for uploading SEP supporting documentation to an off-exchange application.
- Use this when `GET /v1/enrollments/{enrollment_id}?product=ichra&exchange=off_exchange` returns `document_status = "required"` or the application indicates that supporting documentation is needed.
- Send the HealthSherpa ONE `context` object with `product = "ichra"` and `exchange = "off_exchange"`.
- Send `document_type = "sep"`. Supported file types are PDF, JPEG, and PNG.
- You can send `multipart/form-data` with a binary `file`, or `application/json` with `file.filename`, `file.content_type`, and base64 `file.content_base64`.
- HealthSherpa ONE does not persist the uploaded file after processing.

### Off-Exchange Enrollment Workflow

- The Off-Exchange Enrollment API includes application listing through `GET /v1/enrollments?product=ichra&exchange=off_exchange`, application creation through `POST /v1/enrollments`, full replacement-style updates through `PUT /v1/enrollments/{enrollment_id}`, cancellation through `POST /v1/enrollments/{enrollment_id}/cancellations`, termination through `POST /v1/enrollments/{enrollment_id}/terminations`, submission through `POST /v1/enrollments/{enrollment_id}/submissions`, payment redirect data through `GET /v1/enrollments/{enrollment_id}/payment_redirect?product=ichra&exchange=off_exchange`, supporting document upload through `POST /v1/enrollments/{enrollment_id}/supporting_documentation`, and readback through `GET /v1/enrollments/{enrollment_id}?product=ichra&exchange=off_exchange`.
- Poll `GET /v1/enrollments/{enrollment_id}?product=ichra&exchange=off_exchange` for `policy_status`, `document_status`, payment data, policy details, lifecycle events, and updated `errors[]`.

## Errors

- `400 invalid_request`: payload or query validation failed.
- `401 unauthorized`: backend runtime authentication failure when a request reaches a runtime that performs its own authentication.
- `403`: API Gateway rejected the key as missing, invalid, inactive, or unauthorized, or the request was blocked at the edge.
- `404 not_found`: requested resource was not found.
- `429`: request limits exceeded.
- `503`: upstream catalog or marketplace dependency unavailable.
- `500 internal_error`: unexpected server-side exception.
- Direct enrollment endpoints return service failures as top-level `errors[]` instead of `error`. Example: `{ "errors": [{ "code": "invalid_field_value", "message": "must be valid", "field": "plan_hios_id" }] }`; `field` is omitted when no request path is available. Failures blocked at the API edge (for example a missing or invalid API key) still use the `error` envelope, so check for both `errors` and `error`.

## Key links

- Human-readable docs: `https://one.healthsherpa.com/docs.html`
- OpenAPI specification: `https://one.healthsherpa.com/openapi.json`
