Restoring the Payment Gateway: What Broke and How We Fixed It
Restoring the Payment Gateway: What Broke and How We Fixed It
Version: 0.1.49
Overview
Version 0.1.49 resolves a critical regression that completely blocked the ability for portal users to make payments. This post documents what the correct payment flow looks like, what regressed, and what the restored implementation does.
The Payment Request Flow
The myProp payment experience is built on top of AgentOS payment request data. At a high level, the flow works like this:
-
The portal fetches payment request data from the Lambda-backed endpoint:
GET /{clientName}/payments/requests/{personID}This in turn proxies:
GET /{clientName}/payments/requests/{personID}?api_key=...against AgentOS.
-
The response carries three distinct payment entry points:
Field Purpose GenericPaymentLinkA general-purpose gateway URL shown whenever payments are enabled LatestPaymentRequest.RequestUrlGateway URL for the most recent payment request RequestHistory[].RequestUrlPer-item gateway URL for each historical request -
Clicking any of these URLs opens the payment gateway in a new tab via
window.open(url, '_blank').
What Regressed
During the portal rebuild, src/components/payment-requests/index.tsx was rewritten using a different data source and a custom data model:
- Wrong endpoint: The component queried
/v3/{shortName}/lettings/{personType}/{accountId}/paymentrequests— a generic AgentOS v3 listing endpoint — rather than the Lambda payment requests endpoint. - Stripped data model: API responses were mapped to a local
PaymentRequesttype that did not include aRequestUrlfield. - No payment action: The UI rendered read-only status cards. There was no button to open a payment gateway.
The result was that RequestUrl, GenericPaymentLink, and LatestPaymentRequest.RequestUrl were entirely absent from the application at runtime. Users had no way to pay.
The Restored Implementation
Data Layer (src/lib/letmc/payment-request.ts)
The service module now calls the correct Lambda endpoint and maps the full AgentOS response shape:
// Response shape preserved from AgentOS
interface PaymentRequestsResponse {
PaymentsEnabled: boolean;
GenericPaymentLink: string;
LatestPaymentRequest: {
RequestUrl: string;
// ...other fields
};
RequestHistory: Array<{
RequestUrl: string;
AmountLeftToPay: number;
SystemState: string; // e.g. 'Cancelled'
RequestType: string; // e.g. 'STO'
// ...other fields
}>;
}
UI Layer (src/components/payment-requests/index.tsx)
Generic Payment Card
Displayed whenever PaymentsEnabled === true. Provides a general entry point to the payment gateway:
<GenericPaymentRequestCard
link={GenericPaymentLink}
onPay={() => window.open(GenericPaymentLink, '_blank')}
/>
Latest Payment Request Card
Surfaces the most recent payment request with a direct gateway link:
<LatestPaymentRequestCard
request={LatestPaymentRequest}
onPay={() => window.open(latestRequest.RequestUrl, '_blank')}
/>
Payment History Items
Each item in RequestHistory now includes an action button, gated on business rules:
// Button is shown only when there is an outstanding balance
// and the request has not been cancelled.
const canPay =
item.AmountLeftToPay > 0 && item.SystemState !== 'Cancelled';
const label =
item.RequestType === 'STO' ? 'Set up now' : 'Pay Now';
{canPay && (
<Button onClick={() => window.open(item.RequestUrl, '_blank')}>
{label}
</Button>
)}
Button Label Reference
| Condition | Button Label |
|---|---|
RequestType === 'STO' (Standing Order) | Set up now |
Any other RequestType with balance due | Pay Now |
AmountLeftToPay === 0 | (button hidden) |
SystemState === 'Cancelled' | (button hidden) |
Upgrade Notes
This fix is fully backwards-compatible. No configuration changes are required. Portals that were live prior to v0.1.49 will automatically gain the restored payment buttons on their next deployment.