> ## Documentation Index
> Fetch the complete documentation index at: https://docs.silnahealth.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Put Patient Plan

<Warning>
  The default behavior of this API has destructive properties! If you have an existing primary plan for a patient
  and you create a new primary plan for the same patient, the existing primary plan will be deleted/archived and all
  in progress benefits check and prior authorizations will be withdrawn! If you want to protect against this behavior,
  we recommend setting conflict\_behavior=RAISE\_ERROR.
</Warning>

## Behavior Overview

This API has two flows: update and create. We trigger
the update flow if we find a plan for the input patient with a matching `source_id` or we determine the requested plan to be a duplicate.
Else we trigger the create flow. Since all fields are immutable on the patient plan record except for the `source_id`,
we will only update the `source_id` field in the case when we determine the patient plan to be a duplicate.
This means that in the case of `source_id` match, this API will make no updates and will just return the found
patient plan.

### Patient Plans Deduplication

If there is no `source_id` match, then we will run our deduplication logic. This is necessary to prevent accidental
archival of existing patient plans in the case when `source_ids` might be configured incorrectly. We support three deduplication strategies:

1. `MEMBER_NUMBER` (default): Our deduplication logic will check to see that there is no existing
   plan for the input patient with the same member number. If there is an existing patient plan with the same member number,
   we go to the update flow as described above. If not, we go to the create flow.
2. `MEMBER_NUMBER_AND_PAYOR`: We use both the passed in `payor_entity_id`and `member_number` to determine if it is a duplicate. So, we only go to the update flow if both `payor_entity_id`
   and `member_number` match an existing patient plan for the input patient. Else we go to the create flow.
3. `MEMBER_NUMBER_PAYOR_AND_ORDER`: We use the passed in `payor_entity_id`, `member_number`, and `plan_order_number` to determine if it is a duplicate. We go to the update flow if all of
   `payor_entity_id`, `member_number`, and `plan_order_number` match an existing patient plan for the input patient. Else, we go to the create flow. Please note that this strategy
   would allow duplicate plans in different plan slots. For example, you could have a plan with Aetna and member number `12345` in both the primary and secondary plan slots.

### Handling Conflicts

Using the `conflict_strategy` field allows you to configure whether we want to automatically replace an existing plan
if we determine that the `source_ids` are different and that the request is not for a `duplicate plan`.

* The default is `REPLACE` and will result in the deletion/archival of the existing plan
* `RAISE_ERROR` will return a Conflict Error (http status of 409)
* `RAISE_ERROR_ON_AUTH_WITHDRAWAL` will return a Conflict Error (409) only if replacing the plan would lead to withdrawing
  an in progress Prior Authorization. This is a good flag to pass if your system allows edits to member numbers on existing plans and you
  have an implementation which always propagates your system's changes into Silna. Ideally, you should design a solution which
  does not require this.

## Source Ids

Source Ids allow you to control when plans go through the update flow or the create flow. As a result, it is probably the
most critical part of integrating with this API. In this section, we will go in depth on two approaches: Forcing Replacement on Member Number or Payor changes and Forcing Replacement on just Member Number changes.
Please be aware that these are not the only options and you should reach out if you want to discuss another solution for your needs!

### Forcing Replacement on Member Number or Payor Changes

If your system's "Patient Plan" record is mutable and allows updates to the `member_number` or `payor`,
we recommend using a `source_id` format which includes these two fields (ex. `{YOUR_SYSTEMS_PATIENT_PLAN_ID}-{MEMBER_NUMBER}-{PAYOR_ID}`).
This will ensure that if either `member_number` or `payor` changes, we will create a new plan for the patient during a [PUT Patient Plan](/api-reference/v1patientplanresource/put-patient-plan) call.

If your system's "Patient Plan" record only allows updates to the `member_number` (i.e. you would create an entirely new plan when changing the insurance),
we recommend using a `source_id` format which includes the `member_number` field (ex. `{YOUR_SYSTEMS_PATIENT_PLAN_ID}-{MEMBER_NUMBER}`).
This will ensure that if the `member_number` changes, we will create a new plan for the patient during a [PUT Patient Plan](/api-reference/v1patientplanresource/put-patient-plan) call.

If your system has the same immutability guarantees as Silna, then you can use a `source_id` that is just your systems id for the "Patient Plan" record (ex. `{YOUR_SYSTEMS_PATIENT_PLAN_ID}`).

If you want to go down this route, you should set `deduplication_strategy=MEMBER_NUMBER_AND_PAYOR`. You should consider
setting `conflict_strategy=RAISE_ERROR_ON_AUTH_WITHDRAWAL` if your system allows minor updates to patient plans and you
still plan on calling Silna during that flow.

### Forcing Replacement on Just Member Number Changes

