Payments and billing schema

Hi all,

I’m wondering if there’s any good reference material on the database schema around billing and payments, or if someone with experience in this area might be able to provide some info.

For context, I’m looking into adding another payment provider and integrating it into the portals. I’ve managed to get most of the UI pieces working (up through capturing the payment on the gateway’s end - money can move) but none of that ends up getting reflected in the OpenEMR UIs. I’ve found a few tables in the database that look relevant, and can probably reverse-engineer it given enough time, but when it comes to payments, I don’t want to guess. I also did a before-and-after diff of the database contents when using a stripe test key for reference when using the patient portal and that didn’t look quite right, but it seemed to put the payment in some sort of “pending admin approval” state.

For now, I’m trying to concretely know where payments that occurred get recorded in the db, and how that should make it back into the UIs. In particular, the “patient paid” column and the “locked payment pending” that can show up in the patient portal (how do I get past that? when I tried to accept it in the admin side, I’d run into blank screens or permissions errors)

If anyone can point me in a useful direction here, I’d super appreciate it! Thank you and happy holidays!

hi @Firehed, not sure if you have seen the ehi export docs, a good place to start for sure. There’s also the ar_session table and payments table.

Hi @stephenwaite - thanks for that! I did come across those, and also saw data being written into onsite_portal_activity that seems to exist for some sort of pending payment state (this was the only non-log table that saw writes when I made a test payment through the patient portal). I see after the payment form, data is posted to portal/lib/paylib.php(or the fairly-similar interface/patient_file/front_payment_cc.php) but I was having trouble following where it would actually write that a payment happened. The ar_activity table looks like the “more” canonical record of payments happening as far as the UI data is concerned, but I also see it loading data from payments… so I wasn’t really sure what data needs to end up where by the end of processing.

Okay great. Yes, sounds like there should be something in the portal audit process that moves the payments through to be stored in the tables referenced.

I developed stripe several years ago so I don’t recall the nitty gritty.

I can say the In House is the only method that will put payment in

for audit. In audit user verifies credit card, payment and then post the payment. At that point, patient is notified in portal ledger.

Here’s audit

I forget what an electronic payment looks like in audit and if you can post from there, I believe so.

It’d make sense I’d also make available for posting in Post Payments.

Also note, Front Payment also takes credit payments and again i’m unsure but believe if integrated in portal the payment type will appear here as well.

My last integration was for a stripe terminal and Brady did Sphere(better terminal).

1 Like

Thanks for the background! When I tried to open that portal payments page from your screenshot I immediately got bounced out with an auth error (using a clean install with the default admin account). When I commented out a bunch of checks to bypass that for testing purposes, I still wasn’t able to get to a page that would allow me to accept the payment.

Here’s what I got on the patient side when making a payment via stripe (in test mode, which I’d assume shouldn’t matter):

And on the admin side (again, new install using the default admin account) when clicking the portal payments button circled above:

Oh Snap!

Unauthorized

You may want to try returning to the the previous page and verifying that all fields have been filled out correctly.

If you continue to experience this error please contact support.

Stack Trace:

#0 /var/www/localhost/htdocs/openemr/portal/patient/fwk/libs/verysimple/Phreeze/Dispatcher.php(91): GenericRouter->GetRoute()
#1 /var/www/localhost/htdocs/openemr/portal/patient/index.php(54): Dispatcher::Dispatch()
#2 {main}

I’ll try again shortly with “in house” to see if I get a different result, but I’m assuming this isn’t the expected behavior. Could it be related to needing a webhook to process? I didn’t see anything that referenced that, but it sort of matches what I’d expect in terms of behavior.

Try from main audit page to see if payment is there for audit. Miscellaneous → Portal Dashboard

When navigating directly there per your screenshot, I just get an empty page. The home button takes me back to the previous page. Nothing actionable that I can find, despite that top-right menu having the (2) indicator on it.

Are the payments in the onsite_activity_table?

re turn on debug in Config

Yes, I have a single record that appeared in there after making the payment on the stripe gateway through the patient portal.

Does audit work for a document Clinical Documents card i.e. do a Privacy doc and submit.

yep There’s a bug. I’ll look into prob a simple fix

[22-Dec-2025 16:58:29 America/New_York] PHP Fatal error:  Uncaught TypeError: property_exists(): Argument #1 ($object_or_class) must be of type object|string, array given in C:\xampp\htdocs\openemr\portal\patient\fwk\libs\verysimple\Phreeze\Reporter.php:179
Stack trace:
#0 C:\xampp\htdocs\openemr\portal\patient\fwk\libs\verysimple\Phreeze\Reporter.php(179): property_exists(Array, 'OnsiteActivityV...')
#1 C:\xampp\htdocs\openemr\portal\patient\fwk\libs\verysimple\Phreeze\Reporter.php(219): Reporter->GetPublicProperties()
#2 C:\xampp\htdocs\openemr\portal\patient\fwk\libs\verysimple\Phreeze\DataPage.php(101): Reporter->ToObject(Array)
#3 C:\xampp\htdocs\openemr\portal\patient\libs\Controller\OnsiteActivityViewController.php(106): DataPage->ToObjectArray(true, Array)
#4 C:\xampp\htdocs\openemr\portal\patient\fwk\libs\verysimple\Phreeze\Dispatcher.php(172): OnsiteActivityViewController->Query()
#5 C:\xampp\htdocs\openemr\portal\patient\index.php(54): Dispatcher::Dispatch(Object(Phreezer), Object(SavantRenderEngine), '', NULL, Object(GenericRouter))
#6 {main}
  thrown in C:\xampp\htdocs\openemr\portal\patient\fwk\libs\verysimple\Phreeze\Reporter.php on line 179

@Firehed Here is a fix so you can continue. Looks like the UI has issues also with styling.

portal/patient/fwk/libs/verysimple/Phreeze/Reporter.php

Reporter.php (9.3 KB)

2 Likes

btw: Here is what you’re after. Can edit and post from audit

1 Like