API Reference

Complete reference for ProphetXProvider props, all hooks, events, and exported types across React, React Native, and JavaScript SDKs.

The Flutter SDK (prophetx_sdk) mirrors the React Native surface — same provider, same options, same event payloads. Differences are called out per-section: hooks become ChangeNotifier flow controllers on ProphetX.of(context), callbacks fire on Dart Function types, and the event bus is a Dart Stream.

triangle-exclamation

useOnboarding/openOnboarding is not available. It used to combine terms + KYC + a first deposit, but the route is permanently gated off with an error screen today (the underlying Verified Inc API integration was never approved for that integration type). Use 1-Click Signup (useOneClickSignup) for new users instead, and Document verification (useKyc/useIdUpload) for re-verifying an existing user — see those sections below. onGeofenceBlocked / PROPHETX_GEOFENCE_BLOCKED is real and defined on every flow except 1-Click Signup, but geo-eligibility for the embed is enforced at token issuance rather than per-request — don't expect it to fire in normal operation with a validly-issued embed token.

ProphetXProvider

Props

Environment

Pass a preset name or a custom config object:

NameEmbed URLAPI Base URL
"production"https://embed.prophetx.cohttps://isv-api.prophetx.co
"staging"https://isv-embed-fe-embed.vercel.apphttps://isv-api.staging.prophetx.dev
"sandbox"https://isv-embed-fe-embed-sandbox.vercel.apphttps://isv-api.sandbox.prophetx.dev

Custom config:

type EnvironmentConfig = {
  embedUrl: string;
  apiBaseUrl: string;
};

AuthConfig

Optional. When provided, the SDK manages authentication internally — you don't need to pass token yourself.

FieldTypeRequiredDescription
apiBaseUrlstringYesAPI base URL for authentication requests.
refreshBufferSecondsnumberNoAuto-refresh the token this many seconds before expiry. Default: 30.
onAuthStateChanged(state: AuthState) => voidNoCalled whenever auth state changes.
getCredentials() => LoginCredentials | Promise<LoginCredentials>NoReturns credentials on demand for auto-refresh. Avoids storing plaintext credentials in memory.
storageStorageAdapterNoCustom storage adapter. Defaults to browser localStorage.
httpHttpAdapterNoCustom HTTP adapter. Defaults to fetch.
randomRandomAdapterNoCustom random number adapter.

DevToolsConfig

FieldTypeRequiredDescription
enabledbooleanNoEnable or disable devtools.
logLevel"none" | "error" | "warn" | "info" | "debug"NoLog level threshold.
redactPIIbooleanNoWhen true, masks tokens, passwords, and emails in log output.
onEvent(entry: DevToolsLogEntry) => voidNoCustom log sink — receives every log entry.

Deposit flow

Opens the deposit flow. The SDK renders a modal that handles the full deposit UI. React/React Native expose this via the useDeposit hook; the Flutter SDK exposes a DepositFlow controller on ProphetX.of(context).deposit.

Controller surface

SurfaceFieldTypeDescription
React / React Nativeopen(options?: OpenDepositOptions) => voidOpens the deposit modal.
React / React Nativeclose() => voidCloses the deposit modal programmatically.
React / React NativeisOpenbooleanWhether the deposit modal is currently open.
Flutteropen([OpenDepositOptions?]) => voidOpens the deposit modal.
Flutterclose() => voidCloses the deposit modal programmatically.
FlutterisOpenboolWhether the deposit modal is currently open. Notifies via ChangeNotifier.

OpenDepositOptions

OptionTypeDescription
onSuccess(transactionId: string, amount?: number) => voidFires when the deposit completes. Store transactionId on your backend to track the deposit.
onError(code: string, message: string) => voidFires on any error. See Error Codes.
onCancel() => voidFires when the user closes the modal without completing the deposit.
onReady() => voidFires when the embed iframe has loaded and is ready to interact.
onGeofenceBlocked(stateCode: string, reason: string) => voidFires when the user's location is outside a permitted jurisdiction.

The JavaScript SDK's OpenOptions also accepts token, theme, and onSessionExpired — these are passed per-call instead of through a provider.

Withdraw flow

Opens the withdrawal flow. Follows the same pattern as the deposit flow above. React/React Native expose useWithdraw; Flutter exposes ProphetX.of(context).withdraw.

Controller surface

