Skip to content

[BUG] payment_initiate_props never dispatched after custom_provider_ready in invoice flow β€” contradicts documented behaviorΒ #281

@alespin2021

Description

@alespin2021

πŸ› Describe the Bug

The official docs at https://marketplace.gohighlevel.com/docs/marketplace-modules/Payments/ state that after the custom provider iframe dispatches custom_provider_ready, HighLevel sends payment_initiate_props to the iframe with payment details. In practice, this second postMessage never fires when the customer pays an invoice at link.fastpaydirect.com/invoice/{invoiceId}.

Verified behavior:

  • Iframe loads at paymentsUrl and dispatches { type: "custom_provider_ready", loaded: true, addCardOnFileSupported: true } to parent.
  • GHL's own console logs: "Calling processPayment, payment element ready" β€” confirms ready was received.
  • GHL's backend call POST /payments/custom-provider/initiate/invoice returns 201 Created with a valid transactionId.
  • Expected next step per docs: GHL's frontend dispatches payment_initiate_props to iframe.
  • Actual: no postMessage is ever delivered to the iframe.

Manually dispatching payment_initiate_props via window.postMessage inside the iframe completes the flow successfully, proving the iframe handler is correct. The missing step is exclusively GHL's parent-to-iframe dispatch.

Happens identically in live mode and test mode. Reproduced on multiple invoices, after uninstalling/reinstalling the app, with all 11 required scopes granted (payments/orders., payments/custom-provider., invoices.readonly, etc.).

πŸ“ API Endpoint

/payments/custom-provider/initiate/invoice (returns 201 OK but subsequent postMessage never dispatched)

βœ… Expected Behavior

Per the official documentation:

"Once the ready event is dispatched by Iframe, GHL dispatches a data event
sending all the data needed for the iframe to process the payment."
β€” https://marketplace.gohighlevel.com/docs/marketplace-modules/Payments/

After the iframe emits custom_provider_ready, GHL's parent window should send:
{
"type": "payment_initiate_props",
"publishableKey": "...",
"amount": 100,
"currency": "USD",
"mode": "payment",
"orderId": "...",
"transactionId": "...",
"contact": {...},
"locationId": "..."
}

This never occurs. The iframe waits indefinitely and the customer cannot pay.

πŸ’» Screenshots or Code Samples

Iframe sends (confirmed via browser console):

window.parent.postMessage({
  type: 'custom_provider_ready',
  loaded: true,
  addCardOnFileSupported: true
}, '*')
GHL console log confirming receipt:

C0mnZJeE.js:1 responseData Proxy(Object)
C0mnZJeE.js:1 Calling processPayment, payment element ready
GHL backend request (succeeds):

POST https://backend.leadconnectorhq.com/payments/custom-provider/initiate/invoice
Body: {
  "altId": "nWt0qbrzu7q8OAenxxnM",
  "altType": "location",
  "invoiceId": "69e7a6b3e701b65f####",
  "amount": 1,
  "providerId": "69e7cd11cd19ad6bcfbdf417"
}
Response: 201 Created
{ "transactionId": "69e76e874710e24f3001a110",
  "traceId": "4341797a-8fd3-4c06-a8f5-411e5692bf96" }
Expected postMessage dispatch (never occurs):

// Expected per docs but never received:
{ type: 'payment_initiate_props', publishableKey, amount, ... }
Workaround proof (our side is correct):

// Manually dispatched in iframe console β€” full flow completes:
window.postMessage({
  type: 'payment_initiate_props',
  publishableKey: 'DC1B44DC-CE4C-43C9-1619-#######',
  amount: 100, currency: 'USD', mode: 'payment',
  orderId: '69e7a6b3e701b65f0fa4dea4',
  transactionId: 'test-tx',
  contact: { id: 'test', email: 'test@x.com', name: 'Test' }
}, '*')
// β†’ payment form renders correctly


### Product Area

payments

### πŸ“‹ Use Case

We're building a custom payment provider marketplace app (PAB Gateway) that our merchants install to collect credit card and ACH payments on their invoices, subscriptions, payment links, and products. When a customer clicks "Pay" on an invoice link (link.fastpaydirect.com/invoice/{id}), our iframe is supposed to load and display a card entry form so the customer can complete payment.

Our end-to-end implementation works correctly (verified via manual postMessage dispatch), but GHL's frontend never initiates the handshake. This blocks all payment collection through our provider.

### 🚨 Why Should This Be Prioritized?

This bug blocks the entire customer payment flow for ALL custom payment providers on invoices. A merchant that installs a custom provider and sends invoices to customers finds that customers cannot pay β€” the iframe loads but never receives the required payment data. There is no workaround from the merchant side or from the integration developer side.

The behavior directly contradicts documented behavior, which makes it an integration-breaking bug that affects every marketplace app implementing custom payments on invoices.

### 🧠 Additional Context

Configuration:

Marketplace App ID: 69de0c9b227aeda4d8cd712a
Location ID: nWt0qbrzu7q8OAenxxnM
Provider ID: 69e7cd11cd19ad6bcfbdf417
paymentsUrl: https://quick2pay.dev-pabgw.com/s/embed
queryUrl: https://gateway.dev-pabgw.com/api/platforms/pay/query
Scopes granted (11): payments/orders.readonly, payments/orders.write, payments/orders.collectPayment, payments/integration.write, payments/transactions.readonly, payments/subscriptions.readonly, payments/custom-provider.readonly, payments/custom-provider.write, invoices.readonly, contacts.readonly, products.readonly, products/prices.readonly
Trace IDs from reproductions:

Live mode: 4341797a-8fd3-4c06-a8f5-411e5692bf96 (initiate/invoice)
Test mode: 893ffdf4-fed9-4156-ad50-f63da627a9c6 (initiate/invoice)
Environment:

Browser: Chrome latest
Reproduced consistently across incognito/regular windows
App version in Live state with all scopes and payment methods (One Time, Recurring, Off-Session) enabled
Observations:

GET /payments/integrations/entity-providers?...&entityId=undefined&includeDefault=true β€” this preflight query has entityId=undefined, though the invoice has a valid _id in the URL. Possibly a separate frontend issue but may be related.
Iframe receives no postMessages from link.fastpaydirect.com besides React DevTools extension noise.
Our response headers include no restrictive X-Frame-Options, no CSP frame-ancestors, no COEP/COOP/CORP β€” nothing blocking cross-origin embedding or messaging.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions