> ## 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 V2

> V2 additive patient payment (or refund with negative amount) by claimLifecycleId. Without claimLifecycleId, patientFhirId creates an unallocated credit. Temporarily disabled (503) while payment/ledger work continues.

## Overview

Additive patient payment API keyed by `claimLifecycleId` (or `patientFhirId` for unallocated credit). Negative `paymentAmount` records a refund (floored at \$0 paid). Overpayments create unallocated patient credits. Self-pay claims also update the patient ledger.

**This endpoint is temporarily disabled and returns 503** while payment/ledger work continues. For live Elation `billId` posts, use [Patient Payment](/api-reference/endpoint/webhooks/patient-payment).

## Use Cases

* **Payment Processing Integration**: Integrate with payment processors to automatically record patient payments
* **EHR Integration**: Connect with EHR systems that know `claimLifecycleId`
* **Partial payments**: Post any positive amount less than remaining PR
* **Refunds**: Post a negative `paymentAmount` with `notes`
* **Unallocated credits**: Omit `claimLifecycleId` and pass `patientFhirId` to create wallet credit

## Authentication

This endpoint requires JWT access token authentication.

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>
```

## Request Body

<ParamField body="claimLifecycleId" type="string" required={false}>
  Cair claim lifecycle id. Required for claim-targeted payments. Omit when
  creating an unallocated credit with `patientFhirId` only.
</ParamField>

<ParamField body="patientFhirId" type="string" required={false}>
  Required when `claimLifecycleId` is not provided. Creates an unallocated
  patient credit (positive `paymentAmount` only).
</ParamField>

<ParamField body="paymentAmount" type="number" required>
  Non-zero amount in USD. Positive = additive payment (partial OK). Negative =
  refund (cannot exceed current paid; `notes` required).
</ParamField>

<ParamField body="paymentDate" type="string" required={false}>
  ISO 8601 date string. Defaults to the current date when omitted.
</ParamField>

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

<ParamField body="paymentTraceId" type="string" required={false}>
  Processor transaction id (e.g., Stripe `pi_*`).
</ParamField>

<ParamField body="notes" type="string" required={false}>
  Required for refunds (`paymentAmount` \< 0). Optional otherwise.
</ParamField>

## Example Request

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

# claimLifecycleId + partial payment
curl -X POST https://forecaster.cairhealth.com/api/webhooks/patient-payment-v2 \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "claimLifecycleId": "lifecycle-12345",
    "paymentAmount": 25.00,
    "paymentMethod": "Credit Card",
    "paymentTraceId": "pi_1234567890"
  }'
```

## Response

### Temporarily Disabled (503)

```json theme={null}
{
  "error": "Patient payment APIs are temporarily disabled",
  "message": "Work in Progress for this API"
}
```

### Success Response (200) — when re-enabled

```json theme={null}
{
  "success": true,
  "message": "Payment processed successfully",
  "data": {
    "claimId": "550e8400-e29b-41d4-a716-446655440000",
    "claimLifecycleId": "lifecycle-12345",
    "amountSetOnClaim": 75.0,
    "previousPaid": 50.0,
    "excessAmount": 10.0,
    "excessCreditId": "credit-uuid",
    "refundAmount": 25.0
  }
}
```

`excessAmount` / `excessCreditId` appear only on overpay. `refundAmount` appears only for refunds.

### Error Responses

* **400** — validation errors, refund exceeds paid, missing notes on refund
* **401** — invalid/missing token
* **404** — claim / organization not found
* **503** — API temporarily disabled (current)

## Payment Processing Logic

1. Resolve claim via `claimLifecycleId`
2. Add `paymentAmount` to current lifecycle paid (or subtract for refunds)
3. Cap positive payments at patient responsibility; excess → unallocated `PatientCredit`
4. Sync `PatientPaymentDetails`, FHIR `PaymentReconciliation`, and (self-pay) ledger
5. Refunds append `PatientRefundLog` and never create negative claim paid

## Related Endpoints

* [Patient Payment (Elation billId)](/api-reference/endpoint/webhooks/patient-payment)
* [Get patient balances](/api-reference/endpoint/patient-payments/balances)
* [Edit claim payment](/api-reference/endpoint/patient-payments/edit-claim-payment)


## OpenAPI

````yaml POST /api/webhooks/patient-payment-v2
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-v2:
    post:
      description: >-
        V2 additive patient payment (or refund with negative amount) by
        claimLifecycleId. Without claimLifecycleId, patientFhirId creates an
        unallocated credit. Temporarily disabled (503) while payment/ledger work
        continues.
      parameters: []
      requestBody:
        description: Patient payment information
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                claimLifecycleId:
                  type: string
                  description: >-
                    Cair claim lifecycle id. Required for claim-targeted
                    payments.
                  minLength: 1
                patientFhirId:
                  type: string
                  description: >-
                    Required when claimLifecycleId is not provided (unallocated
                    credit).
                paymentAmount:
                  type: number
                  description: >-
                    Non-zero USD amount. Positive = additive payment; negative =
                    refund (notes required).
                paymentDate:
                  type: string
                  format: date
                  description: ISO 8601 date string. Defaults to current date if omitted.
                paymentMethod:
                  type: string
                  description: Payment method (e.g., Credit Card, Stripe, Check)
                paymentTraceId:
                  type: string
                  description: Processor transaction id (e.g., Stripe pi_*)
                notes:
                  type: string
                  description: Required for refunds (negative paymentAmount).
              required:
                - paymentAmount
            example:
              claimLifecycleId: lifecycle-12345
              paymentAmount: 50
              paymentMethod: Credit Card
              paymentTraceId: pi_1234567890
      responses:
        '200':
          description: Payment or credit processed successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  message:
                    type: string
                  data:
                    type: object
                    properties:
                      claimId:
                        type: string
                      claimLifecycleId:
                        type: string
                      amountSetOnClaim:
                        type: number
                      previousPaid:
                        type: number
                      excessAmount:
                        type: number
                      excessCreditId:
                        type: string
                      refundAmount:
                        type: number
                      creditId:
                        type: string
                      patientFhirId:
                        type: string
                      paymentAmount:
                        type: number
                required:
                  - success
                  - message
                  - data
        '400':
          description: Invalid request body
        '401':
          description: Unauthorized
        '404':
          description: Claim or organization not found
        '503':
          description: Patient payment APIs are temporarily disabled
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                  message:
                    type: string
              example:
                error: Patient payment APIs are temporarily disabled
                message: Work in Progress for this API
      security: []
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT

````