SurfaceFieldTypeDescription
React / React Nativeopen(options?: OpenWithdrawOptions) => voidOpens the withdraw modal.
React / React Nativeclose() => voidCloses the withdraw modal programmatically.
React / React NativeisOpenbooleanWhether the withdraw modal is currently open.
Flutteropen([OpenWithdrawOptions?]) => voidOpens the withdraw modal.
Flutterclose() => voidCloses the withdraw modal programmatically.
FlutterisOpenboolWhether the withdraw modal is currently open. Notifies via ChangeNotifier.

OpenWithdrawOptions

OptionTypeDescription
onSuccess(transactionId: string, amount?: number) => voidFires when the withdrawal completes.
onError(code: string, message: string) => voidFires on any error. See Error Codes.
onCancel() => voidFires when the user closes the modal without completing the withdrawal.
onReady() => voidFires when the embed iframe has loaded and is ready to interact.
onGeofenceBlocked(stateCode: string, reason: string) => voidFires when the user's location is outside a permitted jurisdiction.

1-Click Signup flow

triangle-exclamation

Replaces the old "Onboarding flow." useOnboarding/openOnboarding opened a combined terms + KYC + first-deposit experience that is not available in the current embed — the route is permanently gated off with an error screen, because the underlying Verified Inc API integration was never approved for that integration type. 1-Click Signup, documented below, is the real, live path for creating a new user from a phone number. It has a different contract: no token (it runs before a user exists), a backend-minted sessionKey instead, and onOneClick* callbacks rather than onKyc*. If you need terms acceptance too, open the Terms flow separately after redeeming the identity.

Creates a ProphetX user from a phone number in about ten seconds, with no signup form of your own. The user confirms their phone by one-time code inside Verified Inc's own hosted modal, reviews the identity Verified already holds for them, and shares it. Your backend redeems that identity and the user exists — KYC has not run yet at that point; it starts once your backend redeems the identity. React/React Native expose useOneClickSignup; Flutter exposes ProphetX.of(context).oneClickSignup.

This is the one flow with no embed token at all — it carries a single-use sessionKey (minted by your backend via POST /private/v1/one-click/sessions) instead.

Controller surface

SurfaceFieldTypeDescription
React / React Nativeopen(options: OpenOneClickSignupOptions) => voidOpens the modal. Unlike other flows, options are required — there's no opening this one without a sessionKey.
React / React Nativeclose() => voidCloses the modal programmatically.
React / React NativeisOpenbooleanWhether the modal is currently open.
Flutteropen(OpenOneClickSignupOptions) => voidOpens the modal. Options are required here too.
Flutterclose() => voidCloses the modal programmatically.
FlutterisOpenboolWhether the modal is currently open. Notifies via ChangeNotifier.

OpenOneClickSignupOptions

OptionTypeDescription
sessionKeystring (required)Single-use key from POST /private/v1/one-click/sessions. Consumed by one modal open — a spent or lapsed key must be re-minted.
environment'sandbox' | 'production' (required)Must match the environment the key was minted for. Passed straight to Verified's own SDK.
onOneClickSuccess(identityUuid: string) => voidAlways present — unlike document verification's KYC success, 1-Click always yields an identity.
onOneClickDeclined() => voidThe user chose not to share. Not an error — fall back to manual signup.
onOneClickFailed(reason: string, retryable?: boolean) => voidTerminal. retryable is true only for a spent/lapsed session key — everything else (no credentials found, risk score, exhausted attempts) is not recoverable by reopening.
onCancel() => voidFires when the user closes the modal.
onError(code: string, message: string) => voidFires on any error. See Error Codes.
onReady() => voidFires when the embed iframe has loaded.

There is no token or redirectUrl on this flow. onGeofenceBlocked is defined and wired identically to every other flow, but it will never actually fire here — 1-Click runs before a user exists, so its tokenless session is treated as always-allowed by the geo gate rather than being evaluated against it.

Terms flow

triangle-exclamation

There is no useTerms/openTerms SDK method. A previous version of this page presented terms acceptance as a first-class hook alongside deposit/withdraw/KYC. It isn't — the SDK's flow-route union covers deposit, withdraw, 1-Click Signup, and document verification only. Terms acceptance is a standalone route (/tandc) you host yourself in a raw iframe, driving the low-level postMessage handshake directly (see postMessage Protocol). It genuinely is gated on deposit and withdraw, though — every deposit/withdraw permission requires the terms gate, so a user who has never accepted anything gets PERMISSION_DENIED with terms in pending_gates on those calls.

Point an iframe at {embedBaseUrl}/tandc and run the same session handshake every flow uses: wait for PROPHETX_EMBED_LOADED, then post PROPHETX_SESSION with your token (and optionally PROPHETX_THEME).