* Use a `source_id` that is just your systems id for the "Patient Plan" record (ex. `{YOUR_SYSTEMS_PATIENT_PLAN_ID}`) if you have the same immutability guarantees as Silna
* If you don't have the same immutability guarantees, then use a member number like `{YOUR_SYSTEMS_PATIENT_PLAN_ID}-{MEMBER_NUMBER}`.

If you want to go down this route, you should set `deduplication_strategy=MEMBER_NUMBER`. You should consider
setting `conflict_strategy=RAISE_ERROR_ON_AUTH_WITHDRAWAL` if your system allows minor updates to patient plans and you
still plan on calling Silna during that flow.

### Why would I choose one over the other?

We recommend the first approach as it handles more complex cases where the different plans can have the same member number.
This is common with Medicaid MCOs and plans which use SSNs. The downside of this approach is that it can lead to more patient
plan deletions/archivals.

The second approach could be a good choice if you care more about preventing accidental deletion/archival of plans and are
fine with some workflows still being handled in the Silna application.


## OpenAPI

````yaml put /public/v1/patient-plans/
openapi: 3.0.2
info:
  title: Silna Public API
  version: '1.0'
servers:
  - url: https://app.silnahealth.com/api
security:
  - bearerAuth: []
paths:
  /public/v1/patient-plans/:
    put:
      tags:
        - V1PatientPlanResource
      summary: Put Patient Plan
      operationId: V1PatientPlanResource.put
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/V1PatientPlanPut'
        description: |2-

              Request schema for updating a patient plan
              
      responses:
        '200':
          description: |2-

                Response schema for creating a patient plan
                
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/V1PatientPlanPutResponse'
          headers:
            X-RateLimit-Limit:
              schema:
                type: integer
                description: The maximum number of requests allowed in the time window
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: The number of requests remaining in the current time window
            X-RateLimit-Reset:
              schema:
                type: integer
                description: The time when the rate limit will reset, in Unix timestamp
            Retry-After:
              schema:
                type: number
                description: The number of seconds to wait before making another request
        '201':
          description: |2-

                Response schema for creating a patient plan
                
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/V1PatientPlanCreateResponse'
          headers:
            X-RateLimit-Limit:
              schema:
                type: integer
                description: The maximum number of requests allowed in the time window
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: The number of requests remaining in the current time window
            X-RateLimit-Reset:
              schema:
                type: integer
                description: The time when the rate limit will reset, in Unix timestamp
            Retry-After:
              schema:
                type: number
                description: The number of seconds to wait before making another request
        '400':
          description: ''
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationError'
          headers:
            X-RateLimit-Limit:
              schema:
                type: integer
                description: The maximum number of requests allowed in the time window
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: The number of requests remaining in the current time window
            X-RateLimit-Reset:
              schema:
                type: integer
                description: The time when the rate limit will reset, in Unix timestamp
            Retry-After:
              schema:
                type: number
                description: The number of seconds to wait before making another request
        '401':
          description: ''
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AuthenticationError'
          headers:
            X-RateLimit-Limit:
              schema:
                type: integer
                description: The maximum number of requests allowed in the time window
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: The number of requests remaining in the current time window
            X-RateLimit-Reset:
              schema:
                type: integer
                description: The time when the rate limit will reset, in Unix timestamp
            Retry-After:
              schema:
                type: number
                description: The number of seconds to wait before making another request
        '404':
          description: ''
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ObjectNotFoundError'
          headers:
            X-RateLimit-Limit:
              schema:
                type: integer
                description: The maximum number of requests allowed in the time window
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: The number of requests remaining in the current time window
            X-RateLimit-Reset:
              schema:
                type: integer
                description: The time when the rate limit will reset, in Unix timestamp
            Retry-After:
              schema:
                type: number
                description: The number of seconds to wait before making another request
        '409':
          description: ''
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ConflictError'
          headers:
            X-RateLimit-Limit:
              schema:
                type: integer
                description: The maximum number of requests allowed in the time window
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: The number of requests remaining in the current time window
            X-RateLimit-Reset:
              schema:
                type: integer
                description: The time when the rate limit will reset, in Unix timestamp
            Retry-After:
              schema:
                type: number
                description: The number of seconds to wait before making another request
        '429':
          description: ''
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TooManyRequestsError'
          headers:
            X-RateLimit-Limit:
              schema:
                type: integer
                description: The maximum number of requests allowed in the time window
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: The number of requests remaining in the current time window
            X-RateLimit-Reset:
              schema:
                type: integer
                description: The time when the rate limit will reset, in Unix timestamp
            Retry-After:
              schema:
                type: number
                description: The number of seconds to wait before making another request
