Skip to content

Payment route · one $180.00 visit Illustrative amounts · real mechanics

Qlynic

takes $0.00

reads the event, records the fee

  1. Patient $180.00 paid
  2. Stripe − $5.52 fee
  3. Your account $174.48 settled

money information

application_fee_amount transfer_data on_behalf_of — the three ways a platform can take a share of your charge. None of them appears anywhere in our Stripe calls.

Payments

The money goes to your account. We are not in the path.

The card is charged on your own connected Stripe account — your account ID goes out as a header on the call and Stripe does the rest. Stripe gives platforms three ways to take a share of a charge like that, and the honest way to tell you we use none of them is to name them: application_fee_amount, transfer_data and on_behalf_of return no matches anywhere in our code. The one deduction on that line is Stripe’s own processing fee, which Stripe sets and bills to your account, not ours.

What Qlynic does is read. When the payment settles, Stripe sends an event; Qlynic follows the charge to its balance transaction, records the fee and the net against that appointment, and works out the doctor’s share from the net rather than the gross — so the split you agreed is calculated on what actually landed. That is the dashed line in the diagram. It carries an event, and an event is not a cut.

Cancel pass · both words, side by side Same appointment · same afternoon

The patient is not coming. The front desk picks one word.

Cancelled No-show

  1. expired on Stripe The live pay link still payable
  2. voided Cash due at the desk still owed
  3. raised for review Money already collected raised for review
  4. never touched The insurance claim never touched

admin_upcoming admin_calendar manage_link — the three doors a cancellation comes through, and the same pass runs behind all of them. It goes after the door has already committed, on its own connection, with every step separately guarded, so nothing it does can turn a cancellation into an error on your screen.

A no-show is not a cancellation. The difference is the money you can still collect.

Both words end the visit, and about money that has already arrived they behave identically: it is raised as one payment.refund_review entry for a person to decide — the same entry the Stripe side writes, so one filter shows every case — and the insurance claim is left alone by both. That record belongs to the H-Link side of the system and this pass is deliberately locked out of it.

What only “cancelled” does is close the two doors money could still come through. The live checkout session is expired on Stripe’s side, so the link in the patient’s email stops working rather than quietly staying payable, and the cash you were expecting at the desk stops being expected. Mark the same appointment a no-show and both of those stay exactly where they were, because a visit somebody missed is one you may still be owed for. That is the whole difference, and it is a difference about money nobody has handed over yet.

Payment finalisation · appointment 48210 Illustrative amounts · real flag

The patient paid cash at the desk on the way in. Seven minutes later, sitting in the waiting room, they paid the link on their phone as well.

Collected $180.00 — what the visit costs

  1. 14:02 · cash at the desk $180.00 paid
  2. 14:09 · card, the pay link $180.00 paid

$360.00 is now recorded against a $180.00 visit, and that is on purpose.

Committed

duplicate_paid_payment

REFUND REVIEW appointmentId=48210 status=booked flags=duplicate_paid_payment

written to StripeWebhookEvents and to your activity log — under the same payment.refund_review action the cancel pass uses, so one filter shows every case of money that needs a person.

Two payments arrived for one visit. Both of them are in the record.

The webhook that finalises the second payment checks before it writes, and it already knows: there is another paid row on this appointment that is not this session. It writes the payment anyway. That is deliberate, and the comment above that check is where this section gets its name — money is still recorded, truth first, and the case is flagged after commit. Software that quietly drops the second payment leaves your books saying you took $180.00 on an afternoon when $360.00 left the patient’s accounts, and the patient is the one who finds out.

The judging is a separate pass and it runs after the transaction has committed, on its own read, wrapped so that it can never throw. Nothing it decides can change the amounts above the line, and nothing it gets wrong can fail the payment it was looking at. Two other flags come out of the same pass: paid_on_cancelled_appointment when money lands on a visit that was already cancelled, and paid_series_has_cancelled_occurrences with a count when it lands on a recurring series that has cancelled dates in it.