// React — no useTerms hook; a plain iframe + postMessage listener
function AcceptTermsFrame({ token, onAccepted, onCancel }) {
  const iframeRef = useRef(null);

  useEffect(() => {
    function handleMessage(event) {
      if (event.origin !== embedOrigin) return;
      const { type, payload } = event.data;
      switch (type) {
        case "PROPHETX_EMBED_LOADED":
          iframeRef.current.contentWindow.postMessage(
            { type: "PROPHETX_SESSION", payload: { token } },
            embedOrigin
          );
          break;
        case "PROPHETX_SUCCESS":
          // payload is always { transactionId: "tandc", amount: 0 } — not a
          // real transaction reference, don't reconcile it as one.
          onAccepted();
          break;
        case "PROPHETX_CANCEL":
          onCancel();
          break;
        // This route never emits PROPHETX_ERROR — fetch/accept failures
        // render their own in-embed error screen with Try Again instead.
      }
    }
    window.addEventListener("message", handleMessage);
    return () => window.removeEventListener("message", handleMessage);
  }, [token]);

  return <iframe ref={iframeRef} src={`${embedBaseUrl}/tandc`} />;
}

Messages this route sends

MessageWhenPayload
PROPHETX_READYOnce the terms fetch resolves (or fails) — not just once the session validates—
PROPHETX_SUCCESSAcceptance POST returned 200{ transactionId: "tandc", amount: 0 }
PROPHETX_CANCELUser closes out. In the shipped screen the only route to this is Close on the success page — the terms screen itself has no back/cancel control—
PROPHETX_GEOFENCE_BLOCKEDLocation check fails{ stateCode, reason }
PROPHETX_RESIZEContent height changes (document list length drives this){ height }

This route never emits PROPHETX_ERROR — a terms-fetch failure and an accept failure both render an error page inside the embed with Try Again, so don't wait on an error message to know something went wrong.

What users see

  1. Document list. The documents come from GET /embed/v1/terms verbatim, with document types PRIVACY_POLICY, TERMS_OF_USE, MARKET_PARTICIPANT_AGREEMENT, RISK_DISCLOSURE_STATEMENT, RULEBOOK, each with a checkbox and a link to the full document. An "Accept all" checkbox toggles all documents at once. Continue stays disabled until every document is checked — there's no partial acceptance.
  2. Continue. Submits acceptance in a single request. The screen goes back to the same loading state as the initial fetch — a submit and a fetch look identical.
  3. Terminal state. Success shows a result page and sends PROPHETX_SUCCESS; failure shows an in-embed error page with Try Again (which restarts from the terms fetch, wiping any checked boxes).

Don't log or reconcile transactionId as a payment reference — it's the literal string "tandc", and amount: 0 doesn't mean a zero-value transaction; no money moves in this flow at all.

Document verification flow

triangle-exclamation

This is not a phone/OTP flow. A previous version of this page described useKyc as opening a phone-entry → SMS-OTP → PII-confirmation experience. That's Verified Inc's UI, and it's what 1-Click Signup uses (see above) — useKyc never opened it. useKyc opens a document-photo-upload flow reviewed by IDComply, described below.

For a user who already exists and whose automated KYC check came back FAILURE, this opens a government-ID photo upload reviewed by IDComply. React/React Native expose useKyc (a historical alias, kept for backward compatibility) and useIdUpload (the current preferred name) — both open the exact same flow. Flutter exposes ProphetX.of(context).idUpload.

This flow is narrow by design: it only reaches the document step for a user whose automated check actually came back FAILURE. Anyone already verified, still under review, or out of attempts sees the matching terminal screen within a second or two instead — that's expected behavior, not a bug. Gate any "Verify ID" entry point on the user's KYC status rather than showing it unconditionally.

Controller surface

SurfaceFieldTypeDescription
React / React Nativeopen(options?: OpenIdUploadOptions) => voidOpens the modal.
React / React Nativeclose() => voidCloses the modal programmatically.
React / React NativeisOpenbooleanWhether the modal is currently open.
Flutteropen([OpenIdUploadOptions?]) => voidOpens the modal.
Flutterclose() => voidCloses the modal programmatically.
FlutterisOpenboolWhether the modal is currently open. Notifies via ChangeNotifier.

OpenIdUploadOptions vs. OpenKycOptions

These two option types are identical except for exactly one field, redirectUrl — present on OpenIdUploadOptions, absent on OpenKycOptions. That's the one functional reason to prefer useIdUpload over the legacy useKyc alias: on native, a user who finishes in the device browser without a redirectUrl lands on the vendor's own web page instead of back in your app. On web there's no functional difference — migrating is housekeeping, not a fix.

