Payments
Money in. Copays, balances, deposits — ContactFollowUp records them; Stripe handles the cards.
Kinds: COPAY, BALANCE, SELF_PAY, DEPOSIT. Status: PENDING, SUCCEEDED, FAILED, REFUNDED. Amounts are always in cents.
Record a payment
Log a payment against a contact. For payments collected through ContactFollowUp's Stripe checkout, use POST /api/payments/checkout instead.
Required scopes:
contacts.writeRequest body
| Name | Type | Description |
|---|---|---|
contactIdrequired | string | Patient paying. |
amountCentsrequired | integer | Amount in cents. 1 – 10,000,000. |
currency | string | ISO 4217 — defaults to USD. |
kindrequired | string | Payment kind. |
appointmentId | string | Optional linked appointment. |
Request body
{ "contactId": "cln…", "amountCents": 3500, "kind": "COPAY" }Responses
201 CreatedRecorded.example { "id": "pay_3k9w2x…", "contactId": "cln1f8s7p…", "amountCents": 3500, "currency": "USD", "kind": "COPAY", "appointmentId": "ap_3w8d2k…", "status": "SUCCEEDED", "createdAt": "2026-05-18T14:00:00Z" }
Code samples
curl -X POST https://app.contactfollowup.com/api/payments \
-H "Authorization: Bearer $HEARTHNOTE_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "contactId": "cln…", "amountCents": 3500, "kind": "COPAY" }'List payments
Filtered payment list.
Required scopes:
contacts.readQuery parameters
| Name | Type | Description |
|---|---|---|
contactId | string | Patient filter. |
status | string | Status filter. |
limit | integer | Default 100. |
Responses
200 OKPayments.example { "payments": [{ "id": "pay_3k9w2x…", "contactId": "cln1f8s7p…", "amountCents": 3500, "currency": "USD", "kind": "COPAY", "appointmentId": "ap_3w8d2k…", "status": "SUCCEEDED", "createdAt": "2026-05-18T14:00:00Z" }] }
Code samples
curl -X GET https://app.contactfollowup.com/api/payments \
-H "Authorization: Bearer $HEARTHNOTE_TOKEN" \
-H "Content-Type: application/json"Start a checkout session
Create a Stripe checkout session for a patient and return its hosted URL. The webhook from Stripe will mark the payment SUCCEEDED on completion.
Required scopes:
contacts.writeRequest body
| Name | Type | Description |
|---|---|---|
contactIdrequired | string | Patient paying. |
amountCentsrequired | integer | Amount in cents. |
kindrequired | string | Payment kind. |
appointmentId | string | Linked appointment. |
Request body
{ "contactId": "cln…", "amountCents": 3500, "kind": "COPAY" }Responses
201 CreatedCheckout created.example { "id": "pay_pending_…", "checkoutUrl": "https://checkout.stripe.com/c/pay/cs_test_…" }
Code samples
curl -X POST https://app.contactfollowup.com/api/payments/checkout \
-H "Authorization: Bearer $HEARTHNOTE_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "contactId": "cln…", "amountCents": 3500, "kind": "COPAY" }'