Kulcare Docs
DeveloperBilling

Patient Invoices API Documentation

This document describes the Patient Invoices API endpoints for the new billing domain. These endpoints handle creating invoices from patient services, downloading PDFs, and sending invoices via email.

Base URL

{base_url}/billing

Authentication

All endpoints require Bearer token authentication:

Authorization: Bearer {access_token}

Endpoints Overview

MethodEndpointDescription
GET/patient_facilities/:patient_facility_id/invoicesList invoices for a patient
POST/patient_facilities/:patient_facility_id/invoicesCreate invoice from services
GET/invoices/:idGet invoice details
POST/invoices/:id/issueIssue a draft invoice
POST/invoices/:id/send_emailSend invoice via email
GET/invoices/:id/pdfDownload invoice as PDF
POST/invoices/:id/cancelCancel an invoice

1. List Patient Invoices

List all invoices for a specific patient facility.

Request

GET /billing/patient_facilities/{patient_facility_id}/invoices

Query Parameters

ParameterTypeRequiredDescription
facility_idUUIDNoFilter by facility ID
encounter_idUUIDNoFilter by encounter ID
statusstringNoFilter by status: draft, issued, paid, partially_paid, overdue, cancelled
start_datedateNoFilter from date (YYYY-MM-DD)
end_datedateNoFilter to date (YYYY-MM-DD)
overduestringNoFilter overdue invoices: true
payment_receivedstringNoFilter by payment status: true, false
pageintegerNoPage number (default: 1)
per_pageintegerNoItems per page (default: 20, max: 100)
sort_directionstringNoSort direction: asc, desc (default: desc)

Example Request

GET /billing/patient_facilities/019c6f7d-2494-736d-b5fc-625687f4120f/invoices?status=issued&start_date=2024-01-01&end_date=2024-12-31

Response

{
  "data": [
    {
      "id": "019bc196-8d50-7338-a891-dc6b3cd73a82",
      "invoice_number": "INV-2024-000001",
      "status": "issued",
      "currency": "INR",
      "patient_id": "019bb764-9839-781a-9383-8ad47af09cc4",
      "facility_id": "019bb761-4a1c-72e9-9a04-75c5bf5f0152",
      "patient_facility_id": "019c6f7d-2494-736d-b5fc-625687f4120f",
      "encounter_id": "019bbb9d-5b88-7ec4-a391-0e52fa5c9807",
      "issue_date": "2024-01-15",
      "due_date": "2024-01-30",
      "subtotal": 1000.0,
      "discount_amount": 100.0,
      "tax_amount": 162.0,
      "total_amount": 1062.0,
      "amount_paid": 500.0,
      "balance_due": 562.0,
      "is_overdue": false,
      "notes": "Invoice for consultation",
      "billing_address": {
        "street": "123 Main Street",
        "city": "Mumbai",
        "state": "Maharashtra",
        "postal_code": "400001",
        "country": "India"
      },
      "metadata": {},
      "item_count": 2,
      "payment_count": 1,
      "payment_received": false,
      "deleted": false,
      "service_names": ["General Consultation", "ECG"],
      "practitioner": {
        "id": "019bb760-1234-7890-abcd-1234567890ab",
        "name": "Dr. John Smith"
      },
      "items": [
        {
          "id": "019bc196-8d8c-7337-99c2-a49d54d0bf7f",
          "invoice_id": "019bc196-8d50-7338-a891-dc6b3cd73a82",
          "line_number": 1,
          "item_type": "consultation",
          "description": "General Consultation",
          "chargeable_type": "Billing::PatientService",
          "chargeable_id": "019bb770-aaaa-bbbb-cccc-ddddeeeeffff",
          "quantity": 1.0,
          "unit_price": 500.0,
          "discount_percent": 10.0,
          "discount_amount": 50.0,
          "tax_percent": 18.0,
          "tax_amount": 81.0,
          "line_total": 531.0,
          "is_credit": false
        }
      ],
      "created_at": "2024-01-15T12:17:07Z",
      "updated_at": "2024-01-15T12:17:08Z"
    }
  ]
}

2. Create Invoice from Services

Create a new invoice from existing patient services.

Request

POST /billing/patient_facilities/{patient_facility_id}/invoices

Request Body

{
  "invoice": {
    "patient_service_ids": [
      "019c74eb-3d85-7f7d-9fe8-b4803f312a32",
      "019c761a-92ba-7b42-842b-94099e9ca655"
    ],
    "encounter_id": "019bbb9d-5b88-7ec4-a391-0e52fa5c9807"
  }
}

Parameters

ParameterTypeRequiredDescription
patient_service_idsarray[UUID]YesIDs of unbilled patient services to include
encounter_idUUIDNoOptional encounter to associate

Response (201 Created)