What Qlynic does not do is decide what should happen next. It will not refund the second payment, and it will not credit it forward to the patient’s next visit. Both of those are your clinic’s call and both of them have a name attached when they are made.

Doctor share · Dr Okafor Illustrative amounts · real arithmetic

You renegotiate the split today and raise it from sixty per cent to seventy. Here is everything that had already settled before you did.

70 %

the share in force from now on

was 60 % · the two dimmer marks are the rates this ledger was stamped with

  1. Settled After Stripe’s fee Stamped Doctor
  2. 02 Aug · 14:22 $174.48 net 55 % $95.96
  3. 09 Aug · 09:41 $145.20 net 55 % $79.86
  4. 14 Aug · 16:05 $232.10 net 60 % $139.26
  5. 18 Aug · 11:12 $174.48 net 60 % $104.69
  6. Next settlement not yet 70 %

DoctorSharePctAtTime DoctorPayableCentsAtTime — both are written only when Stripe’s fee lands, and only if they are still empty. A re-delivered webhook finds them filled and leaves them alone.

Change the split whenever you like. Last month will not change with it.

The share is stamped onto each payment at the moment Stripe’s fee lands — not when the visit was booked, and not when you run a payout. Two columns are written at that instant: the percentage in force right then, and the amount it comes to, calculated on the net — what actually arrived after Stripe’s cut — and rounded to the cent. The 18 August row above is the rounding: $174.48 at sixty per cent is $104.688, and it is stored as $104.69.

Both columns are written with a COALESCE that only fills them if they are still empty, and that one word does two jobs. Stripe re-delivers webhook events when it is unsure you received them; a second delivery of the same event finds the snapshot already there and changes nothing. And a rate you set tomorrow has no way of reaching backwards into a row that was filled last week.

Which means you can renegotiate a split in the middle of a month without anyone recalculating anything, and a payout run is reading figures that were fixed when the money landed rather than derived from whatever your settings happen to say today.

Qlynic · payments The whole surface, listed

Will not

  1. Issue a refund there is no call to /v1/refunds anywhere in the application
  2. Pay a doctor a payout run writes one row into DoctorPayoutBatches and moves nothing
  3. Hold your money the charge is made on your own connected account, never on ours
  4. Decide for you every flag it raises waits for a person with a name

Every Stripe call in the application — 7

  1. POST /v1/checkout/sessions open the page your patient pays on
  2. GET /v1/checkout/sessions/{id} read that page back
  3. POST /v1/checkout/sessions/{id}/expire close it when the visit is cancelled
  4. GET /v1/payment_intents/{id} read the payment
  5. GET /v1/charges/{id} follow it to the charge
  6. GET /v1/balance_transactions/{id} read Stripe’s fee and the net
  7. GET /v1/accounts/{id} read your Connect status

Five reads. Two writes, and both of them open or close a payment page. Not one of the seven moves a dollar.

Nothing here moves money. That is not a promise. It is a missing endpoint.

The list above is the whole of it — every place this application reaches across to Stripe, found by searching the repository rather than by remembering. Five of the seven only read. The two that write open and close the hosted page your patient pays on, which is also why a card number never touches a Qlynic server: the patient types it on Stripe’s page, on Stripe’s domain. /v1/refunds, the call that sends money back, is not there. A refund reaches Qlynic the way every other fact does — as a webhook it writes down after somebody else has already acted.

A payout run is the same shape. It reads what was stamped on each settled payment, groups it, and writes a single batch row. It makes no Stripe call at all and transfers nothing to anybody. How your doctors actually get paid stays exactly where it was — your bank, your payroll, your decision — and Qlynic’s job is to hand you the arithmetic already done and already dated.

That is the shape of everything on this page. It reads what happened to your money, writes it down where you can see it, and raises its hand when something needs deciding. It does not have an opinion, and it does not have a lever.