Revenue & Payer Integrations

Recipes for the Wave-3 surfaces: external payment recording, hosted payment links, claims monitoring, and the ZATCA compliance stream. Scope tier for all of these is financial (rendered with a money icon in the consent flow); every financial list requires a from/to window of at most 366 days.

Recording payments from a POS or gateway (payments:write)

You collected the money outside Dentolize; record it against the invoice so clinic totals, treasuries and reports stay true:

const payment = await client.payments.create(
  { invoiceId, amount, type: 'CARD', reference: gatewayTxId },
  { idempotencyKey: gatewayTxId } // your own stable key — survives process restarts
);

Generating payment links (paymentlinks:write)

Let a patient pay remotely on the clinic's own gateway:

const link = await client.paymentLinks.create({ invoiceId }); // amount defaults to pending
await sendWhatsApp(patientPhone, link.paymentLink);

Then react to webhooks: onlinepayment.succeeded (its data.paymentId is the recorded payment — the platform records it for you, do not also call payments.create), onlinepayment.failed, onlinepayment.refunded. A clinic without a usable gateway yields 409 payment_provider_not_configured; gateway-side rejections surface as 502 payment_provider_error.

Claims monitoring dashboard (claims:read + insurance:read)

Build a payer-facing view of claim pipelines:

// Directory once (cache it): resolve insurer ids to names
const insurers = new Map();
for await (const company of client.insuranceCompanies.iterate()) insurers.set(company.id, company);

// Claims whose period overlaps the quarter
for await (const claim of client.claims.iterate({ from, to })) {
  track(insurers.get(claim.insuranceCompanyId)?.name, claim.status, claim.totalInsuranceAmount,
        claim.rejectedAmount, claim.remainingAmount, claim.totalReceivedAmount);
}

ZATCA compliance stream (einvoices:read)

Feed a compliance dashboard without touching XML or certificates:

const failing = await client.einvoiceSubmissions.list({ from, to, status: 'REJECTED' });
for (const submission of failing.data) alert(submission.invoiceId, submission.errorMessages[0]);