{
  "data": {
    "id": "019bc196-8d50-7338-a891-dc6b3cd73a82",
    "invoice_number": "INV-2024-000001",
    "status": "draft",
    "currency": "INR",
    "patient_id": "019bb764-9839-781a-9383-8ad47af09cc4",
    "facility_id": "019bb761-4a1c-72e9-9a04-75c5bf5f0152",
    "patient_facility_id": "019c6f7d-2494-736d-b5fc-625687f4120f",
    "encounter_id": "019bbb9d-5b88-7ec4-a391-0e52fa5c9807",
    "issue_date": "2024-01-15",
    "due_date": "2024-02-14",
    "subtotal": 2000.0,
    "discount_amount": 0.0,
    "tax_amount": 0.0,
    "total_amount": 2000.0,
    "amount_paid": 0.0,
    "balance_due": 2000.0,
    "is_overdue": false,
    "notes": null,
    "billing_address": null,
    "metadata": {},
    "item_count": 2,
    "payment_count": 0,
    "items": [
      {
        "id": "019bc196-8d8c-7337-99c2-a49d54d0bf7f",
        "invoice_id": "019bc196-8d50-7338-a891-dc6b3cd73a82",
        "line_number": 1,
        "item_type": "consultation",
        "description": "General Consultation",
        "chargeable_type": "Billing::PatientService",
        "chargeable_id": "019c74eb-3d85-7f7d-9fe8-b4803f312a32",
        "quantity": 1.0,
        "unit_price": 1000.0,
        "discount_percent": 0.0,
        "discount_amount": 0.0,
        "tax_percent": 0.0,
        "tax_amount": 0.0,
        "line_total": 1000.0,
        "is_credit": false
      },
      {
        "id": "019bc196-8dad-76fc-9066-8c20b5fa265a",
        "invoice_id": "019bc196-8d50-7338-a891-dc6b3cd73a82",
        "line_number": 2,
        "item_type": "consultation",
        "description": "General Consultation",
        "chargeable_type": "Billing::PatientService",
        "chargeable_id": "019c761a-92ba-7b42-842b-94099e9ca655",
        "quantity": 1.0,
        "unit_price": 1000.0,
        "discount_percent": 0.0,
        "discount_amount": 0.0,
        "tax_percent": 0.0,
        "tax_amount": 0.0,
        "line_total": 1000.0,
        "is_credit": false
      }
    ],
    "created_at": "2024-01-15T12:17:07Z",
    "updated_at": "2024-01-15T12:17:08Z"
  }
}

Error Response (422 Unprocessable Entity)

{
  "success": false,
  "errors": [
    {
      "detail": "Some services are already billed"
    }
  ]
}

3. Get Invoice Details

Get detailed information about a specific invoice.

Request

GET /billing/invoices/{id}

Query Parameters

ParameterTypeRequiredDescription
viewstringNoResponse view: normal, detailed, with_items (default: detailed)

Response

{
  "data": {
    "id": "019bc196-8d50-7338-a891-dc6b3cd73a82",
    "invoice_number": "INV-2024-000001",
    "status": "draft",
    "currency": "INR",
    "patient_id": "019bb764-9839-781a-9383-8ad47af09cc4",
    "facility_id": "019bb761-4a1c-72e9-9a04-75c5bf5f0152",
    "patient_facility_id": "019c6f7d-2494-736d-b5fc-625687f4120f",
    "encounter_id": "019bbb9d-5b88-7ec4-a391-0e52fa5c9807",
    "issue_date": "2024-01-15",
    "due_date": "2024-02-14",
    "subtotal": 2000.0,
    "discount_amount": 0.0,
    "tax_amount": 0.0,
    "total_amount": 2000.0,
    "amount_paid": 0.0,
    "balance_due": 2000.0,
    "is_overdue": false,
    "notes": null,
    "billing_address": null,
    "metadata": {},
    "item_count": 2,
    "payment_count": 0,
    "items": [...],
    "created_at": "2024-01-15T12:17:07Z",
    "updated_at": "2024-01-15T12:17:08Z"
  }
}

4. Issue Invoice

Transition an invoice from draft to issued status.

Request

POST /billing/invoices/{id}/issue

Response (200 OK)

{
  "data": {
    "id": "019bc196-8d50-7338-a891-dc6b3cd73a82",
    "invoice_number": "INV-2024-000001",
    "status": "issued",
    "currency": "INR",
    "total_amount": 2000.0,
    "amount_paid": 0.0,
    "balance_due": 2000.0,
    "is_overdue": false,
    "issue_date": "2024-01-15",
    "due_date": "2024-02-14",
    "notes": "Updated invoice notes",
    "metadata": {
      "issued_at": "2024-01-16T05:39:08Z",
      "issued_by_id": "69d80db1-8ff9-4c9c-aeb9-5da6b9dc350e",
      "issued_by_name": "System"
    },
    "item_count": 2,
    "payment_count": 0
  }
}

Error Response (422 Unprocessable Entity)

{
  "success": false,
  "errors": [
    {
      "detail": "Invoice cannot be issued in its current state"
    }
  ]
}

5. Send Invoice via Email

Send an invoice to a patient via email.

Request

POST /billing/invoices/{id}/send_email

Request Body