components:
  schemas:
    V1PatientPlanPut:
      description: Request schema for updating a patient plan
      properties:
        member_number:
          maxLength: 80
          minLength: 2
          title: Member Number
          type: string
        group_number:
          default: null
          title: Group Number
          nullable: true
          maxLength: 80
          minLength: 2
          type: string
        start_date:
          default: null
          title: Start Date
          nullable: true
          format: date-time
          type: string
        end_date:
          default: null
          title: End Date
          nullable: true
          format: date-time
          type: string
        payor_entity_id:
          format: uuid
          title: Payor Entity Id
          type: string
        insurance_type:
          $ref: '#/components/schemas/InsuranceType'
          default: null
          description: The type of insurance
          nullable: true
        source_id:
          description: >-
            Unique identifier for the patient plan. This is generated and
            supplied by API clients
          title: Source Id
          type: string
        patient_id:
          format: uuid
          title: Patient Id
          type: string
        plan_order_number:
          description: The order number of the plan (1 for primary, 2 for secondary, etc)
          title: Plan Order Number
          type: integer
        insurance_card_file_id:
          default: null
          description: The file ID corresponding to the front of the insurance card
          title: Insurance Card File Id
          nullable: true
          format: uuid
          type: string
        insurance_card_back_file_id:
          default: null
          description: The file ID corresponding to the back of the insurance card
          title: Insurance Card Back File Id
          nullable: true
          format: uuid
          type: string
        conflict_behavior:
          $ref: '#/components/schemas/APIPatientPlanPutConflictBehavior'
          default: REPLACE
          description: >-
            The behavior to take when there is a conflict with an existing
            patient plan.REPLACE (default) will replace the existing plan (this
            will halt all in progress benefits checks and prior authorizations
            for the plan). RAISE_ERROR will raise an error if there is a
            conflict. RAISE_ERROR_ON_AUTH_WITHDRAWAL will raise an error if
            there are active prior authorizations that would be withdrawn. The
            default behavior is REPLACE
          nullable: true
        deduplication_strategy:
          $ref: '#/components/schemas/DeduplicationStrategy'
          default: MEMBER_NUMBER
          description: >-
            The strategy to use for deduplicating patient plans. MEMBER_NUMBER
            (default) checks only the member number. MEMBER_NUMBER_AND_PAYOR
            checks both member number and payor entity for deduplication.
            MEMBER_NUMBER_PAYOR_AND_ORDER checks member number, payor entity,
            and plan order number for deduplication.
          nullable: true
      required:
        - member_number
        - payor_entity_id
        - source_id
        - patient_id
        - plan_order_number
      title: V1PatientPlanPut
      type: object
      x-folder: public_api
    V1PatientPlanPutResponse:
      description: Response schema for creating a patient plan
      properties:
        patient_plan_id:
          format: uuid
          title: Patient Plan Id
          type: string
      required:
        - patient_plan_id
      title: V1PatientPlanPutResponse
      type: object
      x-folder: public_api
    V1PatientPlanCreateResponse:
      description: Response schema for creating a patient plan
      properties:
        patient_plan_id:
          format: uuid
          title: Patient Plan Id
          type: string
      required:
        - patient_plan_id
      title: V1PatientPlanCreateResponse
      type: object
      x-folder: public_api
    ValidationError:
      type: object
      required:
        - message
      properties:
        message:
          type: string
          description: Human readable error message
      x-folder: null
    AuthenticationError:
      type: object
      required:
        - message
      properties:
        message:
          type: string
          description: Human readable error message
        type:
          $ref: '#/components/schemas/PublicApiErrorType'
      x-folder: null
    ObjectNotFoundError:
      type: object
      required:
        - message
      properties:
        message:
          type: string
          description: Human readable error message
      x-folder: null
    ConflictError:
      type: object
      required:
        - message
      properties:
        message:
          type: string
          description: Human readable error message
      x-folder: null
    TooManyRequestsError:
      type: object
      required:
        - message
      properties:
        message:
          type: string
          description: Human readable error message
      x-folder: null
    InsuranceType:
      type: string
      enum:
        - COMMERCIAL
        - MEDICARE
        - MEDICAID
        - REGIONAL_CENTER
        - WORKERS_COMPENSATION
        - AUTO_INSURANCE
      x-folder: patient
    APIPatientPlanPutConflictBehavior:
      type: string
      enum:
        - RAISE_ERROR
        - REPLACE
        - RAISE_ERROR_ON_AUTH_WITHDRAWAL
      x-folder: patient
    DeduplicationStrategy:
      type: string
      enum:
        - MEMBER_NUMBER
        - MEMBER_NUMBER_AND_PAYOR
        - MEMBER_NUMBER_PAYOR_AND_ORDER
      x-folder: patient
    PublicApiErrorType:
      type: string
      enum:
        - AUTH_INVALID_REQUEST_HEADER
        - AUTH_INVALID_CREDENTIALS
      x-folder: null
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer

````