Skip to main content
All Docs
FeaturesmyProp (AgentOS People Portal)Updated April 4, 2026

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:

  1. 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.

  2. The response carries three distinct payment entry points:

    FieldPurpose
    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
  3. 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 PaymentRequest type that did not include a RequestUrl field.
  • 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

ConditionButton Label
RequestType === 'STO' (Standing Order)Set up now
Any other RequestType with balance duePay 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.