{
  "email": "patient@example.com",
  "format": "inline"
}

Parameters

ParameterTypeRequiredDescription
emailstringYesRecipient email address
formatstringNoEmail format: inline (default) or attachment

Email Formats

FormatDescription
inlineBill details embedded directly in email body
attachmentPDF file attached to email

Response (200 OK)

{
  "success": true,
  "message": "Invoice sent to patient@example.com"
}

Error Response (422 Unprocessable Entity)

{
  "success": false,
  "errors": [
    {
      "detail": "Invalid email address"
    }
  ]
}

6. Download Invoice PDF

Download an invoice as a PDF file.

Request

GET /billing/invoices/{id}/pdf

Response

  • Content-Type: application/pdf
  • Content-Disposition: attachment; filename="invoice_{invoice_number}.pdf"

Example

curl -X GET "https://api.example.com/billing/invoices/019bc196-8d50-7338-a891-dc6b3cd73a82/pdf" \
  -H "Authorization: Bearer {token}" \
  -o invoice.pdf

7. Cancel Invoice

Cancel a draft or payable invoice.

Request

POST /billing/invoices/{id}/cancel

Response (200 OK)

{
  "data": {
    "id": "019bc196-8d50-7338-a891-dc6b3cd73a82",
    "invoice_number": "INV-2024-000001",
    "status": "cancelled",
    "total_amount": 2000.0,
    "amount_paid": 0.0,
    "balance_due": 2000.0
  }
}

Error Response (422 Unprocessable Entity)

{
  "success": false,
  "errors": [
    {
      "detail": "Cannot cancel invoice with existing payments"
    }
  ]
}

Invoice Status Flow

┌─────────┐    issue    ┌─────────┐
│  draft  │ ──────────▶ │  issued │
└─────────┘              └────┬────┘
     │                        │
     │ cancel                 │ partial payment
     │                        ▼
     ▼                  ┌───────────────┐
┌───────────┐           │ partially_paid│
│ cancelled │           └───────┬───────┘
└───────────┘                   │
                                │ full payment
                                ▼
                          ┌─────────┐
                          │  paid   │
                          └─────────┘

Data Types

Invoice Object

FieldTypeDescription
idUUIDUnique identifier
invoice_numberstringHuman-readable invoice number (e.g., INV-2024-000001)
statusstringInvoice status (see status flow)
currencystring3-letter currency code (e.g., INR, USD)
patient_idUUIDPatient ID
facility_idUUIDFacility ID
patient_facility_idUUIDPatient facility junction ID
encounter_idUUIDOptional encounter ID
issue_datedateDate invoice was issued
due_datedatePayment due date
subtotalnumberSubtotal before discounts/taxes
discount_amountnumberTotal discount amount
tax_amountnumberTotal tax amount
total_amountnumberFinal invoice total
amount_paidnumberAmount paid so far
balance_duenumberRemaining balance
is_overduebooleanWhether invoice is past due
notesstringInternal notes
billing_addressobjectBilling address object
itemsarrayArray of invoice items

Invoice Item Object

FieldTypeDescription
idUUIDUnique identifier
invoice_idUUIDParent invoice ID
line_numberintegerLine item number
item_typestringType: consultation, procedure, laboratory, pharmacy, service
descriptionstringItem description
chargeable_typestringPolymorphic type (e.g., Billing::PatientService)
chargeable_idUUIDPolymorphic ID
quantitynumberQuantity
unit_pricenumberPrice per unit
discount_percentnumberDiscount percentage
discount_amountnumberDiscount amount
tax_percentnumberTax percentage
tax_amountnumberTax amount
line_totalnumberTotal for this line
is_creditbooleanWhether this is a credit line

Error Handling

All endpoints return errors in a consistent format:

{
  "success": false,
  "errors": [
    {
      "detail": "Error message here"
    }
  ]
}

Common HTTP Status Codes

CodeDescription
200Success
201Created
401Unauthorized
403Forbidden
404Not Found
422Unprocessable Entity (validation errors)
500Internal Server Error

Notes for Frontend Team

  1. Invoice Creation Flow:

    • First, create patient services via the Patient Services API
    • Then, create an invoice by passing the patient_service_ids
    • The invoice is created in draft status
    • Call the issue endpoint to make it payable
  2. Email Formats:

    • inline: Best for simple bills, displays directly in email
    • attachment: Best for detailed bills, sends as PDF attachment
  3. PDF Download:

    • Returns binary PDF data
    • Use responseType: 'blob' in axios/fetch
    • Content-Disposition header contains the filename
  4. Status Colors (suggested):

    • draft: Gray
    • issued: Blue
    • partially_paid: Yellow/Orange
    • paid: Green
    • overdue: Red
    • cancelled: Gray
  5. Date Formatting:

    • All dates are in ISO 8601 format
    • Display dates in user's locale format

Changelog

Version 1.0.0 (2024-02-20)

  • Initial release
  • Patient invoices CRUD operations
  • PDF generation
  • Email sending (inline and attachment formats)

On this page