Frontend Integration Guide

Embeddable deposit, withdraw, onboarding, and KYC flows for ISV partners.

Add ProphetX-hosted deposit, withdrawal, onboarding, and KYC flows to your frontend using the SDK for your stack.

📘

ProphetX provides embeddable deposit, withdraw, onboarding, and KYC flows for ISV partners. Each SDK works like a drop-in that you wrap around your app and call from a button.

🎥

See it live: isv-embed-fe-mock-isv-host.vercel.app is a demo ISV host app running all four flows end-to-end against sandbox — a working reference before you write any code.

There are four SDKs — pick the one that matches your stack:

StackPackageInstall
React (web)@prophetx/sdk-reactnpm i @prophetx/sdk-react
Vanilla JS@prophetx/sdk-jsnpm i @prophetx/sdk-js
React Native@prophetx/sdk-react-nativenpm i @prophetx/sdk-react-native react-native-webview @react-native-async-storage/async-storage
Flutterprophetx_sdk (Dart)Add to pubspec.yaml (see Flutter)

All four expose the same set of flows, events, and configuration options — only the rendering primitive differs (iframe vs. WebView).


Table of Contents

  1. What You Get
  2. Before You Start
  3. Quick Start (React)
  4. Quick Start (Vanilla JS)
  5. Quick Start (React Native)
  6. Quick Start (Flutter)
  7. Available Flows
  8. Built-In Modules
  9. Environments
  10. Lifecycle & Cleanup
  11. Error Codes
  12. API Reference Cheat Sheet
  13. FAQ & Troubleshooting

1. What You Get

Four end-user flows, fully implemented and hosted by ProphetX:

FlowWhat the user does
DepositPicks a payment method (AeroPay, ZeroHash, or Wire Transfer — PayNearMe is API-supported but has no shipped embed flow yet, and shows a placeholder if granted), enters an amount, and funds their ProphetX wallet.
WithdrawEnters an amount and withdraws to their bank via AeroPay (ZeroHash and PayNearMe withdraw have no shipped embed flow yet).
1-Click SignupNew-user identity creation via Verified Inc's own hosted modal.
Document verificationRe-verification flow for existing users whose automated KYC came back FAILURE.

Each flow opens in a modal (web) or a full-screen sheet (mobile). You get callbacks on success, error, cancel, and KYC outcomes, plus a global event stream for analytics.

Out of the box you also get:

  • Built-in authentication with token storage and auto-refresh
  • Wallet balance API
  • Theming — match the embed to your brand at open time or dynamically
  • Geofence handling — surface region/VPN blocks to your UI
  • DevTools — toggle-on debug logger with automatic PII redaction
  • Three environments — production, staging, sandbox

2. Before You Start

Before you integrate the SDK:

  1. Create a ProphetX partner account — talk to ProphetX onboarding to get your sandbox/staging credentials.
  2. Provide a session JWT for each user — use either the built-in auth module (recommended) or your own backend that calls ProphetX's auth API.
  3. Allow-list your origins — coordinate with ProphetX before going live so your production domains can render the embed.
📘

The SDK never asks you to embed payment provider SDKs (Trustly, AeroPay, ZeroHash) directly — those all live inside the ProphetX-hosted embed.


3. Quick Start (React)

npm i @prophetx/sdk-react

Wrap your app once, then call hooks anywhere inside.

import { ProphetXProvider, useDeposit, useWithdraw } from '@prophetx/sdk-react';

function App() {
  return (
    <ProphetXProvider
      environment="production"
      token={sessionJwt}                     // get this from your backend, or use auth={...} (see below)
    >
      <WalletButtons />
    </ProphetXProvider>
  );
}

function WalletButtons() {
  const deposit  = useDeposit();
  const withdraw = useWithdraw();

  return (
    <>
      <button onClick={() => deposit.open({
        onSuccess: (txId, amount) => console.log('Deposited', txId, amount),
        onError:   (code, msg)    => console.error('Deposit failed', code, msg),
        onCancel:  () => console.log('User cancelled'),
      })}>
        Deposit
      </button>

      <button onClick={() => withdraw.open({
        onSuccess: (txId, amount) => console.log('Withdrew', txId, amount),
        onError:   (code, msg)    => console.error('Withdrawal failed', code, msg),
      })}>
        Withdraw
      </button>
    </>
  );
}

