Dentolize · Balance Invoice Webhooks & API Config Cleanup Walkthrough
On this pageTermsData model notes

Glossary & data model

Terms

API Config Dentolize's outbound webhook system. Settings → Integrations → API Config, gated by the Company.apiEnabled flag. Each configured row is one URL plus a list of event types it should receive.

Webhook / API Config row Stored as JSON in Company.apiConfig (a Prisma Json? column — not a separate table). Each entry has { id, url, secret, apis } after this PR (type removed). apis is an array of event-type strings like "NEW_BALANCE_INVOICE".

Event type One string constant per kind of thing that can happen (NEW_PATIENT, NEW_INVOICE, NEW_PAYMENT, ..., and now NEW_BALANCE_INVOICE, NEW_BALANCE_PAYMENT). Defined once in apiTypes (packages/server/src/apis/apiConfig/mutationsApiConfig.js) and reused by both the resolvers that fire events and the payload builder that shapes them.

Balance Invoice An Invoice record with balanceInvoice: true and details: 'Balance Invoice'. Not a separate model — same Invoice table as regular invoices, distinguished by that boolean flag. Always created fully paid (paidInFull: true).

Balance Payment A Payment record tied to a Balance Invoice, same distinction pattern — same Payment table, identified by being linked to a balance invoice and (for the direct top-up path) details ending in "Balance Payment".

Patient balance / Patient.balance A running credit total on the patient record. Incremented by Add Balance and by the overpaid portion of a regular payment. Spent down when a future invoice payment is marked to draw fromBalance.

handleCallApi The function that actually sends a webhook: looks up the company's stored apiConfig, finds every row subscribed to the given event type, builds the payload via getOtherDataFromPayload, HMAC-signs it if a secret is configured, and POSTs it. Located in packages/server/src/apis/apiConfig/mutationsApiConfig.js. Failures inside it are caught and discarded — see For Quality.

getOtherDataFromPayload The single payload-shaping function (in packages/server/src/apis/apiConfig/otherAPIs.js) that converts an internal record into the JSON body sent to a webhook. Used for every event type — formerly one of three (other/nphies/zatca), now the only one.

Data model notes

  • Company.createdById — the user who created the company (typically the

owner). Used as the default doctor on balance invoices/payments, since there's no natural doctor for a balance top-up the way there is for a clinical appointment. Must be non-null for Add Balance or overpayment-to-balance conversion to work at all — see the edge case in For Quality.

  • InsurancePolicy has no name field — the display name for a policy is

holderName. This tripped up the webhook payload builder before this PR (see Payload accuracy fixes) and is worth remembering anywhere else InsurancePolicy data is surfaced.

  • Invoice.referenceId / Payment reference numbers are assigned

post-creation via updateInvoiceReferenceId / updateTransactionReferenceId (packages/server/src/utils/queryUtils.js), not at insert time — which is why it's possible (and, before this PR, was a bug) to assign the returned reference number onto the wrong in-memory object.