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

# Patient Payment

> Webhook endpoint for processing patient payments from external systems (e.g., Stripe via Elation). Updates the associated claim with payment information and handles overpayments by creating unallocated patient credits.

## Overview

This webhook endpoint allows external systems (e.g., payment processors like Stripe via Elation) to post patient payments directly to Cair Health. When a patient makes a payment, you can send the payment information to this endpoint, and it will automatically update the associated claim with the payment details.

## Use Cases

* **Payment Processing Integration**: Integrate with payment processors (Stripe, Square, etc.) to automatically record patient payments
* **EHR Integration**: Connect with EHR systems like Elation to sync patient payment data
* **Automated Payment Recording**: Automatically update claims when payments are received through external systems

## Authentication

This endpoint requires JWT access token authentication, consistent with all other public API endpoints.

First, obtain an access token by calling the `/api/token` endpoint with your `clientId` and `clientSecret`:

```bash theme={null}
curl -X POST https://forecaster.cairhealth.com/api/token \
  -H "Content-Type: application/json" \
  -d '{
    "clientId": "your-client-id",
    "clientSecret": "your-client-secret"
  }'
```

Then include the access token in the Authorization header:

```
Authorization: Bearer <accessToken>
```

Your `clientId` and `clientSecret` can be found in your [admin panel](https://forecaster.cairhealth.com/admin-panel).

## Request Body

<ParamField body="billId" type="string" required>
  The Elation bill.id that maps to the Claim identifier. This should match the
  Claim identifier with system
  `https://fhir.cairhealth.com/fhir/identifier/claim-id`.
</ParamField>

<ParamField body="paymentAmount" type="number" required>
  The payment amount in USD. Must be a positive number.
</ParamField>

<ParamField body="paymentDate" type="string" required={false}>
  The date of the payment in ISO 8601 format (e.g., "2024-01-15" or
  "2024-01-15T10:30:00Z"). If not provided, defaults to the current date.
</ParamField>

<ParamField body="paymentMethod" type="string" required={false}>
  The method of payment (e.g., "Credit Card", "Debit Card", "Stripe", "Check",
  "Cash").
</ParamField>

<ParamField body="paymentTraceId" type="string" required={false}>
  The transaction ID or payment intent ID from the payment processor (e.g.,
  Stripe payment intent ID like "pi\_1234567890").
</ParamField>

## Example Request

```bash theme={null}
# First, get an access token
TOKEN_RESPONSE=$(curl -X POST https://forecaster.cairhealth.com/api/token \
  -H "Content-Type: application/json" \
  -d '{
    "clientId": "your-client-id",
    "clientSecret": "your-client-secret"
  }')

ACCESS_TOKEN=$(echo $TOKEN_RESPONSE | jq -r '.accessToken')

# Then use the access token to call the webhook
curl -X POST https://forecaster.cairhealth.com/api/webhooks/patient-payment \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "billId": "12345",
    "paymentAmount": 150.75,
    "paymentDate": "2024-01-15",
    "paymentMethod": "Credit Card",
    "paymentTraceId": "pi_1234567890"
  }'
```

## Response

### Success Response (200)

<ResponseField name="success" type="boolean">
  Indicates whether the payment was processed successfully (always `true` for
  200 responses).
</ResponseField>

<ResponseField name="message" type="string">
  A success message describing the result.
</ResponseField>

<ResponseField name="data" type="object">
  Contains the payment processing details: - `claimId`: The UUID of the claim
  that was updated - `claimLifecycleId`: The lifecycle ID of the claim -
  `amountSetOnClaim`: The amount that was set on the claim (may be less than
  paymentAmount if payment exceeds patient responsibility) - `excessAmount`:
  (Optional) Only present if the payment amount exceeds the patient's
  responsibility. This excess amount is automatically created as an unallocated
  patient credit.
</ResponseField>

```json theme={null}
{
  "success": true,
  "message": "Payment processed successfully",
  "data": {
    "claimId": "550e8400-e29b-41d4-a716-446655440000",
    "claimLifecycleId": "lifecycle-12345",
    "amountSetOnClaim": 150.75,
    "excessAmount": 0
  }
}
```

### Error Responses

#### 400 Bad Request

Returned when the request body is invalid or missing required fields.

```json theme={null}
{
  "error": "Invalid request body",
  "details": [
    {
      "path": ["paymentAmount"],
      "message": "paymentAmount must be positive"
    }
  ]
}
```

#### 401 Unauthorized

Returned when authentication fails.

```json theme={null}
{
  "error": "Invalid or expired access token"
}
```

#### 404 Not Found

Returned when the claim cannot be found for the provided `billId`.

```json theme={null}
{
  "error": "Claim not found for billId: 12345"
}
```

#### 500 Internal Server Error

Returned when an unexpected error occurs during payment processing.

```json theme={null}
{
  "error": "Failed to process payment",
  "details": "Error message describing what went wrong"
}
```

## Payment Processing Logic

When a payment is received:

1. **Claim Lookup**: The system searches for a claim matching the provided `billId` using the identifier system `https://fhir.cairhealth.com/fhir/identifier/claim-id`.

2. **Patient Responsibility Calculation**: The system calculates the patient's responsibility from the associated ClaimResponse resource.

3. **Payment Application**:

   * If the payment amount is less than or equal to the patient responsibility, the full payment amount is applied to the claim.
   * If the payment amount exceeds the patient responsibility, only the responsibility amount is applied to the claim, and the excess is automatically created as an unallocated patient credit.

4. **Database Updates**:

   * Updates the `patientPaidAmount` field on all claims with the same `claimLifecycleId`
   * Creates or updates a `PatientPaymentDetails` record with payment information

5. **FHIR Updates**:

   * Creates or updates a `PaymentReconciliation` resource in FHIR
   * Links the payment to the patient via the `patient-payment-issuer` extension

6. **Excess Payment Handling**: If the payment exceeds the patient responsibility, an unallocated `PatientCredit` is automatically created for the excess amount, which can be allocated to other claims later.

## Notes

* The endpoint automatically handles overpayments by creating unallocated patient credits
* All claims with the same `claimLifecycleId` are updated with the payment amount
* The payment date defaults to the current date if not provided
* The endpoint is idempotent - sending the same payment multiple times will update the existing payment record


## OpenAPI

````yaml POST /api/webhooks/patient-payment
openapi: 3.1.0
info:
  title: Cair Health APIs
  description: APIs for the Cair Health platform
  license:
    name: MIT
  version: 1.0.0
servers:
  - url: https://forecaster.cairhealth.com
security:
  - bearerAuth: []
paths:
  /api/webhooks/patient-payment:
    post:
      description: >-
        Webhook endpoint for processing patient payments from external systems
        (e.g., Stripe via Elation). Updates the associated claim with payment
        information and handles overpayments by creating unallocated patient
        credits.
      requestBody:
        description: Patient payment information
        content:
          application/json:
            schema:
              type: object
              properties:
                billId:
                  type: string
                  description: >-
                    Elation bill.id that maps to Claim.identifier with system
                    'https://fhir.cairhealth.com/fhir/identifier/claim-id'
                  minLength: 1
                paymentAmount:
                  type: number
                  description: Payment amount in USD
                  minimum: 0
                  exclusiveMinimum: true
                paymentDate:
                  type: string
                  format: date
                  description: >-
                    ISO 8601 date string (e.g., '2024-01-15'). Defaults to
                    current date if not provided.
                paymentMethod:
                  type: string
                  description: >-
                    Payment method (e.g., 'Credit Card', 'Debit Card', 'Stripe',
                    'Check', 'Cash')
                paymentTraceId:
                  type: string
                  description: >-
                    Stripe payment intent ID or transaction ID (e.g.,
                    'pi_1234567890')
              required:
                - billId
                - paymentAmount
            example:
              billId: '12345'
              paymentAmount: 150.75
              paymentDate: '2024-01-15'
              paymentMethod: Credit Card
              paymentTraceId: pi_1234567890
        required: true
      responses:
        '200':
          description: Payment processed successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    description: Indicates whether the payment was processed successfully
                  message:
                    type: string
                    description: Success message
                  data:
                    type: object
                    properties:
                      claimId:
                        type: string
                        description: UUID of the claim that was updated
                      claimLifecycleId:
                        type: string
                        description: Lifecycle ID of the claim
                      amountSetOnClaim:
                        type: number
                        description: >-
                          Amount that was set on the claim (may be less than
                          paymentAmount if payment exceeds patient
                          responsibility)
                      excessAmount:
                        type: number
                        description: >-
                          Excess amount if payment exceeds patient
                          responsibility (only present if excessAmount > 0)
                    required:
                      - claimId
                      - claimLifecycleId
                      - amountSetOnClaim
                required:
                  - success
                  - message
                  - data
              example:
                success: true
                message: Payment processed successfully
                data:
                  claimId: 550e8400-e29b-41d4-a716-446655440000
                  claimLifecycleId: lifecycle-12345
                  amountSetOnClaim: 150.75
                  excessAmount: 0
        '400':
          description: Invalid request body or missing required fields
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                  details:
                    oneOf:
                      - type: array
                        items:
                          type: object
                      - type: string
              example:
                error: Invalid request body
                details:
                  - path:
                      - paymentAmount
                    message: paymentAmount must be positive
        '401':
          description: Unauthorized - Invalid clientId or clientSecret
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Invalid clientId in Authorization header
        '404':
          description: Claim not found for the provided billId
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: 'Claim not found for billId: 12345'
        '500':
          description: Internal server error during payment processing
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                  details:
                    type: string
              example:
                error: Failed to process payment
                details: Error message describing what went wrong
      security: []
components:
  schemas:
    Error:
      type: object
      properties:
        message:
          type: string
          description: Error message
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT

````