Calmony Pay Payment Integration
Calmony Pay Payment Integration
The platform supports end-to-end payment processing via Calmony Pay, enabling agents to collect holding deposits, move-in balance payments, renewal fees, and custom one-off payments from tenants.
Overview
Payments flow through a central payments_ledger table that tracks every transaction from creation through to completion (or failure/cancellation). Tenant checkout is handled by a Calmony Pay hosted page. On successful payment, a webhook triggers an Inngest function that automatically updates the ledger, completes linked todos, and marks custom payment tasks as paid.
Payment Types
| Type | Description |
|---|---|
holding_deposit | Deposit collected during offer acceptance |
move_in_balance | Balance payment due before move-in |
renewal_fee | Fee charged on tenancy renewal |
custom | Bespoke one-off payment created by an agent |
Payment Methods
- Card — standard card payment via Calmony Pay checkout
- Pay by Bank (open banking) — bank-to-bank transfer initiated through Calmony Pay
Card Payment Limit
Each agency has a configurable maximum card payment ceiling (maxCardPaymentPence). Payments above this threshold are automatically forced to use Pay by Bank.
- Default: £2,000 (200,000 pence)
- No limit: set to
nullto allow all amounts via card - Managed via
payment.getCardLimitandpayment.updateCardLimit(admin-only)
Payment Lifecycle
pending → processing → succeeded
↘ failed
↘ refunded
↘ cancelled
How Payments Work
1. Create a Payment Task
Call payment.createPaymentTask with the payment details. The system:
- Creates a
payments_ledgerentry with statuspending - Enforces the agency card limit — overrides method to
open_bankingif the amount exceeds the ceiling - Creates a Calmony Pay checkout session
- Returns a checkout URL to redirect the tenant
2. Tenant Completes Checkout
The tenant is redirected to the Calmony Pay hosted checkout page to complete payment by card or Pay by Bank.
3. Webhook Processing
On successful payment, Calmony Pay sends a payment_intent.succeeded webhook to /api/webhooks/calmony-pay. This dispatches a calmony-pay/payment_intent.succeeded event to Inngest, which runs the paymentCompletedSync function:
- Deduplicates replayed webhooks using
processedEvents - Finds the
payments_ledgerentry by payment intent ID orledger_idmetadata - Updates ledger status to
succeededand setspaidAt - If linked to a custom payment task — marks it as
paid - If linked to a todo — marks it as complete
- Logs an audit entry for each state change
4. Manual Payment Fallback
Agents can manually confirm payments (e.g. for bank transfers received outside the platform) using payment.markPaymentManuallyPaid. This accepts an optional payment reference and updates the ledger, linked todo, and custom payment task in the same way as the webhook path.
API Reference
payment.createPaymentTask
Creates a ledger entry and Calmony Pay checkout session.
Returns: { checkoutUrl: string, ledgerEntryId: string }
Key inputs:
amountPence— amount in GBP pencepaymentType—holding_deposit|move_in_balance|renewal_fee|customtenancyId— linked tenancy (optional)todoId— linked todo to auto-complete on success (optional)customPaymentTaskId— linked custom payment task (optional)description— human-readable description shown on checkout
payment.getPaymentStatus
Returns full ledger entry details for a given payment ID.
payment.markPaymentManuallyPaid
Manually confirms a payment. Updates the ledger (manuallyPaid: true), linked todo, and linked custom payment task.
Key inputs:
paymentId— ledger entry IDmanualPaymentReference— reference string (e.g. bank transfer reference)
payment.list
Paginated list of payments. Supports filtering by:
tenancyIdstatuspaymentType
payment.stats
Returns aggregate counts and totals:
- Number and total amount of
pendingpayments - Number and total amount of
succeededpayments
payment.getCardLimit / payment.updateCardLimit
Read or update the agency card payment ceiling. Admin-only.
payment.cancelPayment
Cancels a pending payment and updates ledger status to cancelled.
Audit Logging
All state-changing operations are audit logged with resourceType: "payment":
| Action | Trigger |
|---|---|
payment.created | createPaymentTask |
payment.succeeded | paymentCompletedSync webhook |
payment.manually_paid | markPaymentManuallyPaid |
payment.cancelled | cancelPayment |
Environment Variables
No additional environment variables are required. The integration uses:
| Variable | Purpose |
|---|---|
CALMONY_PAY_SECRET_KEY | Authenticates API requests to Calmony Pay |
CALMONY_PAY_WEBHOOK_SECRET | Validates incoming webhook signatures |
Both variables must already be configured in your environment.