Ownit Website Form Submissions: Technical Note

SubjectForm submission integration path & intermittent failure investigation
ScopeQuote Request and Contract Review forms on ownitconveyancing.com.au
StatusReference document. Describes current production behaviour.

1. Overview

This note documents how form submissions on the Ownit Conveyancing website reach Salesforce, clarifies the role (and non-role) of third-party tooling such as N8N and the legacy Web-to-Lead integration, and describes the logging available for diagnosing intermittent failures.

2. Submission path

The website forms do not use the classic Salesforce Web-to-Lead servlet. They post directly into the Salesforce org through the Experience Cloud (LWR) Apex runtime hosted on the customer's own Salesforce domain:

POST https://forms.ownitconveyancing.com/webruntime/api/apex/execute
     ?language=en-US&asGuest=true&htmlEncode=false

This is Salesforce's modern, supported replacement for Web-to-Lead on Experience Cloud sites. Records land directly in the Salesforce org via a configured Apex class, the Web-to-Lead reporting page will therefore show no entries by design; that integration is not part of this flow.

Origin of this endpoint. The URL, Apex class ID, method names, and payload envelope were not invented by us, they were obtained by inspecting Ownit's original Salesforce-hosted quote form at https://forms.ownitconveyancing.com/quote-request. That page is the previous public quote form, built directly on Salesforce Experience Cloud (LWR). The new ownitconveyancing.com.au site calls the same endpoint, with the same envelope, in the same way that page's own JavaScript does. We are simply invoking the existing Salesforce integration from a different front end, the back-end contract is owned and controlled by Salesforce.

Implication Any response the website receives from this endpoint is also the response Salesforce's own original form receives. The "empty 200" behaviour described in section 5 can be reproduced by submitting the same input combination on forms.ownitconveyancing.com/quote-request directly, the failure mode is on the Salesforce side and is not specific to the new website.

Apex class invoked: 01p5g00000oJUoJ
Apex methods called from the website:

2.1 End-to-end flow