You now have a basic deposit and withdrawal button wired to ProphetX-hosted flows.


4. Quick Start (Vanilla JS)

npm i @prophetx/sdk-js
import { createProphetX } from '@prophetx/sdk-js';

const px = createProphetX({ environment: 'production' });

document.querySelector('#deposit-btn').addEventListener('click', () => {
  px.openDeposit({
    token: sessionJwt,
    onSuccess: (txId, amount) => console.log('Deposited', txId, amount),
    onError:   (code, msg)    => console.error(code, msg),
    onCancel:  () => console.log('User cancelled'),
  });
});

// Clean up when your page tears down
window.addEventListener('beforeunload', () => px.destroy());

createProphetX returns an SDKInstance with openDeposit / openWithdraw / openOnboarding (gated — see warning below) / openOneClickSignup / openKyc (or openIdUpload) / close / destroy / updateTheme / updateLocale / on / off / auth / wallet.


5. Quick Start (React Native)

npm i @prophetx/sdk-react-native react-native-webview @react-native-async-storage/async-storage
cd ios && pod install      # iOS only

Peer dependencies: react ^18, react-native >=0.70, react-native-webview >=13, @react-native-async-storage/async-storage >=1.19.

import { ProphetXProvider, useDeposit } from '@prophetx/sdk-react-native';

export default function App() {
  return (
    <ProphetXProvider environment="production" token={sessionJwt}>
      <Home />
    </ProphetXProvider>
  );
}

function Home() {
  const { open } = useDeposit();
  return <Button title="Deposit" onPress={() => open({
    onSuccess: (txId, amount) => console.log('Deposited', txId, amount),
    onError:   (code, msg)    => console.error('Deposit failed', code, msg),
  })} />;
}

The provider mounts a full-screen modal with header + WebView when you open a flow. You don't render the WebView yourself — but a low-level ProphetXWebView is exported if you need custom chrome.

📘

iOS/Android setup: make sure your app has Internet permission (Android) and that NSAppTransportSecurity is not blocking HTTPS (iOS).


6. Quick Start (Flutter)

Add to pubspec.yaml:

dependencies:
  prophetx_sdk:
    git:
      url: [email protected]:betprophet1/isv-embed-fe.git
      path: packages/sdk-flutter
      ref: flutter-sdk-v0.1.0   # use the latest published tag

(Once GA, it will be available as prophetx_sdk: ^x.y.z from pub.dev.)

import 'package:flutter/material.dart';
import 'package:prophetx_sdk/prophetx_sdk.dart';

void main() {
  runApp(
    ProphetXProvider(
      environment: EnvironmentName.production,
      token: sessionJwt,
      child: const MyApp(),
    ),
  );
}

class HomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final px = ProphetX.of(context);
    return ElevatedButton(
      onPressed: () => px.deposit.open(OpenDepositOptions(
        onSuccess: (id, amount) => debugPrint('deposit success $id'),
        onError: (code, message) => debugPrint('deposit failed $code: $message'),
      )),
      child: const Text('Deposit'),
    );
  }
}

Native deps the SDK pulls in: webview_flutter, flutter_secure_storage, http, uuid. Android cleartext is not required for production/staging since the API base URLs are HTTPS.


7. Available Flows

Every flow follows the same pattern:

flow.open({
  // Lifecycle callbacks
  onReady?,
  onSuccess?,
  onError?,
  onCancel?,

  // KYC / geofence callbacks (when applicable)
  onKycSuccess?, onKycFailed?, onKycPending?,
  onGeofenceBlocked?,

  // Per-invocation theme override
  theme?,

  // Manual session refresh (not needed if you use the auth module)
  onSessionExpired?,
});

Deposit

User picks method → enters amount → confirms → completes via provider.

// React
const { open } = useDeposit();
open({
  onSuccess: (txId, amount) => track('deposit_success', { txId, amount }),
  onError:   (code, msg)    => track('deposit_error', { code, msg }),
  onCancel:  ()             => track('deposit_cancel'),
});

