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}/billingAuthentication
All endpoints require Bearer token authentication:
Authorization: Bearer {access_token}Endpoints Overview
| Method | Endpoint | Description |
|---|---|---|
| GET | /patient_facilities/:patient_facility_id/invoices | List invoices for a patient |
| POST | /patient_facilities/:patient_facility_id/invoices | Create invoice from services |
| GET | /invoices/:id | Get invoice details |
| POST | /invoices/:id/issue | Issue a draft invoice |
| POST | /invoices/:id/send_email | Send invoice via email |
| GET | /invoices/:id/pdf | Download invoice as PDF |
| POST | /invoices/:id/cancel | Cancel an invoice |
1. List Patient Invoices
List all invoices for a specific patient facility.
Request
GET /billing/patient_facilities/{patient_facility_id}/invoicesQuery Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
facility_id | UUID | No | Filter by facility ID |
encounter_id | UUID | No | Filter by encounter ID |
status | string | No | Filter by status: draft, issued, paid, partially_paid, overdue, cancelled |
start_date | date | No | Filter from date (YYYY-MM-DD) |
end_date | date | No | Filter to date (YYYY-MM-DD) |
overdue | string | No | Filter overdue invoices: true |
payment_received | string | No | Filter by payment status: true, false |
page | integer | No | Page number (default: 1) |
per_page | integer | No | Items per page (default: 20, max: 100) |
sort_direction | string | No | Sort 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-31Response
{
"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}/invoicesRequest Body
{
"invoice": {
"patient_service_ids": [
"019c74eb-3d85-7f7d-9fe8-b4803f312a32",
"019c761a-92ba-7b42-842b-94099e9ca655"
],
"encounter_id": "019bbb9d-5b88-7ec4-a391-0e52fa5c9807"
}
}Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
patient_service_ids | array[UUID] | Yes | IDs of unbilled patient services to include |
encounter_id | UUID | No | Optional 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
| Parameter | Type | Required | Description |
|---|---|---|---|
view | string | No | Response 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}/issueResponse (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_emailRequest Body
{
"email": "patient@example.com",
"format": "inline"
}Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
email | string | Yes | Recipient email address |
format | string | No | Email format: inline (default) or attachment |
Email Formats
| Format | Description |
|---|---|
inline | Bill details embedded directly in email body |
attachment | PDF 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}/pdfResponse
- 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.pdf7. Cancel Invoice
Cancel a draft or payable invoice.
Request
POST /billing/invoices/{id}/cancelResponse (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
| Field | Type | Description |
|---|---|---|
id | UUID | Unique identifier |
invoice_number | string | Human-readable invoice number (e.g., INV-2024-000001) |
status | string | Invoice status (see status flow) |
currency | string | 3-letter currency code (e.g., INR, USD) |
patient_id | UUID | Patient ID |
facility_id | UUID | Facility ID |
patient_facility_id | UUID | Patient facility junction ID |
encounter_id | UUID | Optional encounter ID |
issue_date | date | Date invoice was issued |
due_date | date | Payment due date |
subtotal | number | Subtotal before discounts/taxes |
discount_amount | number | Total discount amount |
tax_amount | number | Total tax amount |
total_amount | number | Final invoice total |
amount_paid | number | Amount paid so far |
balance_due | number | Remaining balance |
is_overdue | boolean | Whether invoice is past due |
notes | string | Internal notes |
billing_address | object | Billing address object |
items | array | Array of invoice items |
Invoice Item Object
| Field | Type | Description |
|---|---|---|
id | UUID | Unique identifier |
invoice_id | UUID | Parent invoice ID |
line_number | integer | Line item number |
item_type | string | Type: consultation, procedure, laboratory, pharmacy, service |
description | string | Item description |
chargeable_type | string | Polymorphic type (e.g., Billing::PatientService) |
chargeable_id | UUID | Polymorphic ID |
quantity | number | Quantity |
unit_price | number | Price per unit |
discount_percent | number | Discount percentage |
discount_amount | number | Discount amount |
tax_percent | number | Tax percentage |
tax_amount | number | Tax amount |
line_total | number | Total for this line |
is_credit | boolean | Whether 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
| Code | Description |
|---|---|
| 200 | Success |
| 201 | Created |
| 401 | Unauthorized |
| 403 | Forbidden |
| 404 | Not Found |
| 422 | Unprocessable Entity (validation errors) |
| 500 | Internal Server Error |
Notes for Frontend Team
-
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
draftstatus - Call the
issueendpoint to make it payable
-
Email Formats:
inline: Best for simple bills, displays directly in emailattachment: Best for detailed bills, sends as PDF attachment
-
PDF Download:
- Returns binary PDF data
- Use
responseType: 'blob'in axios/fetch - Content-Disposition header contains the filename
-
Status Colors (suggested):
draft: Grayissued: Bluepartially_paid: Yellow/Orangepaid: Greenoverdue: Redcancelled: Gray
-
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)