RevKeenDocs

PracticeHub

Sync patients, invoices, packages, and payments with PracticeHub

Connect your PracticeHub practice management system with RevKeen to automatically sync patient, invoice, and package data, then collect payments online and push them back to PracticeHub. The integration is designed for healthcare providers, wellness clinics, and fitness studios.

Add-On App -- PracticeHub integration is available as a premium add-on to your RevKeen subscription. Contact sales@revkeen.com for pricing.

Overview

The PracticeHub integration creates a bi-directional sync between your practice management system and RevKeen's payment platform:

  • Inbound (PracticeHub → RevKeen): Patients, services & products, packages, and unpaid invoices
  • Outbound (RevKeen → PracticeHub): Successful payments, plus a financial entry on the patient timeline

This allows your patients to pay invoices online while keeping your PracticeHub records automatically updated.

Features

  • Patient Sync -- Import patients as RevKeen customers (only billing-safe fields; no PHI)
  • Invoice Sync -- Sync unpaid invoices for online payment collection
  • Package & Service Sync -- Sync PracticeHub services, products, and prepaid packages into RevKeen products
  • Automatic Payment Push -- Push successful payments back to PracticeHub and auto-allocate them to the originating invoice
  • Patient Timeline Entry -- Each pushed payment also creates a financial log entry on the patient's PracticeHub timeline

Prerequisites

