Developer API
Payment links from
your own software
Create PatientPayments™ bill pay links for patient balances with one REST call, then get a signed webhook the moment the patient pays, the bank returns the debit, or the office issues a refund. Built for practice management systems, billing vendors, and in-house tools.
OpenAPI 3 spec at /api/v1/openapi.json · Test mode with no money moved · HMAC-signed webhooks
curl https://api.patientpayments.com/api/v1/payment-links \
-H "Authorization: Bearer pp_test_…" \
-H "Idempotency-Key: 7c1e4f0a-9b2d-4e3c-8f1a-2d5b6c7e8f90" \
-H "Content-Type: application/json" \
-d '{
"amount": 185.00,
"description": "Crown - tooth #14",
"externalReference": "INV-2026-00123",
"patient": {
"firstName": "Jordan",
"lastName": "Rivera",
"phone": "+12085551234",
"externalId": "PMS-48213"
}
}'
→ 201 Created
{
"id": "plink_3f2a9c1d4e5b4f6a8d9c5e3f2a1b0c9d",
"url": "https://secure.patientpayments.com/pay/K7M2P9QX",
"status": "active",
"amount": 185.00,
...
}
What you can build
One integration, every balance collected
The office keeps its PatientPayments™ account, Stripe payouts, receipts, and dashboard. Your software decides when a balance is due.
Statements that pay themselves
Generate a link for every open balance in your ledger and drop it on the statement, in the portal, or in your own text and email. Patients pay by card or bank on a hosted page.
Post payments automatically
Subscribe to payment_link.paid and post the payment to the right account the second it clears. Refunds, bank returns, and disputes arrive the same way.
Nothing sensitive in your stack
Card and bank details are entered on PatientPayments™ hosted pages, never in your software. You send an amount and a name; you get back a URL and events.
How it works
Most integrations are a few dozen lines. Start in test mode, flip to a live key when the office is ready.
Get a key
The practice admin creates a pp_test_ or pp_live_ key under API & Webhooks.
Create a link
One POST with an amount, description, and the patient's name and mobile number returns a hosted payment URL.
Register a webhook
Point an HTTPS endpoint at us. Every event is signed with HMAC-SHA256 and retried for up to three days.
Simulate, then go live
In test mode, POST /simulate drives paid, processing, failed, and expired outcomes so you can test every path without a card.
Webhooks
Every state change, delivered
Events carry the full payment link, so one handler can post, reverse, and reconcile without a follow-up call. Same event id on every retry, so duplicates are easy to ignore. Missed a few while you were down? Replay up to 30 days.
Webhook integration guide →| payment_link.processing | Bank payment submitted, settling in 3–5 business days |
| payment_link.paid | Payment succeeded (card immediately, bank once settled) |
| payment_link.failed | Bank payment returned after submission |
| payment_link.refunded | Office refunded some or all of the payment |
| payment_link.disputed | Patient's bank opened a chargeback |
| payment_link.dispute_closed | Dispute resolved, won or lost |
| payment_link.expired | Link passed its expiry unpaid |
| payment_link.cancelled | Cancelled by your integration or office staff |
Designed to be safe to expose
The API only ever touches the practice that issued the key, and only the data a payment link needs.
Scoped keys
Read, write, and webhook permissions are granted separately. Keys can be pinned to a single location and given an expiry.
Opaque ids
Every id is a random plink_, loc_, we_, or evt_ value. Nothing is guessable or sequential.
Signed webhooks
HMAC-SHA256 over a timestamp and the raw body, with a 5-minute replay window and zero-downtime secret rotation.
Idempotent writes
Send an Idempotency-Key and retry freely. A network blip never creates two links.
Ready to connect?
API access is switched on per practice. If you build software for practices, tell us which one you are starting with and we will enable it and send you a test key the same day.