# Authentication Source: https://docs.soharhealth.com/api-reference/api-reference/authentication Sohar uses the [OAuth 2.0](https://oauth.net/2/) bearer token authentication scheme. Retrieve a bearer token via the [Get Token](/api-reference/auth/get-token) endpoint. This call requires your `client_id` and `client_secret`, which an organization admin can generate from the Sohar [dashboard](https://app.soharhealth.com/settings). Your credentials determine whether requests use the [sandbox or production environment](/api-reference/api-reference/environments). The `/oauth/token` endpoint expects a JSON body with your credentials: ```json theme={null} { "client_id": "YOUR_CLIENT_ID", "client_secret": "YOUR_CLIENT_SECRET" } ``` Include the token in the `Authorization` header as `Bearer ` when calling other APIs. # Environments Source: https://docs.soharhealth.com/api-reference/api-reference/environments The Sohar API supports sandbox and production environments. Both environments use the same base URL: ```text theme={null} https://api.soharhealth.com ``` The credentials used to retrieve your access token determine the environment for each request. Create separate sandbox and production credentials in the Sohar [dashboard](https://app.soharhealth.com/settings#oauth). ## Sandbox Use the sandbox environment to build and test your integration without affecting live data. Sandbox requests return predefined responses when you use the test values documented for [Verification](/documentation/guides/verification#sandbox-values) and [Discovery](/documentation/guides/discovery#sandbox-values). Sandbox webhook event names use the `sandbox.` prefix, such as `sandbox.verification.updated`. See [Webhook Events](/documentation/webhooks/events) for available events. ## Production Use the production environment for requests involving live patient and insurance data. Replace your sandbox credentials with production credentials when your integration is ready for live traffic. Production webhook event names do not use the `sandbox.` prefix. Resources are associated with the environment in which they are created. Use credentials for the same environment when retrieving a resource. # Errors Source: https://docs.soharhealth.com/api-reference/api-reference/errors Sohar uses standard HTTP response codes to indicate whether an API request succeeded. A response with a `4xx` status code indicates an issue with the request. A response with a `5xx` status code indicates an issue processing the request. ## Response Format Error responses can include an `error` value and the request parameter that caused the error: ```json theme={null} { "error": "invalid_request_error", "param": "patient.firstName" } ``` Some endpoints also return your optional `id` value to help identify the request. Fields that do not apply to an error are omitted. ## Response Codes | Code | Description | | - | - | | `400` | The request is invalid. Check the `param` value, when present, to identify the invalid field. | | `401` | The access token is missing, invalid, or expired. See [Authentication](/api-reference/api-reference/authentication). | | `403` | The authenticated account does not have access to the requested resource or operation. | | `404` | The requested resource was not found. | | `429` | The request exceeded an account quota or [rate limit](/api-reference/api-reference/rate-limits). | | `500` | Sohar encountered an unexpected error while processing the request. | | `503` | Sohar is temporarily unable to process the request. | ## Handling Errors Correct the request before retrying a `4xx` response, except for `429`. Retry `429`, `500`, and `503` responses with exponential backoff and jitter. When retrying a supported create request, reuse its [idempotency key](/api-reference/api-reference/idempotency). # Idempotency Source: https://docs.soharhealth.com/api-reference/api-reference/idempotency Network failures and timeouts can make it unclear whether an API request succeeded. Use an idempotency key when creating a resource to safely retry the same request without creating a duplicate. Idempotency is supported by the [Create Verification](/api-reference/verifications/create-verification-v2) and [Create Discovery](/api-reference/discovery/create-discovery) APIs. ## Usage Include the optional `Idempotency-Key` header with a UUID v4 value. Generate a new key for each resource you intend to create and reuse that key only when retrying the same request. ```javascript theme={null} const idempotencyKey = crypto.randomUUID(); const response = await axios.post( 'https://api.soharhealth.com/v2/verifications', { patient: { firstName: 'John', lastName: 'Doe', dateOfBirth: '09/20/2006', state: 'CA', memberId: '00000000' }, payerId: '60054', placeOfServiceCode: '10', specialtyCode: 'PSY' }, { headers: { 'Authorization': `Bearer ${accessToken}`, 'Idempotency-Key': idempotencyKey } } ); ``` The first request returns `201 Created`. Retrying the request with the same key also returns `201 Created`, with the ID of the resource created by the first request. Sohar does not create another resource or start processing again. Idempotency keys are scoped to your account, environment, and API. Reusing a key with a different request body does not create a new resource; Sohar returns the original resource ID. Use a new key if any request parameters change. An invalid `Idempotency-Key`, including a UUID of a version other than v4, returns `400 Bad Request`. # Introduction Source: https://docs.soharhealth.com/api-reference/api-reference/introduction The Sohar API follows [REST](https://en.wikipedia.org/wiki/REST) principles. Our API endpoints return JSON-encoded responses, using standard HTTP response codes, authentication and verbs. All requests must be made over HTTPS. Requests can be made in our [production or sandbox environment](/api-reference/api-reference/environments). The sandbox environment exists to support your integration and testing of the Sohar API, and doesn't affect live data. The environment is determined by the credentials used to authenticate the request. It's important to note that while any changes to existing API endpoints and webhook fields that could impact your integration will be communicated in advance, new fields may also be introduced. To ensure seamless integration, it is recommended that your system be designed with flexibility in mind, accommodating potential additions without requiring modification. ## Response Codes Sohar uses standard HTTP response codes to indicate whether an API request succeeded. | Code | Description | | - | - | | `200` | The request succeeded. | | `201` | A create request succeeded and returned the new resource. An idempotent retry returns the resource created by the original request. | | `207` | A batch request was processed. The response contains an individual result and status for each item. | See [Errors](/api-reference/api-reference/errors) for error response formats, status codes, and retry guidance. # Rate Limits Source: https://docs.soharhealth.com/api-reference/api-reference/rate-limits Sohar applies rate limits per customer account across authenticated API requests. Limits use a token bucket, which allows short bursts while enforcing a sustained request rate. Standard accounts can make 10 requests per second, with a burst capacity of 20 requests. Custom rate limits are applied to Enterprise accounts. If you exceed a rate limit, Sohar returns `429 Too Many Requests`: ```json theme={null} { "error": "Too many requests" } ``` ## Handling Rate Limits Retry rate-limited requests with exponential backoff and jitter. Sohar does not currently return a `Retry-After` header, so your integration should increase the delay between consecutive attempts. When retrying a supported create request, reuse its [idempotency key](/api-reference/api-reference/idempotency) to avoid creating a duplicate resource. # Get Token Source: https://docs.soharhealth.com/api-reference/auth/get-token post /oauth/token # Create Cost Estimate Source: https://docs.soharhealth.com/api-reference/cost-estimate/create-cost-estimate post /v1/cost-estimate Creates a cost estimate for medical billing codes based on verification data. # Create Discovery Source: https://docs.soharhealth.com/api-reference/discovery/create-discovery post /v2/discovery # Create Discovery V1 Source: https://docs.soharhealth.com/api-reference/discovery/create-discovery-v1 post /v1/discovery # Get Discovery Source: https://docs.soharhealth.com/api-reference/discovery/get-discovery get /v1/discovery/{discoveryId} # Create Flow Source: https://docs.soharhealth.com/api-reference/flows/create-flow post /v1/flows Creates a Flow. # Publish Flow Template Source: https://docs.soharhealth.com/api-reference/flows/create-flow-template post /v1/flows/{flowId}/templates Publishes a new Flow template version. # Get Network Status Source: https://docs.soharhealth.com/api-reference/network-status/get-network-status get /v1/network-status/{verificationId} # Create Patient Source: https://docs.soharhealth.com/api-reference/patients/create-patient post /v1/patients This API is still available but no longer supported and is planned for deprecation in a future release; users should transition to the [Create Verifications](/api-reference/verifications/create-verification-v2) API. # Get Patient Source: https://docs.soharhealth.com/api-reference/patients/get-patient get /v1/patients/{patientId} This API is still available but no longer supported and is planned for deprecation in a future release. # Get Payer Source: https://docs.soharhealth.com/api-reference/payers/get-payer get /v1/payers/{payerId} # Get Payers Source: https://docs.soharhealth.com/api-reference/payers/get-payers get /v1/payers # Create Provider Source: https://docs.soharhealth.com/api-reference/providers/create-provider post /v1/providers # Create Provider Group Source: https://docs.soharhealth.com/api-reference/providers/create-provider-group post /v1/providers/groups # Create Run Source: https://docs.soharhealth.com/api-reference/runs/create-run post /v1/runs Creates a new Run from a Flow template. # Get Run Source: https://docs.soharhealth.com/api-reference/runs/get-run get /v1/runs/{flowRunId} Returns the latest status of a Run and output when complete. # Update Run Source: https://docs.soharhealth.com/api-reference/runs/update-run put /v1/runs/{flowRunId} Updates callback input for a pending Run. # Create Verification Source: https://docs.soharhealth.com/api-reference/verifications/create-verification-v1 post /v1/verifications This API is still available but no longer supported and is planned for deprecation in a future release; users should transition to the [Create Verifications](/api-reference/verifications/create-verification-v2) API. # Create Verification Source: https://docs.soharhealth.com/api-reference/verifications/create-verification-v2 post /v2/verifications # Create Verifications V1 Source: https://docs.soharhealth.com/api-reference/verifications/create-verifications-v1 post /v1/verifications/batch This API is still available but no longer supported and is planned for deprecation in a future release; users should transition to the [Create Verifications](/api-reference/verifications/create-verification-v2) API. # Get Verification V1 Source: https://docs.soharhealth.com/api-reference/verifications/get-verification-v1 get /v1/verifications/{verificationId} This API is still available but no longer supported and is planned for deprecation in a future release; users should transition to the [Get Verification](/api-reference/verifications/get-verification-v2) API. # Get Verification Source: https://docs.soharhealth.com/api-reference/verifications/get-verification-v2 get /v2/verifications/{verificationId} # Create Webhook Source: https://docs.soharhealth.com/api-reference/webhooks/create-webhook post /v1/webhooks # Create Event Source: https://docs.soharhealth.com/api-reference/webhooks/create-webhook-event post /v1/webhooks/{endpointId}/events # Delete Webhook Source: https://docs.soharhealth.com/api-reference/webhooks/delete-webhook delete /v1/webhooks/{endpointId} # Delete Event Source: https://docs.soharhealth.com/api-reference/webhooks/delete-webhook-event delete /v1/webhooks/{endpointId}/events/{event} # Get Webhooks Source: https://docs.soharhealth.com/api-reference/webhooks/get-webhooks get /v1/webhooks # Building Flows Source: https://docs.soharhealth.com/documentation/flows/building-flows Flows is currently in beta and is subject to change as the platform evolves Flows are defined as YAML workflow templates. A Flow template is a YAML document that defines how a workflow runs: what input it accepts, where execution starts, which states it executes, how it branches, when it pauses for additional input, and what output it returns. In familiar terms, Flows follow a workflow-as-code model for orchestrating Sohar APIs. At the top level, a Flow template has five main parts: * `input`: the schema for the data required to start the Flow * `startsAt`: the first state to execute * `states`: the workflow definition * `output`: the shape of the final result returned by the Run * metadata: optional fields such as `name`, `description`, and `version` ## Template Structure The `input` section defines the contract for starting a Run. This is the shape your application must satisfy when it provides `input`. The `states` section defines the workflow itself. Each state represents a unit of execution, such as calling a Sohar API, making a decision, or waiting for more input. The `output` section defines the final response shape for the Flow. When a Run completes, the API returns the result of evaluating this output mapping for that specific execution. A minimal template looks like this: ``` input: type: object required: - patient properties: patient: type: object required: - firstName - lastName - dateOfBirth - state properties: firstName: type: string lastName: type: string dateOfBirth: type: string state: type: string startsAt: discovery states: discovery: type: request resource: Discovery resultSelector: type: object properties: payerId: type: string value: $response.payerId next: final final: end: true output: type: object properties: payerId: type: string value: $.payerId ``` ## Input Each Flow template defines the input required to start a Run. This is declared in the template's `input` section as a schema. When a Run is created, the `input` provided by the caller must match that schema. In practical terms, the input section defines the contract for using the Flow. It tells you what data must be available at the start of execution, before any states run. For example, a Flow that begins with a Verification request may require input such as patient details, payer information, member ID, place of service code, and specialty code. A Flow that begins with Discovery may require a smaller input shape, such as patient information alone. A simple input definition might look like this: ``` input: type: object required: - patient - payerId - memberId properties: patient: type: object required: - firstName - lastName - dateOfBirth - state properties: firstName: type: string pattern: "^.{1,45}$" example: "John" lastName: type: string dateOfBirth: type: string state: type: string payerId: type: string memberId: type: string ``` Named string properties can include two optional fields: * `pattern`: a non-empty regular expression used to validate supplied values. Matching is substring-based unless you add anchors such as `^` and `$`. * `example`: a non-empty, double-quoted string displayed as a form placeholder. It does not prefill or submit the field. These fields can be used recursively on named string properties, including properties inside arrays of objects. They cannot be used on non-string properties, output mappings, or directly on an array's `items` schema. Invalid patterns, empty values, and examples that are not double-quoted prevent template publication. Creating a Run with an input value that does not match its pattern returns HTTP `400`. When designing a Flow, the input should include everything needed to begin execution. In many cases, this means the input shape will mirror the request payload expected by the first Sohar API the Flow calls, or the shared fields needed across multiple later states. ## States Flows currently support four main state types: * `request` * `choice` * `callback` * `parallel` A state can also be terminal by setting `end: true`. ### Request States A `request` state calls a supported Sohar API as part of the workflow. Use request states when you want the Flow to perform work such as creating a Verification, running Discovery, or invoking another supported product operation. A request state defines the `resource` to call, and it must either specify the `next` state or mark itself as terminal with `end: true`. Request states can also control how data moves through the workflow: * `override` lets you adjust the runtime context before the request runs * `resultSelector` lets you map values from the API response back into the Flow context for use in later states This is the core orchestration mechanism in Flows: each request state turns the template into an executable multi-step API workflow. #### Using Result Selector Use `resultSelector` when a later step needs data from the API response returned by the request state. For example, a Verification request may return a status that you want to use in a later choice state. In that case, `resultSelector` can copy the value into the Flow context: ``` verification: type: request resource: Verification resultSelector: type: object properties: verificationStatus: type: string value: $response.status next: route ``` After this state runs, `$.verificationStatus` is available to the rest of the Flow. #### Using Override Use `override` when a request should run with a modified version of the current runtime context. This is useful when you want to set or replace values for a specific request without changing the original input contract of the Flow. For example, you may want to force a specific payer ID before running a request: ``` verification: type: request resource: Verification override: payerId: "00001" next: final ``` In this example, the request runs with `payerId` set to "00001" in the effective runtime context for that state. ### Choice States A `choice` state adds branching logic. Choice states evaluate conditions in order and take the first matching branch. This lets you model workflow logic such as: * if required data is present, continue to one step * if a result indicates success, take one branch * if a result indicates a pending or error condition, take another If no condition matches, the Flow uses the default branch if one is defined. ### Callback States A `callback` state pauses the workflow and waits for additional input. Use callback states when a Flow cannot continue with the data available at the start of the Run. This is useful for human-in-the-loop workflows, conditional follow-up collection, or integrations where some information becomes available later. When a Run reaches a callback state, it moves to `PENDING`. The callback step defines the input contract for the additional data required to continue. ### Parallel States A `parallel` state runs multiple branches concurrently. Use parallel states when a workflow needs to execute independent operations at the same time rather than sequentially. A parallel state must define at least two branches. Each branch has its own `startsAt` entry point and a `states` map containing the steps for that branch. Branches can include `request` and `choice` states. The Flow waits for all branches to complete before continuing to the `next` state. Each branch contributes its `resultSelector` values back into the shared Flow context. ``` parallel-verifications: type: parallel branches: - startsAt: psy-verification states: psy-verification: type: request resource: Verification override: specialtyCode: PSY resultSelector: type: object properties: psyVerificationId: type: string value: $response.verificationId end: true - startsAt: pch-verification states: pch-verification: type: request resource: Verification override: specialtyCode: PCH resultSelector: type: object properties: pchVerificationId: type: string value: $response.verificationId end: true next: final ``` In this example, two Verification requests run concurrently with different specialty codes. Once both branches complete, the Flow merges the results and continues to the `final` state. ## Context Context is the runtime data available to a Flow as it executes. You can think of it as the working memory for a Run. It begins with the `input` provided when the Run starts, and then evolves as the workflow progresses. At runtime, context is built from: * the initial `input` provided when the Run is created * any `callback` input submitted later while the Run is `PENDING` * any values written back into context by a request state's `resultSelector` This means the context for a Run is not static. It starts with the input contract for the template, then accumulates the data needed for later states. ### Why Context Matters Request states execute against the current context. In practice, this means the data in context needs to match the input shape expected by the Sohar API the state is calling. If a request state invokes Verification, the context must contain the fields that Verification expects. If a later state invokes Discovery or Cost Estimate, the context must contain the fields required by those APIs at that point in the workflow. To determine what fields a request state needs in context, refer to the API documentation for the Sohar product that state calls. In general, the context available at that point in the Flow should match the request shape that product expects. For example: * a Verification request expects a shape like `patient`, `payerId`, `memberId`, `placeOfServiceCode`, and `specialtyCode` * a Discovery request expects a shape like `patient` Because of this, Flow authors should treat context as the contract between states. Each step should either consume fields already present in context or write the fields that later states will need. ## Output Each Flow template also defines the output returned when a Run completes. This is declared in the template's `output` section. Rather than returning the raw response from a single Sohar API, a Flow returns the result of evaluating the template's output mapping for that specific Run. In practical terms, the output section defines the final response contract for the Flow. It lets you decide which values from the workflow should be exposed to the caller, and how those values should be shaped. A simple output definition might look like this: ``` output: type: object properties: verificationStatus: type: string value: $.verificationStatus verificationId: type: string value: $.verificationId ``` In this example, the completed Run returns an object with `verificationStatus` and `verificationId`, regardless of how many states the Flow executed internally to produce those values. When designing a Flow, it is helpful to think of `output` as the public interface of the completed workflow. The Flow may execute several internal states, but the output should expose only the final data the caller actually needs. ## Flow Logic Choice states are how Flows make decisions at runtime. Each `choice` evaluates a variable from the runtime context and applies a single operator. Choices are evaluated from top to bottom, and the first match wins. If nothing matches, the Flow uses the default path. If no default is defined, execution fails. Supported operators are: * `isPresent`, `isNull` * `isTruthy`, `isFalsy` * `stringEquals`, `stringMatches` * `numericEquals`, `lt`, `gt`, `lte`, `gte` A simple branching example: ``` route: type: choice choices: - variable: $.verificationStatus stringEquals: "complete.eligible" next: eligible - variable: $.verificationStatus stringMatches: "^pending\\." next: pending default: ineligible ``` # Introduction Source: https://docs.soharhealth.com/documentation/flows/introduction Flows is a workflow engine for **orchestrating Sohar APIs** into a single automated process. Instead of integrating each API endpoint separately and managing the logic yourself, Flows lets you define a workflow once and run it as a single unit. You can think of it as **workflow-as-code** for common healthcare operations. A Flow can call multiple Sohar products in sequence, branch based on results, pause while waiting for additional input and return a final output when the workflow is complete. At a practical level, a **Flow** is a reusable workflow template, and a **Run** is one execution of that template. A template defines the workflow logic, including what inputs it expects, which states it executes, how it makes decisions and what output it returns. A Run is what happens when your application starts that workflow for a specific request. Flows are useful when the integration you want is bigger than a single API call. For example, you may need to run multiple products in order, apply decision logic between states, or introduce a human-in-the-loop step before continuing. Rather than hard-coding that orchestration in your application, you can define it in a Flow and interact with it through the API. This gives teams a more structured way to build automation on top of Sohar. Developers get a clearer orchestration model, product teams get reusable workflow definitions, and both gain a consistent way to reason about multi-step API behaviour. # Using Flows Source: https://docs.soharhealth.com/documentation/flows/using-flows Flows is currently in beta and is subject to change as the platform evolves Flows gives you a standard way to run multi-step Sohar workflows through the API. From an integration perspective, the model is simple: you choose a Flow template, start a Run, monitor its status, and read the final output when it completes. If the workflow needs additional information partway through, the Run can pause and wait for input before continuing. ## Flows & Runs A **Flow** template is the reusable definition of a workflow. It describes the states the workflow will execute, the input it expects, and the output it produces. A **Run** is a single execution of that template. Each Run represents one real workflow instance, such as processing a specific patient or payer request. ## Starting a Run To use a Flow, your application starts a Run from a template. This can either be started in the Sohar dashboard or using the [Create Run](/api-reference/runs/create-run) API. When a Run is created, you provide the input data required by that template. The API returns a `flowRunId`, which becomes the ID your application uses to track and interact with that workflow execution. Flows are asynchronous and may not complete immediately. This makes them better suited for orchestration, automation, and multi-step processing than a single request-response API call. ## Input Each Flow template defines the input it expects when a Run starts. When creating a Run, your application provides that data as `inputData`. Because Flows are template-driven, the required input can vary between templates. Some Flows have everything they need up front, while others may request additional input later through a callback step. In that case, the initial `inputData` starts the workflow, and a later callback input resumes it. ## Tracking Progress A Run moves through a small set of statuses: * `CREATED`: the Run has been accepted * `IN_PROGRESS`: the workflow is actively executing * `PENDING`: the workflow is paused and waiting for additional input * `COMPLETE`: the workflow finished successfully and output is available * `ERROR`: the workflow ended with an error For most integrations, there are two common patterns: * Poll the [Get Run](/api-reference/runs/get-run) API until the status reaches `COMPLETE`, `PENDING`, or `ERROR` * Listen for webhook events and react when the Run changes state Polling is usually the simplest way to get started. Webhooks are a better fit when you want your system to react to workflow progress asynchronously without repeated status checks. ## Handling Paused Runs Some Flows include callback states. These are pause points where the workflow needs more information before it can continue. When that happens, the Run moves to `PENDING`. At that point, you can submit the required input and resume the workflow using the [Update Run](/api-reference/runs/update-run) API. Once the new input is accepted, the Flow continues execution and transitions back to `IN_PROGRESS`. This is useful for human-in-the-loop workflows, conditional data collection, or integrations where not all required information is available at the start of the process. ## Output The shape of that output is defined in the template. During execution, data is gathered and processed across states, and when the Run reaches `COMPLETE` it returns the template-defined output for that specific workflow instance. ## Versions Flows are versioned through their templates. You can run the latest version of a template or explicitly target a specific version. In practice, this gives teams flexibility during development and change management: * Use the latest version when you want to adopt the current workflow definition automatically * Pin to a specific version when you need stable, repeatable behavior in production # Quickstart Source: https://docs.soharhealth.com/documentation/getting-started/quickstart The most common use case for the Sohar API is to determine the eligibility status and healthcare benefits for a patient. In this tutorial we will create a verification request to Aetna in the [sandbox environment](/api-reference/api-reference/environments#sandbox) using predefined [sandbox values](/documentation/guides/verification#sandbox-values). Create a client ID and client secret for the sandbox environment in the Sohar [dashboard](https://app.soharhealth.com/settings#oauth) and use them to get an access token. ```javascript theme={null} const response = await axios.post( 'https://api.soharhealth.com/oauth/token', { client_id: process.env.SOHAR_CLIENT_ID, client_secret: process.env.SOHAR_CLIENT_SECRET } ); const accessToken = response.data.access_token; ``` Call the [Create Verification](/api-reference/verifications/create-verification-v2) API using your access token. ```javascript theme={null} const response = await axios.post( 'https://api.soharhealth.com/v2/verifications', { patient: { firstName: 'John', lastName: 'Doe', dateOfBirth: '09/20/2006', state: 'CA', memberId: '00000000' }, payerId: '60054', placeOfServiceCode: '10', specialtyCode: 'PSY' }, { headers: { 'Authorization': `Bearer ${accessToken}` } } ); const verificationId = response.data.verificationId; ``` Call the [Get Verification](/api-reference/verifications/get-verification-v2) API with the `verificationId` to get the response. Note that it can take some time to deliver the response - you can either poll the endpoint or subscribe to [webhook events](/documentation/webhooks/events). ```javascript theme={null} const response = await axios.get( `https://api.soharhealth.com/v2/verifications/${verificationId}`, { headers: { 'Authorization': `Bearer ${accessToken}` } } ); ``` # Discovery Source: https://docs.soharhealth.com/documentation/guides/discovery Insurance discovery is the process of searching for a patient's coverage when their member ID and payer are not known. There are a number of use cases for insurance discovery, including: * increasing conversion during patient intake * searching for a patient's coverage if the information they provide is inaccurate * searching for a patient's coverage when they change insurance plans The [Create Discovery](/api-reference/discovery/create-discovery) API endpoint details the required parameters for initiating an insurance discovery request with Sohar. The [Get Discovery](/api-reference/discovery/get-discovery) API endpoint details the values that are returned if an insurance discovery request is successful. These values can be used with the [Create Verification](/api-reference/verifications/create-verification-v2) API endpoint to determine eligibility and retrieve benefits information. ## Sandbox Values Use the following values for the `state` parameter of the [Create Discovery](/api-reference/discovery/create-discovery) API endpoint to return the corresponding values for `memberId` and `payerId`. You must use credentials for the [sandbox environment](/api-reference/api-reference/environments#sandbox) to create sandbox requests. | State | Payer ID | Member ID | | - | - | - | | CA | 60054 | 00000000 | | DE | 60054 | 00000001 | | FL | 60054 | 10000000 | | GA | 60054 | 10000001 | | IL | 60054 | 10000002 | | KY | OSCAR | 00000000 | | MA | 06111 | 00000000 | | OH | null | null | | NY | 62308 | 00000000 | | TX | 84980 | 00000000 | # Network Status Source: https://docs.soharhealth.com/documentation/guides/network-status Network Status describes your relationship with payers. You would be considered **In Network** if you have contracts in place for a certain plan, or **Out of Network** if you don't. You can create rules in the Sohar dashboard to cover your payer contracts and manage any exceptions. The [Get Network Status](/api-reference/network-status/get-network-status) API endpoint can be used to programmatically retrieve the network status for a given `verificationId`, based on your rules. # Verification Source: https://docs.soharhealth.com/documentation/guides/verification Verifications are a core concept of the Sohar platform. A Verification represents a request for eligibility status and benefits information for a given patient. ## Providers A National Provider Identifier (NPI) is a unique 10-digit number assigned to healthcare providers in the U.S. There are two types of NPIs relevant here: **Type 1 (rendering provider)**, which identifies the individual delivering care (e.g., a doctor), and **Type 2 (group provider)**, which identifies the organization or practice (e.g., a clinic). Some payers require an NPI for a credentialed provider in order to return patient data. Depending on the payer, this may be a Type 1 or Type 2 NPI. If a required NPI is missing, the request will fail with an `error.payer.npi` response. Sohar handles this complexity automatically using the providers enrolled in your account. To avoid provider-related errors, make sure your providers are enrolled - either through the dashboard or programmatically using the [Create Provider](/api-reference/providers/create-provider) API. To restrict provider selection to a specific provider group, include that group's `providerGroupId` in the verification request. ## Statuses | Status | Description | | - | - | | complete.eligible | The verification was successfully completed; patient is confirmed active coverage and covered for the provided specialty code. | | complete.ineligible | The verification was successfully completed; Patient is either inactive and/or not covered for the provided specialty code. | | error.member.id | The member ID was not recognized by the payer, or a different payer ID should be used. | | error.member.dob | The patient's Date of Birth was not recognized by the payer, or a different payer ID should be used. | | error.member.name | The patient's name was not recognized by the payer, or a different payer ID should be used. This is often due to incorrect spelling or nicknames. | | error.payer | The payer has been unavailable for over 24 hours and the Sohar Operations team has been unable to resolve the verification via payer portal or phone call. This status may also occur when the verification requires manual contact with the payer but manual resolution is not enabled for your account. | | error.payer.npi | The provided NPI is not recognized by the payer. Some payers require an NPI on file in order to provide benefits. Some payers require a rendering NPI in order to provide benefits, for example Blue Cross Blue Shield of Texas. | | pending | The verification could not be resolved immediately, typically because the payer API was unavailable. A verification with this status will be followed by one of the statuses listed above. | ## Sandbox Values Use the following `payerId` and `memberId` values in the [sandbox environment](/api-reference/api-reference/environments#sandbox) for predefined responses. | Payer ID | Member ID | Status | | - | - | - | | 60054 | 00000000 | complete.eligible | | 60054 | 00000001 | complete.ineligible | | 60054 | 10000000 | error.member.id | | 60054 | 10000001 | error.member.dob | | 60054 | 10000002 | error.member.name | | OSCAR | 00000000 | error.payer.npi | | 06111 | 00000000 | pending | # Payers Source: https://docs.soharhealth.com/documentation/resources/payers A payer is the insurance organization responsible for adjudicating a patient's benefits. In Sohar, payers are represented by a stable `payerId` and a human-friendly `payerName`. You can retrieve the payer list with [Get Payers](/api-reference/payers/get-payers) and look up a specific payer with [Get Payer](/api-reference/payers/get-payer). ## Payer IDs and aliases Payer IDs are the identifiers Sohar expects in API requests. If an input payer is incorrect, Sohar may resolve it to the correct payer and return the corrected `payerId` and `payerName` in the response. Some payers also have alias IDs and alias names; these are alternative identifiers and payer names used by other systems that map to the same payer in Sohar. The Get Payers and Get Payer APIs return these as `aliasPayerIds` and `aliasPayerNames`. ## Group Payers Group Payers are a Sohar concept that roll up related payer IDs under a single parent grouping. This is useful when a payer operates multiple regional plans, product lines, or legacy brands that you want to manage together. Each Group Payer has a Group ID, listed in the Sohar dashboard in the Payers view. For example, the Group ID for Medicaid is `SH03D959`. Pass a Group ID as the `payerId` value when calling the [Create Verification V2](/api-reference/verifications/create-verification-v2) API. Sohar uses the patient's member ID and state to select a payer within the group. If the group cannot be resolved, the API returns `400 Bad Request` for `payerId`. * Use Group Payers when the patient indicates a broad payer (for example “Medicaid”) but the regional payer is unclear. * When available, prefer a specific `payerId` for the patient’s coverage to avoid ambiguity. If you need help mapping payer IDs to a Group Payer, reach out to Sohar support. # Data Analytics Source: https://docs.soharhealth.com/documentation/tutorials/data-analytics This guide shows you how to build a pipeline that ingests webhook-triggered Verification data from Sohar into your data warehouse. This pattern is ideal for: * Performing analytics or business intelligence on structured API data * Creating structured data exports to import into external tools * Decoupling real-time webhook handling from downstream ETL * Scaling data pipelines efficiently ## Setup Create a client ID and client secret in the Sohar [dashboard](https://app.soharhealth.com/settings#oauth). Configure a [webhook endpoint](/documentation/webhooks/introduction) to listen for events. Subscribe your endpoint to the `verification.updated` event. Configure an Amazon S3 bucket with programmatic write permissions via IAM user or role. In this guide we reference Amazon S3, but the same process also applies to Google Cloud Storage and similar services. ## Workflow The diagram below outlines the workflow we will build to transfer Verification data from Sohar to your data warehouse. Data analytics diagram ## Handle Webhook Events Here's a basic Express route to receive webhook events from Sohar and save the Verification response to Amazon S3: ```js theme={null} const express = require('express'); const axios = require('axios'); const AWS = require('aws-sdk'); const app = express(); app.use(express.json()); // Configure AWS SDK AWS.config.update({ region: process.env.AWS_REGION }); const s3 = new AWS.S3(); const BUCKET = process.env.S3_BUCKET_NAME; app.post('/webhooks', async (req, res) => { // Retrieve the verification ID from the request body const verificationId = req.body['verificationId']; // Generate an access token const createTokenResponse = await axios.post( 'https://api.soharhealth.com/oauth/token', { client_id: process.env.SOHAR_CLIENT_ID, client_secret: process.env.SOHAR_CLIENT_SECRET } ); const accessToken = createTokenResponse.data.access_token; // Retrieve details of the completed verification const getVerificationResponse = await axios.get( `https://api.soharhealth.com/v2/verifications/${verificationId}`, { headers: { 'Authorization': `Bearer ${accessToken}` } } ); const verificationData = getVerificationResponse.data; // Save to Amazon S3 const timestamp = new Date().toISOString(); const folder = timestamp.split('T')[0].replace(/-/g, '/'); // "2025/06/01" const key = `sohar-data/${folder}/${verificationId}.json`; await s3.putObject({ Bucket: BUCKET, Key: key, Body: JSON.stringify(verificationData), ContentType: 'application/json', }).promise(); console.log(`Saved JSON to S3: ${key}`); res.status(200).send({ success: true }); }); app.listen(3000, () => console.log(`Listening on port 3000`)); ``` ## Load to the Data Warehouse Now that data is in S3, you can: * Use **AWS Glue** to crawl and ETL the data into Redshift or Athena * Use **dbt + dbt-s3** to ELT from S3 into Snowflake or BigQuery * Use **Airbyte**, **Fivetran**, or **custom scripts** for downstream ingestion # Patient Intake Source: https://docs.soharhealth.com/documentation/tutorials/patient-intake This guide walks through a common approach to integrating Sohar into your patient intake flow. When a patient submits their information (first name, last name, date of birth, insurance information etc.), you send it to Sohar to process, check eligibility and return the result back to your system in real time. Patient intake diagram ## Setup Create a client ID and client secret in the Sohar [dashboard](https://app.soharhealth.com/settings#oauth). Create credentials for the [sandbox environment](/api-reference/api-reference/environments#sandbox) to get started quickly without the need for actual patient data. Configure a [webhook endpoint](/documentation/webhooks/introduction) to listen for events. If you are using the [sandbox environment](/api-reference/api-reference/environments#sandbox), subscribe your endpoint to the `sandbox.verification.updated` event. If you are using the production environment, subscribe to the `verification.updated` event. ## Workflow The diagram below outlines the workflow we will build to take your patient through the intake flow and handle the response from Sohar. Patient intake diagram ## Collect Patient Data Create an interface to capture the following information at minimum: * First Name * Last Name * Date of Birth * State (2-letter code, e.g. CA) * Payer ID * Member ID You can use the [Get Payers](/api-reference/payers/get-payers) API to retrieve a list of payer IDs. We recommend adding the Sohar payer IDs to your existing payer list, and presenting the list to your patients during intake. ## Create a Verification Pass the information collected in the previous step to the [Create Verification](/api-reference/verifications/create-verification-v2) API. You will also need to specify the `placeOfServiceCode` and `specialtyCode`. In this example we are interested in benefits information for a telehealth consultation (place of service code `10`) with a psychotherapist (specialty code `PSY`). ```javascript theme={null} const response = await axios.post( 'https://api.soharhealth.com/v2/verifications', { patient: { firstName: 'John', lastName: 'Doe', dateOfBirth: '09/20/2006', state: 'CA', memberId: '00000000' }, payerId: '60054', placeOfServiceCode: '10', specialtyCode: 'PSY' }, { headers: { 'Authorization': `Bearer ${accessToken}` } } ); ``` ## Handle Webhook Events Once the Verification request is complete, the response will be posted to all subscribed webhook endpoints. This is an example of the `verification.updated` and `sandbox.verification.updated` webhook payloads: ```json theme={null} { "verificationId": "990cdad8-1438-4bbd-8b55-120b56e87540", "id": "123456", "status": "complete.eligible" } ``` Sohar responds asynchronously via webhooks, typically within 30 seconds. The example below demonstrates how to retrieve information once the response is ready. ```javascript theme={null} const express = require('express'); const axios = require('axios'); const app = require('express')(); app.use(express.json()); app.post('/webhooks', async (req, res) => { // Retrieve the verification ID from the request body const verificationId = req.body['verificationId']; // Generate an access token const createTokenResponse = await axios.post( 'https://api.soharhealth.com/oauth/token', { client_id: process.env.SOHAR_CLIENT_ID, client_secret: process.env.SOHAR_CLIENT_SECRET } ); const accessToken = createTokenResponse.data.access_token; // Retrieve details of the completed verification const getVerificationResponse = await axios.get( `https://api.soharhealth.com/v2/verifications/${verificationId}`, { headers: { 'Authorization': `Bearer ${accessToken}` } } ); // Handle routing logic based on the Sohar response const verificationData = getVerificationResponse.data; const status = verificationData.status; res.status(200).send({ success: true }); }); app.listen(3000, () => console.log('Running on port 3000')); ``` You can store the Sohar response in your system for [data analytics](/documentation/tutorials/data-analytics) purposes, or load it into external systems such as your EHR. ## Patient Routing Depending on the response you receive from Sohar, it might make sense to route the patient to different flows. The flows detailed below are most commonly used when integrating with Sohar. Patient routing ### Schedule Consultation This is the ideal outcome. The status is `complete.eligible`, indicating that the request is complete, the patient has active coverage and they are eligible for the requested service. The patient can proceed through the intake funnel - often the next step is to schedule their initial consultation. ### Request Alternative Insurance The status `complete.ineligible` indicates that the request is complete but the patient either doesn't have active coverage or they are not eligible for the requested service. Perhaps their coverage has lapsed or they are using an outdated member ID. In this instance it might make sense to ask the patient if they have alternative insurance information. If the patient is able to provide alternative information, this information can be submitted to the [Create Verification](/api-reference/verifications/create-verification-v2) API. ### Review Intake Data A member error status indicates that there was something wrong with the information submitted by the patient. This could either be an `error.member.id` status, an `error.member.name` status or an `error.member.dob` status. Ask the patient to review the information they submitted, and if they are able to correct any mistakes then the updated information can be submitted to the [Create Verification](/api-reference/verifications/create-verification-v2) API. ### Manual Workflow There are two types of payer error status that can be returned. `error.payer` indicates that the payer has been unavailable for at least 24 hours - it is unlikely that you will see this status returned during patient intake. `error.payer.npi` indicates that the payer doesn't recognise the NPI that Sohar included in the request. [Here](/documentation/guides/verification#providers) is some information about how to manage providers in your account in order to avoid this response. We typically see customers implement manual workflows to handle this status or any other unexpected response. This might involve contacting the patient to clarify the information they submitted. # Event Types Source: https://docs.soharhealth.com/documentation/webhooks/events List of supported event types and their payload. ### `verification.updated` Occurs whenever a production verification has been completed. ```json theme={null} { "event": "verification.updated", "verificationId": "990cdad8-1438-4bbd-8b55-120b56e87540", "id": "123456", "status": "complete.eligible" } ``` ### `sandbox.verification.updated` Occurs whenever a sandbox verification has been completed. ```json theme={null} { "event": "sandbox.verification.updated", "verificationId": "990cdad8-1438-4bbd-8b55-120b56e87540", "id": "123456", "status": "complete.eligible" } ``` ### `verification.pending` Occurs whenever a production verification has not been resolved immediately. ```json theme={null} { "event": "verification.pending", "verificationId": "990cdad8-1438-4bbd-8b55-120b56e87540", "id": "123456", "status": "pending" } ``` ### `sandbox.verification.pending` Occurs whenever a sandbox verification has not been resolved immediately. ```json theme={null} { "event": "sandbox.verification.pending", "verificationId": "990cdad8-1438-4bbd-8b55-120b56e87540", "id": "123456", "status": "pending" } ``` ### `discovery.updated` Occurs whenever a discovery request is updated. ```json theme={null} { "event": "discovery.updated", "discoveryId": "fb701ac1-1246-4860-b1ec-bd916b97a990", "status": "complete", "id": "123456" } ``` ### `sandbox.discovery.updated` Occurs whenever a sandbox discovery request is updated. ```json theme={null} { "event": "sandbox.discovery.updated", "discoveryId": "fb701ac1-1246-4860-b1ec-bd916b97a990", "status": "complete", "id": "123456" } ``` ### `flow.updated` Occurs when the status or state of a Flow Run is updated. ```json theme={null} { "event": "flow.updated", "flowRunId": "990cdad8-1438-4bbd-8b55-120b56e87540", "status": "COMPLETE", "stateId": "create-verification" } ``` ### `sandbox.flow.updated` Occurs when the status or state of a sandbox Flow Run is updated. ```json theme={null} { "event": "sandbox.flow.updated", "flowRunId": "990cdad8-1438-4bbd-8b55-120b56e87540", "status": "ERROR", "stateId": "create-verification" } ``` ### `flow.callback` Occurs when a Flow Run reaches a callback state and is waiting for additional input. ```json theme={null} { "event": "flow.callback", "flowRunId": "990cdad8-1438-4bbd-8b55-120b56e87540", "input": { "type": "object", "properties": { "memberId": { "type": "string" } } } } ``` ### `sandbox.flow.callback` Occurs when a sandbox Flow Run reaches a callback state and is waiting for additional input. ```json theme={null} { "event": "sandbox.flow.callback", "flowRunId": "990cdad8-1438-4bbd-8b55-120b56e87540", "input": { "type": "object", "properties": { "memberId": { "type": "string" } } } } ``` # Introduction Source: https://docs.soharhealth.com/documentation/webhooks/introduction Webhooks notify your application when events occur in the Sohar platform. They use HTTPS and deliver JSON payloads so you can respond to updates in real time. In your application, create a route that accepts POST requests. Below is an example using Node.js with Express: ```js theme={null} const express = require('express'); const app = express(); app.use(express.json()); app.post('/webhooks', (req, res) => { const event = req.body; console.log(event); res.status(200).end(); }); app.listen(3000, () => console.log('Listening on port 3000')); ``` Whenever you receive an event, respond with `HTTP 200 OK` to acknowledge receipt. You can create a tunnel to your localhost server using a tool like [ngrok](https://ngrok.com/download). For example: `https://fa8b-9-27-207-123.ngrok-free.app/webhooks` You must use credentials for the [production environment](/api-reference/api-reference/environments#production) to call the [Create Webhook](/api-reference/webhooks/create-webhook) and register your endpoint, which will generate an `endpointId`. With these credentials, call the [Create Event](/api-reference/webhooks/create-webhook-event) API to subscribe your endpoint to events. For testing, the `sandbox.verification.updated` event is recommended. Even though webhooks are managed by production credentials, all webhook endpoints can subscribe to production and sandbox events. Send a few test requests to confirm that your endpoint receives events. If your endpoint is subscribed to the `sandbox.verification.updated` event, you can call the [Create Verification](/api-reference/verifications/create-verification-v2) API with sandbox credentials and [sandbox values](/documentation/guides/verification#sandbox-values) for testing purposes. After testing, deploy your endpoint to your production environment. Use the [Create Webhook](/api-reference/webhooks/create-webhook) API to register your production URL so that live events can be delivered. # Security Source: https://docs.soharhealth.com/documentation/webhooks/security Webhook signing secrets can be used to verify that incoming requests genuinely originate from our systems and haven't been tampered with. To access these secrets in the Svix Portal, open an endpoint's detail view from the [Webhooks](https://app.soharhealth.com/webhooks) page in your dashboard, then select **Open Svix Portal** from the menu in the top-right corner. Sohar webhooks use [Svix](https://www.svix.com/) for secure message delivery. To verify the authenticity of these webhooks, you must: * Use the provided webhook secret. * Extract and process the `svix-id`, `svix-timestamp`, and `svix-signature` headers. * Use the raw body of the request to compute the HMAC signature. This is a JavaScript example. Other language examples are available in the [Svix documentation](https://docs.svix.com/receiving/verifying-payloads/how). ```bash theme={null} npm install svix ``` ```javascript theme={null} import { Webhook } from 'svix'; const secret = process.env.WEBHOOK_SECRET; // Replace with your actual webhook secret // Headers received from the webhook const headers = { 'svix-id': 'msg_bNaGN5s2IJgP0aeHcgjlmOzh', 'svix-timestamp': '1750612550', 'svix-signature': 'v1,cIoc4hu+u+C4V8o72ynm2z4tNBzu+5tcNvGyc4ELnUY=', }; const payload = '{"status": "complete"}'; // Raw request body const wh = new Webhook(secret); // Throws an error if verification fails wh.verify(payload, headers); ``` Always use the raw request body when verifying webhooks, as even minor changes can invalidate the cryptographic signature. Be cautious with frameworks that automatically parse and re-serialize JSON bodies - this transformation can alter the payload and cause signature verification to fail.