Possible error codes: DEPOSIT_FAILED (generic fallback), PROVIDER_LOAD_FAILED, PROVIDER_UNAVAILABLE, DEPOSIT_NOT_COMPLETED, DEPOSIT_WALLET_WRITE_FAILED, plus ZeroHash-specific codes — ZEROHASH_LOAD_FAILED, ZEROHASH_PROVIDER_ERROR, ZEROHASH_DENIED, ZEROHASH_RESTRICTED, ZEROHASH_DETAILS_REQUIRED, ZEROHASH_NOT_APPROVED, ZEROHASH_KYC_PENDING, ZEROHASH_DEPOSIT_CONFLICT — see Error Codes. onGeofenceBlocked(stateCode, reason) is also wired on this flow, though in practice geo-eligibility is enforced when your backend mints the embed token, not per-request — see the geofence FAQ entry in FAQ & Troubleshooting.

Withdraw

const { open } = useWithdraw();
open({
  onSuccess: (txId, amount) => console.log('Withdrew', txId, amount),
  onError:   (code, msg) => {
    if (code === 'KYC_REQUIRED') {
      // This user already exists (they have an embed token) — re-verify them,
      // don't send them through signup.
      idUpload.open();
    }
  },
});

Possible error codes: WITHDRAWAL_FAILED (generic fallback). Withdraw may also surface a literal KYC_REQUIRED per the SDK's own source — its backend origin is unconfirmed (no backend code path we could find actually emits it, so treat it as a legacy/defensive client-side code rather than something you're likely to see in practice), see Error Codes.

1-Click Signup (new-user identity)

triangle-exclamation

useOnboarding/openOnboarding — previously documented here — is not available: the route is permanently gated off with an error screen (the underlying Verified Inc API integration was never approved for that integration type). Use useOneClickSignup for new users instead.

Use this the first time a brand-new user signs up — there's no ProphetX user yet, so there's no embed token either. Verified Inc's own hosted modal handles phone/OTP lookup and PII confirmation; your backend mints a sessionKey first and redeems the resulting identity afterward. KYC hasn't run yet at that point — it starts once your backend redeems the identity, and can still come back FAILURE. See Verified Modal for the full contract (sessionKey/environment, onOneClickSuccess/onOneClickDeclined/onOneClickFailed).

Document verification (existing-user re-verification)

For an existing user whose automated KYC came back FAILURE, use useKyc (historical alias) or useIdUpload (preferred) — a government-ID photo upload reviewed by IDComply, opened in a second browser tab. There's no phone/OTP step in this flow. See Verified Modal for the full walkthrough.

const { open } = useOneClickSignup();
const { sessionKey, environment } = await myBackend.mintOneClickSession();
open({
  sessionKey,
  environment,
  onOneClickSuccess: (identityUuid) => myBackend.redeem(identityUuid),
  onOneClickDeclined: () => showManualSignupForm(),
  onOneClickFailed: (reason, retryable) => console.warn('1-Click failed', reason, retryable),
});
const { open: idUpload } = useIdUpload(); // or useKyc — same flow
idUpload.open({
  onKycSuccess: () => handleSuccess(),
  onKycFailed: (reason, retryable) => console.warn('Verification failed', reason, retryable),
  onKycPending: () => toast('Identity check pending review'),
});

8. Built-In Modules

Authentication

You have two options for token management:

Option A — let the SDK do it (recommended). Pass an auth config; the SDK handles login, storage, JWT decoding, and auto-refresh.

// React
<ProphetXProvider
  environment="staging"
  auth={{
    apiBaseUrl: 'https://isv-api.staging.prophetx.dev',
    refreshBufferSeconds: 30,   // auto-refresh 30s before expiry
  }}
>
  <App />
</ProphetXProvider>

function Login() {
  const { login, logout, isAuthenticated, state } = useAuth();

  if (!isAuthenticated) {
    return (
      <button onClick={() => login({ email: '[email protected]', password: 'pw' })}>
        Sign in
      </button>
    );
  }
  return <button onClick={logout}>Sign out (expires {state.expiresAt})</button>;
}
// Vanilla JS
const px = createProphetX({
  environment: 'staging',
  auth: { apiBaseUrl: 'https://isv-api.staging.prophetx.dev' },
});

await px.auth.login({ email, password });
px.auth.onStateChange((state) => console.log('Auth →', state.status));
px.auth.logout();

Auth states: unauthenticated → authenticating → authenticated → expired → (auto-refresh) → authenticated. Login errors land in error with codes INVALID_CREDENTIALS, NETWORK_ERROR, SERVER_ERROR, TIMEOUT.