flowchart LR U["User
(browser)"] -->|1. Submit form| FE["Next.js Frontend
ownitconveyancing.com.au"] FE -->|2. POST JSON| API["Next.js API route
/api/create-quote
/api/submit-quote
/api/submit-contract-review"] API -->|3. Forward payload| SF["Salesforce Experience Cloud
forms.ownitconveyancing.com
/webruntime/api/apex/execute"] SF -->|4. Run Apex method
on class 01p5g00000oJUoJ| ORG[("Salesforce Org
Quote Request / Lead records")] SF -.->|Response JSON| API API -.->|Response JSON| FE API -->|5. Log request & response| LOG[("Strapi log store
instant-quote-logs
(7-day retention)")]

Note The Next.js API route is a thin server-side proxy. It does not transform business data; it wraps the payload in the standard Salesforce Apex envelope (namespace, classname, method, params) and forwards it. This is the same pattern Salesforce uses internally when a Lightning Web Component calls Apex on an Experience Cloud site.

In parallel with returning the Salesforce response to the browser, the API route writes a structured log entry to our Strapi instance (collection instant-quote-logs) capturing the inbound frontend request, the outbound Salesforce payload, and the Salesforce response. Logs are retained for 7 days and are the primary diagnostic source for the failures discussed in section 4. The log write is fire-and-forget, it does not block or affect the user-facing response, and a logging outage cannot cause a form submission to fail.

2.2 API endpoints in scope

EndpointPurposeSalesforce Apex method
/api/create-quoteSubmits a new Quote RequestcreateQuoteRequest
/api/submit-quoteFinalises an existing Quote Request by record IDsubmitQuoteRequest
/api/submit-contract-reviewSubmits a Contract Review leadsubmitLead
/api/upload-contractAttaches contract files to a Quote / LeaduploadFile

3. Role of N8N

N8N is not present in the current website code base. A grep of the source tree returns no N8N references, no related webhooks, and no third-party workflow tooling. The current production flow is website → Next.js API proxy → Salesforce Apex, with no intermediate workflow tool.

Per team knowledge, N8N was used at an earlier stage of the integration to broker requests between the website and Salesforce. It has since been retired in favour of the direct Apex submission path described in section 2, which removes a hop from the chain, eliminates a third-party point of failure, and lets Salesforce receive the payload in the exact shape its Apex methods expect. This historical context comes from the delivery team rather than from evidence in the current code (which is consistent with the integration having been fully removed).

Practical implications:

4. Diagnostics, intermittent failures and undefined responses

Every Salesforce request and response from the website is logged server-side for the last 7 days. Each log entry captures the following fields:

FieldContents
frontendRequestEndpoint hit and the raw body received from the browser.
salesforceRequestExact URL and JSON payload sent to Salesforce.
salesforceResponseHTTP status code and full response body returned by Salesforce.
createdAtTimestamp.

For any failed submission, this allows determination of whether:

  1. The payload reached Salesforce correctly;
  2. Salesforce returned an error, and which kind (Apex exception, validation rule, permission, governor limit); or
  3. The response was malformed or partial, which would explain undefined values surfacing in the UI.
Information required to investigate specific failures: With this, the matching log entries can be pulled and the failure traced end-to-end, returning a root cause and remediation path.

5. Log analysis findings (7-day window)

The full Strapi log store was queried for the 7 days ending 2026-06-22 02:00 UTC. Total entries: 274 (250 to /api/create-quote, 24 to /api/submit-quote; the /api/submit-contract-review endpoint is not yet covered by the logger, see section 6.4).

5.1 Transport layer

All 274 calls to Salesforce returned HTTP 200. No 4xx, no 5xx, no timeouts in the 7-day window. The website-to-Salesforce transport is healthy at the network and auth layers.

5.2 Anomaly, "empty 200" responses

Despite the clean HTTP status, 10 of the 250 createQuoteRequest responses returned a 200 with an empty body:

{"returnValue": {"statusCode": 200}, "cacheable": false}

No mainProduct, no fixedFeeProduct, no childProducts, no quoteRequest. The website expects these fields to render the quote, so the UI reads them as undefined. This is the symptom users have been reporting.

A clear pattern emerged across the 10 empty responses:

FieldAffected values
stateQLD (9 / 10), VIC (1)
propertyTypeOff-the-Plan Land (6), Off-the-Plan Unit or Townhouse (2), Commercial Building (2)
transactionTypeSale (6), Transfer (4), never Purchase
formTypeform-old-version (10 / 10)

5.3 Failure rate scoped to the affected property types

Across all 250 createQuoteRequest calls the empty-response rate is 4 %. But when scoped to the specific property types involved, the picture matches the client's "15-20 %" report:

Property typeEmpty / TotalRate
Off-the-Plan Land6 / 2227 %
Off-the-Plan Unit or Townhouse2 / 540 %
Commercial Building2 / 633 %
House (most common)0 / 1340 %
Unit0 / 590 %
Land0 / 210 %

This also explains the "one minute it works, the next minute it doesn't" observation, the same user can test successfully on a House (Purchase) and then fail on Off-the-Plan Land (Sale) in QLD. The failure is not random; it is tied to the combination of (state, propertyType, transactionType).

5.4 Additional partial-response case

One further entry (log id 3845, QLD Sale) returned a populated mainProduct but was missing fixedFeeProduct. Same root-cause family, a partial product configuration in Salesforce rather than a transport problem.

5.5 Funnel observation (informational, not a failure)

create-quote = 250, submit-quote = 24. The 9.6 % rate is user funnel drop-off after viewing the quote, not a system failure. Mentioning here so it is not misread as a high failure rate.

6. Root cause and recommended actions

6.1 Most likely root cause

Salesforce-side product configuration gap. The createQuoteRequest Apex method appears to silently return 200 with an empty body when no Product record matches the requested (state, transactionType, propertyType) combination. The website cannot distinguish this from a real success and falls back to rendering undefined values.

The website is faithfully relaying whatever Salesforce returns. The fix needs to happen in two places: data in Salesforce (so the matching products exist) and contract in Apex (so the website is told clearly when something is missing).

6.2 Recommended actions (priority order)

  1. Audit Salesforce product records for QLD + (Off-the-Plan Land / Off-the-Plan Unit or Townhouse / Commercial Building) + (Sale / Transfer). Most likely no matching Product record exists for these combinations.
  2. Update the Apex method (createQuoteRequest) to return an explicit error response (e.g. statusCode: 404 with a message) when no product matches, instead of an empty 200.
  3. Add a defensive check on the website (optional front-end change, scoped separately) so that, even before the Apex change is deployed, users see a clear message ("we can't generate an instant quote for this combination, please contact us") rather than undefined fields. Small piece of work, flagged here as a recommendation rather than included as part of the investigation.
  4. Extend logging to /api/submit-contract-review (optional). The Contract Review endpoint integrates with Salesforce via the same Apex executor (method submitLead, creating Lead records) but is not currently feeding the log store, so Contract Review failures are invisible. Adding the same logging treatment is a small piece of work and can be quoted separately if Ownit wants visibility extended across all forms.

7. Summary

QuestionAnswer
Why is Salesforce Web-to-Lead empty? By design. The website uses Salesforce Experience Cloud Apex, not the legacy Web-to-Lead servlet. Records still land in the Salesforce org, through a modern, supported integration.
Is N8N involved in form submissions? Not in the current production flow. The website code base contains no N8N references. The site posts directly to Salesforce via the Apex executor. Per team knowledge, N8N was used in an earlier integration stage and has since been retired; any legacy workflow found is no longer invoked.
What is causing the 15-20 % failures? Likely a Salesforce-side product configuration gap. Specific combinations (mostly QLD + Off-the-Plan or Commercial property types + Sale/Transfer) return a 200 with no product data, which the UI renders as undefined. Common combinations (House, Unit, Land) are unaffected. See section 5 for the full breakdown.