Skip to main content
The Mobile Bridge lets the Paylead WebApp (MFP) running inside your native WebView invoke native device capabilities: opening a URL in the system browser, writing to the clipboard, downloading a file. It uses the JSON-RPC 2.0 protocol over postMessage. Your native app receives requests from the WebApp and responds by calling back into JavaScript.
The bridge JavaScript is versioned (v1, v2, …). The machine-readable contract for each version is published as a schema.json. See the Methods reference below for the current version, and the Versions & download page to download a schema or browse older versions.

Transport

The WebApp communicates with your native app through the postMessage API. Your native app is responsible for exposing this channel at the exact location where the WebApp expects to find it. The location depends on the platform:
The inbound channel name is PayleadBridge (capital P, capital B), identical across iOS, Android, Flutter, React Native, and any other platform your app targets. This casing is part of the contract and is not negotiable. If your app registers a single shared channel name for multiple platforms (common in Flutter and React Native), use this exact casing everywhere, not one platform’s convention on one side and a different one on the other.A mismatch fails silently: on the platform where the casing doesn’t match, the WebApp never reaches your native handler, every bridge call falls back to standard web APIs instead, and nothing surfaces an error. The bug can go unnoticed until a partner reports missing native behaviour.
WebApp → NativeThe PayleadBridge channel must be exposed to window.webkit.messageHandlers.PayleadBridge.Once the channel is registered, the WebApp sends messages to your app by calling postMessage on it. For example, on iOS:
WebApp
You never call this yourself: the WebApp does it internally. Your app only needs to (1) register the channel at the expected location and (2) handle the incoming payloads. WKWebView auto-deserializes the JSON, so your handler receives a [String: Any] dictionary.Native → WebAppCall back with argument binding; never interpolate the JSON into the source.
Native
Never interpolate JSON strings into JavaScript source. Use argument binding (callAsyncJavaScript on iOS), JSONObject.quote() (Android), or a careful dart:convert encode-and-escape (Flutter). Direct interpolation such as "response('${json}')" creates a JS injection vector. This rule applies every time you call back into the WebApp.Separately, window.payleadBridge (lowercase) is the WebApp’s own object, registered automatically and used only to call back with .response(...). Never read from or write to it from native code.

Message format

Request (WebApp → Native)

Your handler receives JSON-RPC 2.0 request objects:

Success response (Native → WebApp)

Call window.payleadBridge.response(jsonString) with a serialized JSON-RPC 2.0 result:

Error response (Native → WebApp)

If the action fails, respond with a JSON-RPC 2.0 error (see Error codes):

Envelope constraints

  • jsonrpc must equal "2.0". Reject any other value with error code -32600. If the envelope cannot be parsed at all, respond with "id": null and error code -32600.
  • id must be a UUID v4 string. The WebApp always sends a randomly generated UUID v4; non-string ids are silently dropped by the WebApp.
  • The id in the response must match the id from the request.
  • result and error are mutually exclusive. On success include result and omit error; on failure include error and omit result. If the WebApp receives both, error takes precedence and the call rejects.
  • Timeouts. The WebApp rejects requests that don’t receive a response within 5 seconds for browser.open and clipboard.write, and 30 seconds for file.download. For file.download, respond once the download has been triggered (consent granted, transfer started), not once it completes.

Methods

browser.open

Opens a URL in the device’s native browser (outside the WebView).
string
required
URL to open. Must use the https:// scheme.Pattern ^https:// · max length 2048

clipboard.write

Copies text to the device clipboard.
string
required
Text to copy to clipboard.max length 4096

file.download

Downloads a file and presents it to the user.
string
required
URL of the file to download. Must use the https:// scheme.Pattern ^https:// · max length 200
string
Suggested filename. Allowed characters: letters, digits, underscore, hyphen, dot. Must start with a letter or digit. The native app must still sanitise before writing to disk.Pattern ^[a-zA-Z0-9][a-zA-Z0-9_\-.]*$ · max length 255
string
MIME type hint (e.g. application/pdf).one of application/pdf, text/csv, image/jpeg, image/jpg, image/png

Error codes

When a method fails, the native app responds with a JSON-RPC 2.0 error object carrying one of these codes in error.code. error.message must never contain stack traces, filesystem paths, or other sensitive information.

Integration guide

1

Register the message handler

Register a WKScriptMessageHandler named PayleadBridge.
2

Receive the request

Receive JSON-RPC requests in userContentController(_:didReceive:).
3

Execute and respond

Execute the action and call back with callAsyncJavaScript using named argument binding.
  • Check message.frameInfo.isMainFrame and verify the host against your allowlist before processing any message. Cross-origin iframes inside the WebView otherwise share access to window.webkit.messageHandlers.PayleadBridge.
  • Use limitsNavigationsToAppBoundDomains = true and declare your domains under WKAppBoundDomains in Info.plist (iOS 14+).
  • Block navigations to hosts outside your allowlist in decidePolicyFor.

Security checklist for partners

Before shipping your integration, verify each item:
  • HTTPS only: every URL received from the bridge is validated to start with https:// before opening or downloading. javascript:, data:, file:, and intent:// schemes are explicitly rejected.
  • Filename sanitisation: the schema restricts filenames to a safe character set (^[a-zA-Z0-9][a-zA-Z0-9_\-.]*$); as defense in depth, the native app re-validates and strips null bytes / OS-reserved names before writing to disk.
  • Origin allowlist: the bridge is only reachable from pages whose host matches your trusted allowlist (*.paylead.fr, *.paylead.tech, *.paylead.eu). Navigations outside the allowlist are blocked.
  • User consent: file.download triggers a native prompt so the user can confirm or cancel.
  • App-bound domains (iOS 14+): limitsNavigationsToAppBoundDomains = true and WKAppBoundDomains are configured in Info.plist.

General recommendations

  • Back/forward gestures: disable allowsBackForwardNavigationGestures (iOS) and handle the back button explicitly (Android) to avoid accidental off-domain navigations.
  • Loading indicators: file.download can take up to 30 seconds; surface progress in your native UI.
  • Correlation logging: when logging bridge errors natively, include the request id so failures can be cross-referenced with the WebApp’s client-side logs.

What’s next

Page URLs

The WebApp URLs your app can open to land on a specific screen.

Troubleshooting

Diagnose a recurring auth screen, lost cookies, or hard-to-trace behaviour.