Service Request Data Flows
This page explains how service requests, payments, and appointments are connected — and what happens automatically at each stage of the lifecycle.
How It All Ties Together
A service request can optionally require scheduling, payment, or both. These requirements are set via the workflow configuration and stored as metadata on the service request. The system coordinates status updates across all three resources (ServiceRequest, Appointment, Invoice/Payment) to keep them in sync.
Service Request (Draft)
├── Requires Scheduling?
│ └── Appointment created, linked via basedOn reference
├── Requires Payment?
│ └── Invoice + Stripe checkout session, linked via extension
│
├── All requirements met → Status changes to Active
└── Expired or dismissed → Status changes to Revoked
Service Request Status Lifecycle
┌─────────┐
│ Draft │ ← Created during registration or portal workflow
└────┬─────┘
│
┌────────┼──────────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌──────┐ ┌─────────┐
│ Active │ │Revoked│ │On Hold │
└───┬────┘ └──────┘ └────┬────┘
│ │
▼ │
┌───────────┐ │
│ Completed │◄─────────────┘
└───────────┘
| Transition | Trigger |
|---|---|
| Draft → Active | Payment completed (automatic), or staff manually activates |
| Draft → Revoked | Workflow expired, patient dismissed, or staff cancelled |
| Active → Completed | Service fulfilled by care team |
| Active → On Hold | Staff pauses the request |
| On Hold → Active | Staff resumes the request |
| On Hold → Completed | Service fulfilled after hold |
| Any → Entered in Error | Staff marks as recorded by mistake |
Payment Flow
Payment is processed through Stripe and tracked via an Invoice resource linked to the service request.
Happy Path
Patient initiates payment
│
▼
┌──────────┐ Stripe checkout ┌─────────┐ Webhook: ┌────────┐
│ Unpaid │ ───────────────────────► │ Pending │ ─────────────────────► │ Paid │
└──────────┘ session created └─────────┘ session.completed └────────┘
│
▼
Service Request: Draft → Active
Invoice: Issued → Balanced
Appointment status updated
(if configured)
- The service request starts with payment status Unpaid.
- The patient (or staff) clicks Add Payment, which creates a Stripe checkout session and an Invoice.
- Payment status transitions to Pending while the patient completes checkout.
- On success, Stripe sends a
checkout.session.completedwebhook that:- Updates the payment status to Paid
- Transitions the service request from Draft to Active
- Marks the Invoice as Balanced
- Updates the linked appointment status (if an
appointmentStatusAfterPaymentis configured) - Records Stripe references (Payment Intent ID, Charge ID, Session ID) on the PaymentReconciliation resource
- Triggers post-payment appointment notifications (confirmations, reminders)
Checkout Session Expiration
If the patient does not complete the Stripe checkout in time, the session expires:
┌─────────┐ Session timeout ┌──────────┐
│ Pending │ ────────────────────────► │ Expired │
└─────────┘ (Stripe webhook) └──────────┘
│
▼
Invoice: Unchanged (stays payable)
Appointment: Unchanged
- The payment status changes to Expired.
- The linked Invoice is left as it was (still payable) so the patient can pay again. Starting that retry expires the old checkout session, so only one session is ever live per Invoice.
- The linked appointment is not cancelled by the expired session. It stays on the schedule so the patient can pay again from the portal, or staff can add a payment. Unpaid appointments are only cancelled automatically by the Cancel appointments after payment timeout setting, which runs on its own schedule.
- The system includes race-condition protection — if a payment was completed just before the expiration event, the Invoice and payment status are left as paid.
Payment Failure
If the payment is declined or encounters an error:
- The payment status changes to Failed.
- The decline code and error message are recorded on the PaymentReconciliation resource.
- If the related Invoice can be resolved from the PaymentReconciliation request references, the Invoice is cancelled.
- The service request payment status is updated to failed (unless it has already been marked as paid or refunded).
Refunds
When a charge is refunded through Stripe:
- The payment status changes to Refunded.
- The refund amount, date, and currency are recorded on the PaymentReconciliation resource.
- The linked Invoice is cancelled.
- The service request payment status is updated to refunded.
Disputes
When a charge is disputed (chargeback) through Stripe:
- The dispute status, reason, and ID are recorded on the PaymentReconciliation resource.
- The original payment record is preserved for audit purposes.
Appointment Flow
Appointments can be linked to service requests through the FHIR basedOn reference. This link enables the system to coordinate lifecycle events between the two resources.
How Appointments Are Linked
- When a patient books an appointment during a service request workflow, the appointment's
basedOnfield references the service request (e.g.,ServiceRequest/abc123). - If the workflow also requires payment, an Invoice is created with extensions linking it to both the service request and the appointment.
What Happens After Payment
When payment completes for a service request that has a linked appointment:
- The system finds the appointment via the
basedOnreference on the service request. - If an
appointmentStatusAfterPaymentvalue is configured (e.g., "booked"), the appointment status is updated accordingly. - Post-payment appointment notifications are triggered (confirmation emails, reminders, etc.).
- Any payment timeout checks that were scheduled for the appointment are cancelled since payment succeeded.
Payment Timeout
If the workflow is configured with a paymentTimeoutMinutes value, the system schedules a background check after the appointment is booked:
- After the timeout period, the system checks whether payment has been received.
- If no payment is found, the appointment is automatically cancelled.
- If payment was completed (race condition protection), the appointment is left unchanged.
Appointment Cancellation on Dismissal
When a patient dismisses an incomplete workflow from the portal:
- The service request is revoked.
- All non-terminal appointments linked via
basedOnare cancelled. - Any scheduled reminders and late/no-show checks for those appointments are also cancelled.
Appointments already in a terminal state (Cancelled, Fulfilled, No-show, Entered in Error) are skipped during this process.
Workflow Expiration
Service requests created through registration or portal workflows have an expiration date. This prevents incomplete workflows from lingering indefinitely.
How Expiration Works
- When a service request is created as part of a workflow, an expiration date is set based on the organization's configuration.
- If the service request remains in Draft status past its expiration date, it is automatically revoked.
- Patients see an expiration warning in the portal when a workflow is within 7 days of expiring.
What Gets Affected
When a service request expires:
| Resource | Action |
|---|---|
| Service Request | Status changed to Revoked |
| Linked Appointments | Cancelled (if not already in a terminal state) |
| Scheduled Reminders | Cancelled for any linked appointments |
| Payment | Not processed — any pending checkout sessions will also expire naturally on the Stripe side |
Workflow Recovery
Patients who leave a workflow incomplete can return and resume it:
- The portal detects incomplete service requests in Draft status and surfaces them as recovery cards.
- Each card shows which steps are complete (e.g., "Scheduled") and which remain (e.g., "Payment").
- Patients can Continue to resume from where they left off, or Dismiss to cancel.
- If the patient was redirected to Stripe for payment, the workflow state is preserved so they can resume seamlessly after returning.
Summary: What Triggers What
| Event | Service Request | Appointment | Payment Status | Invoice |
|---|---|---|---|---|
| Patient creates request | → Draft | — | Unpaid (if required) | — |
| Patient books appointment | Draft (unchanged) | → Booked/Pending | — | — |
| Stripe checkout initiated | Draft (unchanged) | Unchanged | → Pending | → Issued |
| Payment succeeds | → Active | Status updated (if configured) | → Paid | → Balanced |
| Checkout session expires | Draft (unchanged) | Unchanged | → Expired | Unchanged (stays payable) |
| Payment fails | Draft (unchanged) | Unchanged | → Failed | → Cancelled (if linked/resolved) |
| Refund processed | Unchanged | Unchanged | → Refunded | → Cancelled |
| Patient dismisses workflow | → Revoked | → Cancelled | Not processed | — |
| Workflow expires | → Revoked | → Cancelled | Not processed | — |
| Payment timeout reached | Unchanged | → Cancelled | Unchanged | Unchanged |