OptionTypeDescription
redirectUrlstring — useIdUpload only, not on useKycAbsolute URL IDComply returns the user to when they finish. Defaults to an in-embed "you can close this" page. Native apps must set this to a deep link (e.g. myapp://kyc/return) — otherwise the OS browser can't hand control back to your app. This is effectively required for native, which is why native integrations should call useIdUpload, not useKyc.
onSuccess(transactionId: string, amount?: number) => voidNot emitted by this flow (no transaction) — present only for parity with the shared callbacks union.
onKycSuccess(identityUuid?: string) => voidFires when the document is verified. No identityUuid — the IDPV API returns none. You already have the user's UUID from POST /users.
onKycFailed(reason: string, retryable?: boolean) => voidFires when rejected. retryable is false for compliance outcomes and exhausted attempts — branch on it, not reason, which is for logging only.
onKycPending() => voidFires when the document was submitted but review hasn't resolved yet.
onError(code: string, message: string) => voidFires on any error. See Error Codes.
onCancel() => voidFires when the user closes the modal.
onReady() => voidFires when the embed iframe has loaded and is ready to interact.
onGeofenceBlocked(stateCode: string, reason: string) => voidSee the geofence note at the top of this page.

What users see

Once you call open():

  1. The embed reads the user's KYC status first. If they're not eligible (already verified, still under review, compliance-failed, or attempts exhausted), it stops here and shows the matching terminal screen — no attempt is consumed. All four ineligible cases answer the same 409 kyc_not_retryable from the API; the embed disambiguates by checking status first, so you just receive the resolved outcome.
  2. If eligible, it mints an IDComply session and opens the hosted form in a second browser tab — IDComply sets X-Frame-Options/frame-ancestors, so it cannot be shown in an iframe. There is no in-modal fallback.
  3. The modal shows a "Finish Verifying Your Identity" waiting screen and polls while the user is in the other tab. Document capture takes minutes, so this wait is deliberately generous.
  4. When the session finishes, the verdict resolves and the modal lands on a terminal screen, then fires the corresponding callback. Unlike 1-Click Signup, there's no further async step after this — by the time your callback fires, the decision is final.

Wallet

Fetches and returns the user's current wallet balance. Requires ProphetXProvider with an environment configured. React/React Native expose useWallet; Flutter exposes ProphetX.of(context).wallet (a ChangeNotifier).

Return value (React / React Native)

FieldTypeDescription
balanceWalletBalance | nullCurrent balance, or null if not yet fetched.
loadingbooleanWhether a fetch is in progress.
errorProphetXApiError | nullLast error, or null.
refetch() => Promise<void>Call to re-fetch the balance. Not automatic — call it on mount and after deposits/withdrawals.

WalletBalance

FieldTypeDescription
totalBalancenumberThe user's available balance.
currencystringCurrency code (e.g. "USD").

JavaScript SDK

The vanilla SDK exposes a wallet property on the SDK instance:

MethodTypeDescription
sdk.wallet.getBalance()() => Promise<WalletBalance>Returns the user's balance. sdk.wallet is null if auth was not configured.

Flutter

ProphetX.of(context).wallet is a WalletClient that extends ChangeNotifier. Pair it with ListenableBuilder to react to balance / loading / error transitions.

FieldTypeDescription
balanceWalletBalance?Current balance, or null if not yet fetched.
loadingboolWhether a fetch is in progress.
errorObject?Last error, or null.
refetchFuture<WalletBalance?> Function()Re-fetches the balance. Call on mount and after deposits/withdrawals.

Auth

Manages user authentication. Requires ProphetXProvider with the auth prop configured. React/React Native expose useAuth; Flutter exposes ProphetX.of(context).auth (an AuthManager that extends ChangeNotifier).

Return value (React / React Native)

FieldTypeDescription
stateAuthStateCurrent authentication state. See AuthState.
login(credentials: LoginCredentials) => Promise<LoginResult>Authenticate with email and password.
logout() => voidClear the token and reset state.
tokenstring | nullCurrent JWT, or null if unauthenticated.
isAuthenticatedbooleanConvenience boolean — true when state.status === "authenticated".

AuthState

StatusFieldsDescription
"unauthenticated"—No active session.
"authenticating"—Login in progress.
"authenticated"token: string, expiresAt: numberActive session with a valid JWT.
"expired"lastToken: stringSession expired. Contains the last token for reference.
"error"error: ProphetXAuthErrorAuthentication failed.

LoginCredentials

FieldTypeRequiredDescription
emailstringYesUser's email address.
passwordstringYesUser's password.
deviceIdstringNoOptional device identifier.

LoginResult

FieldTypeDescription
tokenstringSigned JWT.
expiresAtnumberUnix timestamp (ms) when the token expires.

ProphetXAuthError

FieldTypeDescription
type"AUTH_ERROR"Always "AUTH_ERROR".
code"INVALID_CREDENTIALS" | "NETWORK_ERROR" | "SERVER_ERROR" | "TIMEOUT"Error category.
messagestringHuman-readable error message.
statusnumber | undefinedHTTP status code, if applicable.

JavaScript SDK

The vanilla SDK exposes an auth property on the SDK instance:

MethodTypeDescription
sdk.auth.login(credentials)(LoginCredentials) => Promise<LoginResult>Authenticate.
sdk.auth.logout()() => voidClear the session.
sdk.auth.getToken()() => string | nullGet the current JWT.
sdk.auth.getState()() => AuthStateGet the current auth state.
sdk.auth.onStateChange(cb)(cb: (state: AuthState) => void) => () => voidSubscribe to state changes. Returns an unsubscribe function.
sdk.auth.handleSessionExpired()() => Promise<string | null>Re-authenticates using the getCredentials callback from AuthConfig.
sdk.auth.destroy()() => voidTear down the auth manager and clear timers.

sdk.auth is null if AuthConfig was not passed to createProphetX.

Flutter

ProphetX.of(context).auth is an AuthManager that extends ChangeNotifier. state is a sealed hierarchy (Unauthenticated, Authenticating, Authenticated, Expired, AuthError) — match on it with Dart 3 pattern syntax.

MemberTypeDescription
loginFuture<LoginResult> Function(LoginCredentials)Authenticate with email + password. Throws ProphetXAuthError.
logoutvoid Function()Clear the session.
tokenString?Current JWT, or null when not in the Authenticated state.
isAuthenticatedbooltrue when state is Authenticated.
stateAuthStateSealed hierarchy. See enum below.
handleSessionExpiredFuture<String?> Function()Re-authenticates using the getCredentials callback from AuthConfig. Used internally as the default onSessionExpired.

AuthState subtypes: Unauthenticated, Authenticating, Authenticated(token, expiresAt), Expired(lastToken), AuthError(error). expiresAt on Flutter is Unix seconds (the JS SDKs use milliseconds).

ProphetXAuthError.code is the Dart enum AuthErrorCode { invalidCredentials, networkError, serverError, timeout }.

Events

Subscribes to all SDK events globally. Useful for analytics, logging, or cross-cutting concerns that apply regardless of which flow is open. React/React Native expose useEvents; Flutter exposes a broadcast Stream on ProphetX.of(context).events.

ProphetXEventHandlers (React / React Native)

All fields are optional. Pass only the events you care about.

HandlerPayloadDescription
onReady—Embed iframe loaded and ready.
onSuccess{ transactionId: string, amount?: number }Transaction completed.
onError{ code: string, message: string }An error occurred.
onCancel—User closed the modal.
onKycSuccess{ identityUuid: string }Identity verification passed.
onKycFailed{ reason: string }Identity verification failed.
onKycPending—Identity verification submitted, awaiting result.
onGeofenceBlocked{ stateCode: string, reason: string }User's location is not permitted.

Note: useEvents receives payload data as objects (e.g. { transactionId, amount }), while flow hook callbacks receive them as positional arguments (e.g. (transactionId, amount)).

Flutter event types

The Flutter SDK uses a sealed ProphetXEvent hierarchy. Subscribe to a single subtype with events.on<T>(handler) or to the full union with events.stream.listen(...).

Event subtypeFieldsDescription
ReadyEvent—Embed iframe loaded and ready.
SuccessEventtransactionId: String, amount: num?Transaction completed.
ErrorEventcode: String, message: StringAn error occurred.
CancelEvent—User dismissed the modal.
KycSuccessEventidentityUuid: StringIdentity verification passed.
KycFailedEventreason: StringIdentity verification failed.
KycPendingEvent—Identity verification submitted, awaiting result.
GeofenceBlockedEventstateCode: String, reason: StringUser's location is not permitted.
SessionExpiredEvent—The session token has expired.
SessionRefreshedEventtoken: StringA new session token was obtained after expiry.
FlowOpenEventflow: StringA flow modal was opened. flow is "deposit", "withdraw", "onboarding", or "kyc".
FlowCloseEventflow: StringA flow modal was closed.

ProphetXEmbed

Low-level iframe component. Use this when you need direct control over the embed lifecycle — most integrations should use the hooks above instead.

This component is only available in @prophetx/sdk-react.


function CustomEmbed() {
  const ref = useRef<ProphetXEmbedHandle>(null);

  return (
    <ProphetXEmbed
      ref={ref}
      open={true}
      onOpenChange={(open) => console.log("Open state:", open)}
      src="https://embed.prophetx.co/deposit"
      token={token}
      title="Deposit"
      theme={{ mode: "dark" }}
      onSuccess={(transactionId, amount) => console.log("Success:", transactionId)}
      onError={(code, message) => console.error("Error:", code, message)}
      onCancel={() => console.log("Cancelled")}
      onReady={() => console.log("Ready")}
      onGeofenceBlocked={(stateCode, reason) => console.log("Blocked:", stateCode)}
      onKycSuccess={(identityUuid) => console.log("KYC passed:", identityUuid)}
      onKycFailed={(reason) => console.log("KYC failed:", reason)}
      onKycPending={() => console.log("KYC pending")}
      onSessionExpired={async () => {
        const fresh = await fetchToken();
        return fresh;
      }}
    />
  );
}

Props

PropTypeRequiredDescription
openbooleanYesControls whether the embed is visible.
onOpenChange(open: boolean) => voidYesCalled when the open state should change (e.g. user closes the modal).
srcstringYesFull URL of the embed page to load.
tokenstringYesPartner session JWT.
titlestringNoAccessible title for the iframe.
themeEmbedThemeNoTheme overrides.
localestringNoBCP 47 locale tag (e.g. "en", "es"). Sent to the embed via PROPHETX_LOCALE. Defaults to "en".
onSuccess(transactionId: string, amount?: number) => voidNoTransaction completed.
onError(code: string, message: string) => voidNoAn error occurred.
onCancel() => voidNoUser closed the modal.
onReady() => voidNoEmbed iframe loaded and ready.
onGeofenceBlocked(stateCode: string, reason: string) => voidNoLocation not permitted.
onKycSuccess(identityUuid: string) => voidNoIdentity verification passed.
onKycFailed(reason: string) => voidNoIdentity verification failed.
onKycPending() => voidNoIdentity verification pending.
onSessionExpired() => Promise<string | null>NoReturn a fresh JWT or null to abort.

ProphetXEmbedHandle (ref)

Access the imperative handle via useRef<ProphetXEmbedHandle>:

MethodTypeDescription
sendMessage(message: { type: string; payload?: unknown }) => voidSend a raw postMessage to the iframe.
reload() => voidReload the iframe.

JavaScript SDK instance

The object returned by createProphetX().

Method / PropertyTypeDescription
openDeposit(opts)(OpenOptions) => voidOpen the deposit flow.
openWithdraw(opts)(OpenOptions) => voidOpen the withdraw flow.
openOneClickSignup(opts)(OpenOneClickSignupOptions) => voidOpen the 1-Click Signup flow (new users). opts is required — needs sessionKey/environment.
openKyc(opts) / openIdUpload(opts)(OpenIdUploadOptions) => voidOpen the document verification flow (existing users). Same flow, two names.
close()() => voidClose any open flow.
destroy()() => voidTear down the SDK — removes DOM elements, clears listeners, destroys auth manager.
updateTheme(theme)(EmbedTheme) => voidUpdate the theme on a currently open embed.
on(event, handler)See EventEmitterSubscribe to an event. Returns an unsubscribe function.
off(event, handler)See EventEmitterUnsubscribe from an event.
authAuthManager | nullAuth manager instance. null if AuthConfig was not provided.
walletWalletClient | nullWallet client instance. null if auth was not configured.

OpenOptions (JavaScript SDK)

OptionTypeDescription
tokenstringSession JWT. Required unless using the auth module.
themeEmbedThemePer-flow theme overrides.
localestringBCP 47 locale tag (e.g. "en", "es"). Defaults to "en".
onSuccess(transactionId: string, amount?: number) => voidTransaction completed.
onError(code: string, message: string) => voidAn error occurred.
onCancel() => voidUser closed the modal.
onReady() => voidEmbed loaded and ready.
onGeofenceBlocked(stateCode: string, reason: string) => voidLocation not permitted.
onSessionExpired() => Promise<string | null>Return a fresh JWT or null to abort.

KycOpenOptions (JavaScript SDK)

OptionTypeDescription
tokenstringSession JWT. Required unless using the auth module.
themeEmbedThemePer-flow theme overrides.
localestringBCP 47 locale tag (e.g. "en", "es"). Defaults to "en".
onKycSuccess(identityUuid: string) => voidIdentity verification passed.
onKycFailed(reason: string) => voidIdentity verification failed.
onKycPending() => voidIdentity verification pending.
onError(code: string, message: string) => voidAn error occurred.
onCancel() => voidUser closed the modal.
onReady() => voidEmbed loaded and ready.
onGeofenceBlocked(stateCode: string, reason: string) => voidLocation not permitted.
onSessionExpired() => Promise<string | null>Return a fresh JWT or null to abort.

Events

The SDK has three event layers. Most integrations only use callback events (passed to open()). Use the EventEmitter for global analytics or logging. Use the postMessage protocol only if building a custom integration without the SDK.

Callback events

Passed as options to open() on each flow hook. See the individual hook sections above for the full list per flow.

Summary of all callback events across flows:

CallbackAvailable onPayload
onSuccessAll flows(transactionId: string, amount?: number)
onErrorAll flows(code: string, message: string)
onCancelAll flows—
onReadyAll flows—
onGeofenceBlockedAll flows(stateCode: string, reason: string)
onOneClickSuccessuseOneClickSignup(identityUuid: string)
onOneClickDeclineduseOneClickSignup—
onOneClickFaileduseOneClickSignup(reason: string, retryable?: boolean)
onKycSuccessuseKyc, useIdUpload(identityUuid?: string) — always absent
onKycFaileduseKyc, useIdUpload(reason: string, retryable?: boolean)
onKycPendinguseKyc, useIdUpload—

EventEmitter

A typed pub/sub system available in all three SDKs. In React/React Native, use useEvents. In JavaScript, use sdk.on() / sdk.off().

Event namePayload typeDescription
ready—Embed iframe loaded and ready to interact.
success{ transactionId: string; amount?: number }Transaction completed successfully.
error{ code: string; message: string }An error occurred.
cancel—User dismissed the modal.
kycSuccess{ identityUuid: string }Identity verification passed.
kycFailed{ reason: string }Identity verification failed.
kycPending—Identity verification submitted, awaiting result.
geofenceBlocked{ stateCode: string; reason: string }User's location is outside a permitted jurisdiction.
resize{ height: number }Embed content height changed. Useful for inline (non-modal) embeds.
sessionExpired—The session token has expired.
sessionRefreshed{ token: string }A new session token was obtained after expiry.
open{ flow: string }A flow modal was opened. flow is "deposit", "withdraw", "onboarding", or "kyc".
close{ flow: string }A flow modal was closed.

EventEmitter API:

// Subscribe — returns an unsubscribe function
const unsub = sdk.on("success", ({ transactionId, amount }) => { ... });

// Unsubscribe by reference
sdk.off("success", handler);

// Unsubscribe via return value
unsub();

postMessage protocol

Raw messages exchanged between the host page and the ProphetX iframe via window.postMessage. The SDK handles these automatically — use this reference only if you are building a custom integration without the SDK.

Outbound messages (iframe to host)

These messages are sent by the ProphetX embed to your page:

Message typePayloadDescription
PROPHETX_READY—Embed loaded and ready.
PROPHETX_EMBED_LOADED—Iframe DOM content loaded.
PROPHETX_SUCCESS{ transactionId: string; amount?: number }Transaction completed.
PROPHETX_ERROR{ code: string; message: string }An error occurred.
PROPHETX_CANCEL—User dismissed the flow.
PROPHETX_RESIZE{ height: number }Embed content height changed.
PROPHETX_GEOFENCE_BLOCKED{ stateCode: string; reason: string }User's location isn't eligible. Defined on every flow except 1-Click Signup; in practice this is enforced at token issuance, not per-request, so it rarely fires with a validly-issued embed token.
PROPHETX_KYC_SUCCESS{ identityUuid?: string }Document verification (useKyc/useIdUpload) resolved successfully. identityUuid is always absent — the IDPV API returns none. Final — no further async step.
PROPHETX_KYC_FAILED{ reason: string; retryable?: boolean }Document verification was rejected. Branch on retryable, not reason (log/route only).
PROPHETX_KYC_PENDING{}Document submitted, review not yet resolved.
PROPHETX_ONE_CLICK_SUCCESS{ identityUuid: string }1-Click Signup: user shared their identity. KYC has not run yet — redeem via POST /private/v1/users/one-click to start it.
PROPHETX_ONE_CLICK_FAILED{ reason: string; retryable?: boolean }1-Click Signup: terminal failure. retryable is only ever true for a spent/lapsed session key.
PROPHETX_ONE_CLICK_DECLINED{}1-Click Signup: user chose not to share. Not an error.
PROPHETX_SESSION_EXPIRED—Session token expired.

Inbound messages (host to iframe)

Send these messages to the ProphetX iframe:

Message typePayloadDescription
PROPHETX_SESSION{ token: string }Provide the session JWT when opening a flow.
PROPHETX_SESSION_REFRESH{ token: string }Provide a refreshed JWT after a PROPHETX_SESSION_EXPIRED event.
PROPHETX_THEMEEmbedThemeUpdate the embed's theme.
PROPHETX_CLOSE—Close the embed.

Example — listening without the SDK:

window.addEventListener("message", (event) => {
  // Validate origin
  if (event.origin !== "https://embed.prophetx.co") return;

  const { type, payload } = event.data;

  switch (type) {
    case "PROPHETX_READY":
      console.log("Embed ready");
      break;
    case "PROPHETX_SUCCESS":
      console.log("Transaction:", payload.transactionId, payload.amount);
      break;
    case "PROPHETX_ERROR":
      console.error("Error:", payload.code, payload.message);
      break;
    case "PROPHETX_CANCEL":
      console.log("Cancelled");
      break;
    case "PROPHETX_SESSION_EXPIRED":
      // Fetch a new token and send it back
      fetchToken().then((token) => {
        iframe.contentWindow.postMessage(
          { type: "PROPHETX_SESSION_REFRESH", payload: { token } },
          "https://embed.prophetx.co"
        );
      });
      break;
  }
});

EmbedTheme

Theme overrides applied to the embed UI. Pass via the theme prop on ProphetXProvider (React/React Native), as part of OpenOptions (JavaScript SDK), or dynamically via sdk.updateTheme().

type EmbedTheme = {
  mode?: "light" | "dark";
  primaryColor?: string;
  colorOverrides?: Partial<ColorOverrides>;
  spacingOverrides?: Partial<SpacingOverrides>;
  radiusOverrides?: Partial<RadiusOverrides>;
  fontSizeOverrides?: Partial<FontSizeOverrides>;
};

Top-level fields

FieldTypeDescription
mode"light" | "dark"Base color scheme. Defaults to "dark".
primaryColorstringPrimary brand color. Applied to primary, primaryHover, cta, and ctaHover tokens.

colorOverrides

Fine-grained color tokens. All fields are optional CSS color strings.

TokenDescription
primaryPrimary brand color
primaryHoverHover state for primary elements
primaryForegroundText/icon color on primary backgrounds
secondarySecondary color
secondaryHoverHover state for secondary elements
backgroundPage background
surfaceCard/panel background
surfaceElevatedElevated surface (modals, dropdowns)
textDefault text color
textMutedDe-emphasized text
textSubtleLeast prominent text (placeholders, hints)
borderDefault border color
borderSubtleSubtle border (dividers, separators)
errorError text/icon color
errorBackgroundError background (alerts, badges)
successSuccess text/icon color
successBackgroundSuccess background
warningWarning text/icon color
warningBackgroundWarning background
ctaCall-to-action button color
ctaHoverCTA hover state
ctaForegroundText on CTA buttons
filledFilled/solid button color
filledHoverFilled button hover state
filledForegroundText on filled buttons
dangerDestructive action color
dangerHoverDestructive action hover state
dangerForegroundText on destructive action buttons

spacingOverrides

TokenDescription
xsExtra-small spacing
smSmall spacing
mdMedium spacing
lgLarge spacing
xlExtra-large spacing

radiusOverrides

TokenDescription
smSmall border radius
mdMedium border radius
lgLarge border radius
fullFully rounded (pill shape)

fontSizeOverrides

TokenDescription
xsExtra-small font size
smSmall font size
mdMedium (base) font size
lgLarge font size
xlExtra-large font size

DevToolsLogEntry

Entries emitted by the devtools system. Receive them via DevToolsConfig.onEvent.

FieldTypeDescription
timestampnumberUnix timestamp (ms).
category"auth" | "message" | "api" | "lifecycle" | "event"Log category.
level"error" | "warn" | "info" | "debug"Severity level.
messagestringHuman-readable log message.
dataRecord<string, unknown> | undefinedOptional structured data.

Type exports

All types are exported from the SDK package you're using. Import them alongside components and hooks:



Did this page help you?