Device ID is auto-generated (crypto.randomUUID()) and persisted (localStorage on web, AsyncStorage on RN, flutter_secure_storage on Flutter). You can override with login({ email, password, deviceId }).

Option B — bring your own token. Pass token as a prop / option, and (optionally) an onSessionExpired handler that returns a fresh token. See Session refresh below.

Wallet / Balance

Once authenticated, you can fetch the user's balance.

// React
const { balance, loading, error, refetch } = useWallet();
return loading ? <Spinner /> : <p>${balance?.totalBalance}</p>;
// Vanilla JS
const { totalBalance, currency } = await px.wallet.getBalance();

Response: { totalBalance: number, currency: string } (default currency 'cash').

Theming

Match the embed to your brand. Two ways to set a theme:

// 1. On the provider (default for all flows)
<ProphetXProvider
  environment="production"
  token={jwt}
  theme={{
    mode: 'dark',
    primaryColor: '#4F46E5',
    backgroundColor: '#1a1a2e',
    colorOverrides:  { 'text-primary': '#fff' },
    radiusOverrides: { sm: '4px', md: '8px', lg: '16px' },
  }}
>...
// 2. Per-invocation override
px.openDeposit({ theme: { mode: 'light' } });

Updating dynamically:

// Vanilla JS
px.updateTheme({ mode: 'light' });
// React — just change the prop, the provider re-sends automatically
const [theme, setTheme] = useState({ mode: 'light' });
<ProphetXProvider theme={theme} ...>...</ProphetXProvider>

Full ThemePayload shape:

type ThemePayload = {
  mode?: 'light' | 'dark';
  primaryColor?: string;
  backgroundColor?: string;
  colorOverrides?: Record<string, string>;
  spacingOverrides?: Record<string, string>;
  radiusOverrides?: Record<string, string>;
  fontSizeOverrides?: Record<string, string>;
};

Events

Subscribe once and react to anything the embed emits — perfect for analytics or error reporting.

// React
import { useEvents } from '@prophetx/sdk-react';

function Analytics() {
  useEvents({
    onReady:          ()     => analytics.track('embed_ready'),
    onSuccess:        (d)    => analytics.track('flow_success', d),
    onError:          (d)    => errorReporter.capture('flow_error', d),
    onCancel:         ()     => analytics.track('flow_cancel'),
    onGeofenceBlocked:(d)    => analytics.track('geofence_block', d),
    onKycSuccess:     (d)    => analytics.track('kyc_success', d),
    onKycFailed:      (d)    => analytics.track('kyc_failed', d),
    onKycPending:     ()     => analytics.track('kyc_pending'),
  });
  return null;
}
// Vanilla JS
const unsub = px.on('success', (d) => analytics.track('deposit_success', d));
px.on('error',   (d) => errorReporter.capture('sdk_error', d));
px.on('open',    (d) => analytics.track('flow_open', { flow: d.flow }));
px.on('close',   (d) => analytics.track('flow_close', { flow: d.flow }));
unsub();

All events:

EventPayload
ready—
success{ transactionId, amount? }
error{ code, message }
cancel—
kycSuccess{ identityUuid }
kycFailed{ reason }
kycPending—
geofenceBlocked{ stateCode, reason }
resize{ height }
sessionExpired—
sessionRefreshed{ token }
open / close{ flow: 'deposit' | 'withdraw' | ... }

Geofence

US betting regulation varies by state. If the user is in a blocked region (or behind a VPN), you'll get a callback so you can swap in your own messaging.

deposit.open({
  onGeofenceBlocked: (stateCode, reason) => {
    // reason: 'region' | 'vpn' | 'error'
    if (reason === 'vpn') showVpnWarning();
    else showStateUnavailable(stateCode);
  },
});

You can also subscribe globally via on('geofenceBlocked', ...) / useEvents({ onGeofenceBlocked }).

Session refresh

Using the auth module: session expiry is handled automatically — when the embed reports PROPHETX_SESSION_EXPIRED, the SDK re-authenticates using stored credentials and the flow resumes. You don't need to do anything.

Without the auth module: provide an onSessionExpired handler that returns a fresh token (or null to abort):

<ProphetXProvider
  environment="production"
  token={jwt}
  onSessionExpired={async () => {
    const res  = await fetch('/api/auth/refresh');
    const data = await res.json();
    return data.token;  // return null to abort
  }}
>...
px.openDeposit({
  token: jwt,
  onSessionExpired: async () => (await refresh()).token,
});

