Integration guide

Everything your billing system needs: one endpoint to create a financing link, one webhook to learn it funded.

Authentication

Every request carries your organization's API key, shown once in the provider portal when your account is created.

Authorization: Bearer pcf_your_key
Base URL: https://api.emrfi.com/api/partner

Keys are stored hashed on our side; if one is lost, EMRfi issues a new one and retires the old.

Flow

  1. Your system creates a financing session for a balance and receives a patient URL.
  2. You deliver the URL to the patient (SMS, email, patient portal message, or a button in your app).
  3. The patient sees a page in your branding and applies with Affirm (about ninety seconds).
  4. When the loan funds, we POST a signed webhook to you and the session status becomes funded. Money settles to your Stripe account and then your bank on your payout schedule.

Create a financing session

POST /financing-sessions
Content-Type: application/json

{
  "amountCents": 150000,             // required, integer, the balance owed to you
  "externalRef": "ENC-48213",        // required, your invoice / encounter / account id
  "patientRef": "MRN-00912",         // optional, an identifier meaningful to you (no PHI)
  "patientEmail": "pt@example.com",  // optional, prefills Affirm's application
  "description": "Visit balance",    // optional, shown on the patient page (no PHI)
  "method": "affirm"                 // optional: "affirm" (default) or "card"
}

Response 201:

{
  "id": 42,
  "url": "https://emrfi.com/pay/3f9c…",   // give this to the patient
  "status": "created",
  "method": "affirm",
  "balanceCents": 150000,
  "platformFeeCents": 4350,
  "stripeFeeCents": 9291,
  "patientTotalCents": 163641,
  "providerNetCents": 150000,
  "expiresAt": "2026-09-21T14:03:11.000Z"   // links expire after 24 hours; create a new one if needed
}

Affirm requires a balance of at least $50.00. Below that, or for organizations without Affirm active, use "method": "card".

Check status

GET /financing-sessions/{id}
GET /financing-sessions            // most recent 200
statusmeaning
createdLink issued, patient has not completed.
fundedLoan approved and paid. Post the payment to the account.
expiredLink expired unused. Create a new session.
cancelledVoided before funding, or reversed after funding.

Void or reverse

POST /financing-sessions/{id}/cancel

On a created session this voids the link. On a funded session it issues a full refund, including all fees, and Affirm cancels the patient's loan. Use it when a balance was posted in error or is later covered by insurance.

Webhooks

Set your webhook URL in the portal (Integration tab) or with PATCH /account. We POST JSON with a signature header:

POST https://your-system.example.com/emrfi
pcf-signature: t=1758380001,v1=9b3d…

{ "type": "financing_session.funded",
  "createdAt": "2026-09-20T14:53:21.000Z",
  "data": { "sessionId": 42, "externalRef": "ENC-48213", "patientRef": "MRN-00912",
            "balanceCents": 150000, "amountCents": 163641, "platformFeeCents": 4350,
            "paymentIntent": "pi_3…" } }

Verify it: compute HMAC-SHA256 over t + "." + rawBody with your webhook secret, compare to v1, and reject timestamps older than five minutes.

// Node
const [t, v1] = sig.split(',').map(x => x.split('=')[1]);
const expect = crypto.createHmac('sha256', SECRET).update(`${t}.${rawBody}`).digest('hex');
const ok = crypto.timingSafeEqual(Buffer.from(expect), Buffer.from(v1)) && Date.now()/1000 - t < 300;

Respond with any 2xx. We attempt delivery once and mark the session notified; poll GET /financing-sessions/{id} as a backstop.

Quotes

GET /quote?amountCents=150000&method=affirm

Returns the same fee fields as a session, without creating one. Useful for showing a patient "finance $1,636.41 over time" before they click.

Account

GET  /account                 // status, branding, fee model
PATCH /account                // { brandName, logoUrl, brandColor, supportPhone, webhookUrl }
POST /account/sync            // refresh payment status from Stripe
POST /onboarding-link         // hosted Stripe verification (the portal embeds this for you)

Errors

codewhen
400Missing or invalid field; message says which.
401Missing or unknown API key.
404Session not found (or belongs to another organization).
422Action not allowed in this state, e.g. payments setup incomplete, Affirm not active, balance below minimum.

No PHI, by design

Send us an amount and identifiers that mean something to you. Do not put names, dates of birth, diagnoses, or clinical detail in externalRef, patientRef, or description. EMRfi is not a business associate under HIPAA for that reason, and your patient's financing application is handled by Affirm under Affirm's own privacy notice.