Before connecting PracticeHub, you will need:

  • A PracticeHub account with API access enabled
  • Your PracticeHub API Key (from Settings → Developers in PracticeHub)
  • Your PracticeHub Base URL (e.g., https://yourclinic.practicehub.io)
  • A contact email for the PracticeHub x-app-details header
  • At least one configured payment processor in RevKeen (the activation wizard reads your supported currencies from your gateway processors)

Contact PracticeHub support to enable API access for your account if you don't see the Developers section under Settings.

Setup Instructions

The activation wizard has three steps: API Credentials, Sync Options, and Field & Payment Mappings.

Step 1: API Credentials

  1. Log in to your PracticeHub admin panel
  2. Navigate to Settings → Developers
  3. Generate or copy your API Key
  4. Note your Base URL (the URL you use to access PracticeHub, e.g. https://yourclinic.practicehub.io)

Then in RevKeen:

  1. Open the RevKeen Dashboard
  2. Go to Apps → Marketplace → PracticeHub and click Connect
  3. Enter your credentials:
FieldRequiredDescriptionExample
Base URLYesYour PracticeHub instance URL (no trailing slash; /api suffix is stripped automatically)https://yourclinic.practicehub.io
API KeyYesYour PracticeHub API key. Sent as the x-practicehub-key header.(generated in PracticeHub)
Contact EmailYesEmail PracticeHub support can use to reach your team. Sent as part of the x-app-details header.ops@yourclinic.com
App NameNoIdentifier sent in the x-app-details header. Defaults to RevKeen.RevKeen
  1. Click Validate Connection

RevKeen calls GET /api/payment_methods against your PracticeHub instance to validate the credentials and to load the list of payment methods used in Step 3. If validation fails, double-check the API key, Base URL, and contact email.

Step 2: Sync Options

After validation you choose what data to sync. Each toggle is independent — you can disable any of them later.

OptionDefaultWhat it does
Sync Patients → RevKeen CustomersOnImports patient records as RevKeen customers (billing-safe fields only)
Sync Services & Products → RevKeen ProductsOnImports services and one-off products from /api/packages
Sync Packages (Prepaid) → RevKeen SubscriptionsOnImports prepaid packages (e.g. 10 visits) as products with credit metadata
Sync Unpaid Invoices → RevKeen InvoicesOnImports unpaid invoices for online payment collection
Push Payments Back to PracticeHubOnPushes completed RevKeen payments to PracticeHub and auto-allocates them to the originating invoice
Auto-send invoice emailsOffWhen on, RevKeen emails a payment link to the customer as soon as the invoice arrives from PracticeHub. When off (the default), invoices land in the new imported status — dormant until you explicitly Send or Mark as delivered. See Invoice Lifecycle.
Invoice Lookback Period3 monthsHow far back to fetch unpaid invoices on the initial sync. Choices: 1 week, 1 month, 3 months, 6 months, 1 year

Step 3: Field & Payment Mappings

The final step controls how PracticeHub data is interpreted by RevKeen and how payments are reported back. Sensible defaults are pre-selected, so most clinics can accept the defaults and move on.

Default Payment Collection Method

OptionWhen to use
Generate Checkout Link (default)Best for instant collection — patients click a hosted checkout link
Send InvoiceEmail an invoice that can be paid later (and supports partial payments)
Auto-detect by amountUse a checkout link below the threshold and an invoice above it. Configure the threshold in the same step (default 500)

Customer Field Mappings

MappingDefaultOptions
Email Fieldemail (Primary)email, work_email, other_email
Phone Fieldmobilephone, mobile, work_phone, home_phone
Name FormatFirst Lastfirst_last, last_first, full_name

Product Sync Mode

ModeBehavior
Auto-create RevKeen products (default)Each PracticeHub package becomes a RevKeen product automatically
Manual mapping onlyYou map PracticeHub packages to existing RevKeen products yourself
Don't sync productsSkip product sync entirely

Charge Type Handling

How different PracticeHub charge types are billed in RevKeen:

PracticeHub Charge TypeDefault RevKeen Action
One-off charges (services)Send checkout link
Package purchases (prepaid)Send checkout link
Recurring / membership feesCreate a RevKeen subscription

Payment Method Mappings

Map a RevKeen collection method (Checkout Link, Invoice, or RevKeen Terminal) to a PracticeHub payment_type_id so pushed payments show up under the right payment method in PracticeHub. The dropdown is populated from your PracticeHub GET /api/payment_methods response, filtered to active methods and sorted by sort_order. You can add as many rows as you need, but at least one mapping with a real PracticeHub payment type must be configured before activation completes.

Data Sync Details

What Syncs

PracticeHubRevKeenDirectionSync Trigger
Patients (/api/patients)CustomersPracticeHub → RevKeenupdated cursor
Unpaid Invoices (/api/invoices)InvoicesPracticeHub → RevKeenupdated cursor
Invoice Line Items (/api/line_items)Invoice line itemsPracticeHub → RevKeenPer-invoice fetch
Packages, Services & Products (/api/packages)ProductsPracticeHub → RevKeenFull refetch each cycle (the updated filter is not supported on this endpoint)
Payment Methods (/api/payment_methods)Payment method mappingsPracticeHub → RevKeenRefreshed at activation and during reverse-sync
Locations (/api/locations)Stored on the integration recordPracticeHub → RevKeenActivation / reconciliation
Successful Payments (/api/payments)RevKeen → PracticeHubRevKeen invoice.paid event
Patient timeline log (/api/patient_logs)RevKeen → PracticeHubAfter each successful payment push

Patient to Customer Mapping

When a patient syncs from PracticeHub, only billing-safe fields are imported:

PracticeHub FieldRevKeen FieldNotes
idexternal_idUsed for matching
email (or your configured email field)emailRequired — patients without an email are skipped
first_namefirst_nameDirect mapping
last_namelast_nameDirect mapping
mobile (or your configured phone field)phoneConfigurable in Step 3
patient_numberStored in customer metadataUsed for display

What Does NOT Sync (PHI Compliance)

RevKeen never imports Protected Health Information (PHI). Imports are scanned for PHI before mapping; any record with PHI in a blocked field is rejected and logged.

The following PracticeHub fields are explicitly blocked by the import mappers:

notes, description, descriptions, clinical_details, clinical_notes, staff_notes, treatment_plan, treatment_plans, medical_history, diagnosis, diagnoses, symptoms, soap_notes, progress_notes, internal_notes.

Patient fields that are present in the PracticeHub API but never imported into RevKeen include:

  • Date of birth (dob)
  • Sex
  • Patient balance (private balance, third-party balance)
  • Default location
  • Any free-text clinical or staff notes

Only billing-safe fields are synced:

  • Email address
  • First name, Last name
  • Patient number (stored as customer metadata)
  • Phone (configurable field)
  • Invoice amounts, dates, line items, and statuses
  • Product / package / service names and prices

Invoice Lifecycle (from PracticeHub to Paid)

The biggest thing to understand about this integration is what happens to a PracticeHub invoice once it lands in RevKeen — specifically, that it is not automatically sent to the customer unless you opt in. The flow is designed so the merchant always controls the moment the customer is asked to pay.

PracticeHub                RevKeen
unpaid invoice ──sync──▶  imported ──┬──▶ approved / sent ──▶ partially_paid ──▶ paid ──reverse-sync──▶ /api/payments
                                     │                                                                  /api/patient_logs
                                     └──▶ (skipped if "Mark as delivered")

Step 1: Imported (default landing state)

When the sync fetches an unpaid PracticeHub invoice, it normalizes the status to RevKeen's sent and then — if Auto-send invoice emails is off (the default) — overrides the status to imported:

  • imported is a dedicated dormant status for externally-sourced invoices.
  • It is the "not yet actioned by merchant" tray on the dashboard.
  • Reminder and dunning crons skip these invoices because their delivered_to_customer_at is NULL.
  • The customer is not emailed and no payment link is generated yet.

This default exists so that historical PracticeHub invoices imported during the lookback window (up to 1 year) are never accidentally re-emailed to customers who already paid by some other channel.

Step 2: Merchant action — Send or Mark as delivered

From the invoices list in the RevKeen dashboard, the merchant has two choices for each imported invoice:

ActionResultUse when
Send via RevKeenGenerates a payment link and emails the customer. Invoice transitions imported → sent.You want RevKeen to actually collect the payment.
Mark as delivered (bulk action POST /v2/invoices/mark-delivered)Sets delivered_to_customer_at and transitions the invoice toward approved/sent without re-emailing.The invoice was already sent from PracticeHub and you just want RevKeen to track it (so reminders and the eventual payment push work).

If you turn Auto-send invoice emails on in Step 2 of the wizard, the sync will skip the imported step entirely — every newly created invoice goes straight to sent and the customer immediately receives a payment link. This is appropriate for clinics that want PracticeHub to be the single source of truth and RevKeen to do the collection automatically.

Step 3: Sent → Paid

Once the invoice is sent:

  • The customer pays via the hosted RevKeen checkout (or the invoice is settled on a RevKeen Terminal or marked paid manually).
  • A partial payment moves the invoice to partially_paid; full settlement moves it to paid.
  • The standard reminder ladder applies — see the Invoices and Reminders docs.
  • All other RevKeen invoice events (invoice.created, invoice.sent, invoice.paid, etc.) fire normally and are visible to any merchant-side webhook subscriptions.

Step 4: Paid → reverse-sync to PracticeHub

When an invoice that originated from PracticeHub becomes paid, RevKeen's reverse-sync queue picks it up and pushes the payment back. This is the only step where data flows from RevKeen to PracticeHub. The full mechanics are documented in How Payment Push Works below — in short, it's a POST /api/payments (with service: "Invoice" + service_id so PracticeHub auto-allocates) and a POST /api/patient_logs for the patient timeline entry.

If the push fails (PracticeHub down, network blip, mapping missing), the job is retried with exponential backoff. Before each retry, RevKeen looks up existing PracticeHub payments by service_id to make sure a partial recovery never produces a duplicate.

Status mapping summary

StageRevKeen statusWhat it means
Just synced from PracticeHub (auto-send off)importedDormant, not visible to the customer
Merchant clicked SendsentCustomer has been emailed a payment link
Merchant clicked Mark as deliveredapproved / sent (with delivered_to_customer_at set)RevKeen tracks payment but did not email
Auto-send was on at sync timesentCustomer was emailed automatically
Customer paid part of the invoicepartially_paidAwaiting remainder
Customer paid the full amountpaidTriggers reverse-sync push to PracticeHub
Voided in PracticeHubvoidedMapped from void / cancelled / written_off
Credit-noted in PracticeHubrefundedMapped from credit / credited / credit_note

How Payment Push Works

When a customer pays a PracticeHub-originated invoice through RevKeen, the payment is automatically recorded in PracticeHub and allocated to the matching invoice.

Payment flow:

  1. The patient pays a RevKeen-issued invoice (originally synced from PracticeHub)
  2. RevKeen processes the payment via your payment gateway
  3. The gateway confirms the payment and the RevKeen invoice.paid event fires
  4. The reverse-sync queue resolves the PracticeHub payment_type_id for the collection method that was actually used (checkout link, invoice, or terminal), falling back to your default mapping
  5. RevKeen calls POST /api/payments on PracticeHub
  6. RevKeen calls POST /api/patient_logs to add a "Payment received via RevKeen" entry on the patient's timeline
  7. PracticeHub auto-allocates the payment to the originating invoice using the service / service_id fields

PracticeHub does not support POST /api/payment_allocations (the endpoint returns 501 Not Implemented). RevKeen instead sets service: "Invoice" and service_id: <PracticeHub invoice id> on the payment, which causes PracticeHub to auto-allocate the payment to the invoice on the server side.

What Gets Pushed

When a payment is completed, RevKeen sends the following to PracticeHub POST /api/payments:

FieldDescriptionExample
amountPayment amount in major units (decimal pounds / dollars), per the PracticeHub PaymentCreate schema50.00
patient_idPracticeHub patient ID12345
payment_type_idThe payment_type_id resolved from your payment method mapping7
location_idOptional PracticeHub location ID1
serviceAlways "Invoice" — tells PracticeHub which entity to allocate against"Invoice"
service_idThe PracticeHub invoice ID being settled"98765"
noteHuman-readable summary of the paymentJohn Smith (john@example.com) | Txn: nmi_txn_abc123 | Ref: ...

After the payment is created, RevKeen also posts to /api/patient_logs so staff can see the payment on the patient timeline:

FieldValue
patient_idPracticeHub patient ID
typefinancial
sub_typesuccess
source_entityRevKeen
dataHTML-formatted summary including PracticeHub invoice / payment IDs, RevKeen invoice / payment IDs, amount, card brand & last 4, gateway transaction ID, and paid-at timestamp

Sync Architecture

Authentication Headers

Every request to PracticeHub includes:

HeaderValueSource
x-practicehub-keyYour API keyStep 1 of the activation wizard
x-app-details<App Name>=<Contact Email> (e.g. RevKeen=ops@yourclinic.com)Step 1 of the activation wizard

The x-app-details header is required by the PracticeHub API. If the contact email is missing or malformed, PracticeHub will reject the request.

Incremental Sync Strategy

RevKeen tracks the last sync timestamp per resource and only fetches records updated since then. PracticeHub uses an operator:value filter syntax:

GET /api/patients?updated=gte:2026-01-30T10:00:00Z&page=1&page_size=200
GET /api/invoices?updated=gte:2026-01-30T10:00:00Z&page=1&page_size=200
GET /api/line_items?invoice_id=eq:98765&page=1&page_size=200
GET /api/packages?page=1&page_size=200

Notes:

  • Pagination uses page + page_size=200 and follows the links.next URL returned by PracticeHub.
  • The /api/packages endpoint does not support the updated filter (PracticeHub returns 400), so RevKeen refetches all packages each cycle and filters active ones client-side.
  • Invoice line items live at a separate endpoint (/api/line_items), not nested inside the invoice payload.
  • Invoice status filtering (only unpaid statuses are imported for collection) is performed client-side after the fetch.

Polling Schedule

A scheduler tick runs every 60 seconds and decides per-merchant whether to enqueue a sync, based on the merchant's polling profile. The default profile is:

WindowEffective interval
Active hours (Mon–Fri 07:00–19:00 by default)10 minutes baseline
Burst window (after a change is detected)60 seconds for up to 10 minutes
Off-hours (overnight / weekends)30 minutes

Polling profiles and active windows can be customized per merchant if your clinic operates outside the default business hours.

Invoice Status Mapping

PracticeHub invoice statuses are normalized to RevKeen's invoice_status enum:

PracticeHub statusesRevKeen status
sent, unpaid, outstanding, open, issued, pending, awaiting_paymentsent (then overridden to imported if auto-send is off — see Invoice Lifecycle)
partial, part_paidpartially_paid
past_due, pastdue, late, overdueoverdue
paid, complete, settled, closedpaid
void, cancelled, canceled, written_offvoided
credit, credited, credit_noterefunded

Invoices arriving from PracticeHub default to sent (not draft), since they have already been issued in the source system. With Auto-send invoice emails off (the default), sent is then rewritten to imported so the merchant has explicit control over when the customer is contacted.

Payment Method Mapping

The PracticeHub payment_type_id used when pushing a payment is resolved in this order:

  1. Per-method mapping you configured in Step 3 (matched on the RevKeen collection method: checkout link, invoice, or terminal)
  2. Default payment_type_id stored on the integration's configuration
  3. Name match fallback against the live /api/payment_methods list (e.g. RevKeen card payments fall back to a PracticeHub method whose name contains "card")

If none of these resolve, the payment push is failed and retried. You can review and edit your mappings at any time under Apps → Marketplace → PracticeHub → Settings.

Sync Activity & Logs

There is no merchant-facing webhook stream specifically for PracticeHub events. Sync activity is observed through:

  • The Sync History section on the PracticeHub app page in the dashboard
  • Standard RevKeen events such as invoice.paid, which is what triggers the reverse-sync push to PracticeHub

If you have a webhook endpoint subscribed to RevKeen invoice and payment events, you'll see those events fire normally — the PracticeHub integration is upstream/downstream of them, not a separate event channel.

Error Handling and Retries

RevKeen wraps every PracticeHub call with the shared external-API client, which handles retries with backoff:

Error TypeAction
Rate limit (429)Exponential backoff and retry (up to 3 attempts per request)
Server error (5xx)Retry with delay (up to 3 attempts)
Network timeout (30s)Retry (up to 3 attempts)
Authentication error (401 / 403)Surface a credential error; sync stops until credentials are fixed
Not found (404) on a single recordSkip that record, continue the sync
service: "Invoice" allocation failureThe reverse-sync job is failed and retried; idempotency check on the next run skips records that already exist in PracticeHub by service_id

Per-request timeouts are 30 seconds. If sync errors persist, check the Sync History section on the PracticeHub app page in the dashboard for detailed error messages.

Troubleshooting

Connection Failed

Invalid API Key

  • Verify your API key is correct (no extra spaces)
  • Check if the API key has expired
  • Ensure API access is enabled in PracticeHub

Invalid Base URL

  • Use the full URL including https://
  • Don't include trailing slashes
  • Example: https://yourclinic.practicehub.io

Network Timeout

  • Check if PracticeHub is accessible
  • Verify your firewall allows outbound connections
  • Try again in a few minutes

Connection Failed: Bad x-app-details

  • The contact email you entered must be a valid email address — PracticeHub rejects malformed x-app-details headers
  • The format sent to PracticeHub is <App Name>=<Contact Email> (e.g. RevKeen=ops@yourclinic.com)

Sync Issues

Patients Not Syncing

  • Check that patients have a value in the configured email field (Step 3 — defaults to the primary email field)
  • Verify the Sync Patients toggle is on in Apps → Marketplace → PracticeHub → Settings
  • Check the Sync History section on the PracticeHub app page

Payments Not Pushing

  • Verify the RevKeen customer is linked to a PracticeHub patient (the customer was originally synced from PracticeHub)
  • Verify the RevKeen invoice was originally synced from PracticeHub (the integration only pushes payments for invoices it created)
  • Confirm at least one payment method mapping is configured in Step 3 of the activation wizard, or under Apps → Marketplace → PracticeHub → Settings → Payment Methods
  • Check the Sync History section on the PracticeHub app page for reverse-sync errors

Missing Invoices

  • Only unpaid invoices sync to RevKeen — paid invoices are skipped because they're already settled
  • Initial sync only fetches invoices within the Invoice Lookback Period you selected; older unpaid invoices won't appear unless you increase the lookback
  • Check the invoice status in PracticeHub — only sent, unpaid, outstanding, partial, and overdue statuses are imported

Frequently Asked Questions

How quickly do payments appear in PracticeHub?

Payment push is triggered as soon as the RevKeen invoice.paid event fires, and typically appears in PracticeHub within a few seconds. The patient balance updates as soon as PracticeHub confirms receipt and auto-allocates the payment to the originating invoice.

What happens if PracticeHub is down when a payment is made?

The reverse-sync job is retried with exponential backoff. Before each retry, RevKeen checks whether a payment with the same service_id already exists in PracticeHub, so a recovered run will not double-record. Once PracticeHub is reachable, queued pushes are delivered automatically.

Can I sync specific patients only?

Currently, RevKeen syncs every patient that has a value in the configured email field. There is no per-group or per-location filter today — contact support if you need that.

Do partial payments sync correctly?

Yes. RevKeen pushes the exact amount paid (in major units) to PracticeHub. PracticeHub auto-allocates the payment against the invoice via the service / service_id fields, and the invoice status updates accordingly.

What about refunds?

Refunds processed in RevKeen are recorded in RevKeen but are not automatically pushed to PracticeHub. You will need to manually adjust the patient balance in PracticeHub for refunds.

What about appointments?

The integration intentionally avoids syncing appointment details — appointment data tends to contain PHI and is out of scope for billing. Patients, packages, and invoices are sufficient to drive payment collection.

Is my data secure?

Yes. All API communication uses HTTPS/TLS encryption. API keys are stored encrypted at rest using KMS envelope encryption (per-row data encryption keys, AES-256-GCM), and decrypted only inside the engine-API and reverse-sync worker when a request needs to call PracticeHub. PHI fields from PracticeHub are scanned and rejected at import time.

Support

Need help with your PracticeHub integration?