DevTools

Toggle-on debug logging with PII redaction. Off by default.

<ProphetXProvider
  environment="staging"
  devtools={{
    enabled: true,
    logLevel: 'debug',           // 'none' | 'error' | 'warn' | 'info' | 'debug'
    redactPII: true,             // default true; masks tokens, emails, passwords
    onEvent: (entry) => myLogger.log(entry.category, entry.message, entry.data),
  }}
>...

Categories: auth (purple), message (blue), api (green), lifecycle (amber), event (pink). With redactPII on, tokens / passwords / emails appear as [REDACTED] in logs.


9. Environments

EnvironmentEmbed URLAPI Base URL
productionhttps://embed.prophetx.cohttps://isv-api.prophetx.co
staginghttps://embed-staging.prophetx.cohttps://isv-api.staging.prophetx.dev
sandboxhttps://embed-sandbox.prophetx.cohttps://isv-api.sandbox.prophetx.dev
// Preset (recommended)
createProphetX({ environment: 'staging' });
<ProphetXProvider environment="staging" .../>

// Custom (point at your own deploys)
createProphetX({
  environment: { embedUrl: 'https://embed.example.com', apiBaseUrl: 'https://api.example.com' },
});
📘

Start in sandbox, promote through staging, then go live in production. Your allow-listed origins must be configured by ProphetX before production traffic will work.


10. Lifecycle & Cleanup

React / React Native / Flutter: cleanup is automatic when the provider unmounts. Nothing extra to do.

Vanilla JS: call destroy() when you're done with the SDK instance (typically on page unload). This tears down the iframe, removes listeners, and stops auth timers. After destroy() the instance is unusable.

px.close();    // close the active flow modal
px.destroy();  // tear the whole SDK down

11. Error Codes

CodeWhereMeaning
DEPOSIT_FAILEDonError in depositGeneric deposit failure (fallback — check for a provider-specific code first)
WITHDRAWAL_FAILEDonError in withdrawGeneric withdrawal failure (fallback)
PERMISSION_DENIEDonError in deposit/withdrawA required gate is unmet, or a provider permission is denied — check pending_gates / denyReason. Covers what used to be documented as TERMS_NOT_SIGNED-style codes; there's no Trustly-specific code (not wired to any live endpoint).
KYC_REQUIREDonError in withdraw only⚠️ Real in the frontend SDK's source, but unconfirmed against isv-backend — see Error Codes.
onGeofenceBlockedDedicated callback, not onErrorReal, on every flow except 1-Click Signup — but enforced at token issuance, so it shouldn't fire with a validly-issued token.
SESSION_EXPIREDonErrorToken expired and no refresher provided
SESSION_INVALIDonErrorToken rejected by server
ORIGIN_UNAUTHORIZEDonErrorEmbedding origin isn't allow-listed
INVALID_CREDENTIALSauth.loginWrong email/password
NETWORK_ERRORauth.loginNetwork unreachable
SERVER_ERRORauth.login5xx from auth endpoint
TIMEOUTauth.loginRequest timed out

See Error Codes for the full reference, including the real provider-specific codes (aeropay_rejected, pnm_rejected, amount_mismatch, etc.) that a DEPOSIT_FAILED/WITHDRAWAL_FAILED fallback may be masking.


12. API Reference Cheat Sheet

React (@prophetx/sdk-react)

<ProphetXProvider
  environment? : 'production' | 'staging' | 'sandbox' | EnvironmentConfig
  token?       : string                                // omit when using `auth`
  theme?       : ThemePayload
  auth?        : { apiBaseUrl: string, refreshBufferSeconds?: number }
  devtools?    : DevToolsConfig
  onSessionExpired? : () => Promise<string | null>
>

// Flow hooks
useDeposit():        { open(opts?), close(), isOpen }
useWithdraw():       { open(opts?), close(), isOpen }
useOneClickSignup(): { open(opts), close(), isOpen }   // opts required — needs sessionKey
useKyc() / useIdUpload(): { open(opts?), close(), isOpen }  // same flow, two names

// Module hooks
useAuth():   { state, login, logout, token, isAuthenticated }
useWallet(): { balance, loading, error, refetch }
useEvents(handlers): void

Vanilla JS (@prophetx/sdk-js)

createProphetX({ environment?, auth?, devtools? }): SDKInstance

type SDKInstance = {
  openDeposit(opts):        void;
  openWithdraw(opts):       void;
  openOnboarding(opts):     void;  // opens the gated error screen — see the 1-Click Signup warning above
  openOneClickSignup(opts): void;  // opts required — needs sessionKey/environment
  openKyc(opts):            void;  // historical alias
  openIdUpload(opts):       void;  // same flow as openKyc, preferred name
  close():       void;
  destroy():     void;
  updateTheme(theme):  void;
  updateLocale(locale): void;
  on(event, handler):  () => void;
  off(event, handler): void;
  auth:   AuthManager  | null;   // null until `auth` configured
  wallet: WalletClient | null;
};

Options shared by all flows

type OpenOptions = {
  token?: string;                                // not needed with auth module
  theme?: ThemePayload;
  onReady?: () => void;
  onSuccess?: (transactionId: string, amount?: number) => void;
  onError?:   (code: string, message: string) => void;
  onCancel?:  () => void;
  onGeofenceBlocked?: (stateCode: string, reason: string) => void;
  onSessionExpired?:  () => Promise<string | null>;
};

type KycOpenOptions = OpenOptions & {
  onKycSuccess?: (identityUuid: string) => void;
  onKycFailed?:  (reason: string) => void;
  onKycPending?: () => void;
};

React Native (@prophetx/sdk-react-native)

Same API as @prophetx/sdk-react. Provider renders a full-screen native Modal with WebView. ProphetXWebView and ProphetXModal are exported for advanced custom chrome.

Flutter (prophetx_sdk)

ProphetXProvider(
  environment: EnvironmentName.production,         // or EnvironmentConfig(...)
  token: jwt,
  auth: AuthConfig(apiBaseUrl: '...'),
  theme: const EmbedTheme(mode: 'dark'),
  locale: 'en',
  child: const MyApp(),
);

final px = ProphetX.of(context);
px.deposit.open(OpenDepositOptions(onSuccess: ...));
px.withdraw.open(...);
px.onboarding.open(...);
px.kyc.open(...);

px.auth?.login(LoginCredentials(email: ..., password: ...));
px.wallet?.refetch();
px.events.stream.listen((event) { ... });   // ReadyEvent | SuccessEvent | ...

13. FAQ & Troubleshooting

Q: Do I need to embed Trustly / AeroPay / ZeroHash SDKs?
No. The ProphetX embed loads them itself.

Q: The embed isn't rendering — I get a blank modal.
Most common cause: your origin isn't on ProphetX's allow-list. Contact your ProphetX integration contact and confirm window.location.origin. In dev, also confirm you're pointing at the right environment.

Q: I keep getting SESSION_EXPIRED.
Either turn on the auth module (auth: { apiBaseUrl }) so the SDK refreshes for you, or implement onSessionExpired to return a fresh token from your backend.

Q: How do I detect when the user closed the modal vs. completed?
Use onCancel (user dismissed) vs. onSuccess (flow completed). They're mutually exclusive per open() call.

Q: Can I show my own loading state before the embed shows?
Yes — keep your own spinner up until onReady fires.

Q: How do I customize the modal chrome on mobile?
For RN, the default ProphetXProvider renders ProphetXModal for you. To swap in your own header / presentation, use the lower-level ProphetXWebView directly. Flutter has the same pattern with ProphetXWebView.

Q: What if my user is on a VPN?
You'll get onGeofenceBlocked(stateCode, 'vpn'). Surface an appropriate message — don't auto-retry.

Q: Where do I send sensitive analytics — through useEvents or my own backend?
Either, but useEvents already passes you only the event payloads (no raw tokens or PII). The built-in DevTools also redact PII before logging.

Q: How do I switch the theme to match a dark/light toggle in my app?
Pass a state variable to theme on the provider (React) or call px.updateTheme(...) (Vanilla JS). The embed updates live.

Q: Can I run two flows at once?
No — opening a second flow closes the first one. This is intentional to keep the user's attention on one transaction at a time.


Support resources

  • Live demo — isv-embed-fe-mock-isv-host.vercel.app, a mock ISV host app with all flows wired to sandbox
  • Status page — https://status.prophetx.co (ask your contact for the right URL for your tenant)
  • Partner support — reach out through your ProphetX integration channel
  • SDK source — available on request for security review


Did this page help you?