Skip to main content
By the end of this guide, you’ll understand how to use each SDK callback function to respond to key events in the user journey.
Before you start

Overview

When a user interacts with Link, Mesh fires SDK events that you can respond to in your app. The four callback functions below cover the most important moments in the user journey: connecting an account, completing a transfer, exiting, and responding to granular in-flow events.

SDK callback functions

SDK callback functionDescriptionKey usesPayload details
onIntegrationConnected()Allows you to run specific business logic when the user has successfully completed connecting an account.Capture accessTokens to:
• pass to Mesh SDK for a return-user experience
• pass to Mesh endpoints to get user deposit addresses or balances
accessToken: the access and refresh tokens to the connected account with some basic metadata about the account and tokens
brokerBrandInfo: links to icons and logos for the connected integration
onTransferFinished()Allows you to run specific business logic when the user has successfully completed a transfer.Show user a banner or notification acknowledging a pending transaction. Example: “Your 99.99 USDC deposit is pending and will be credited to your account when it receives enough network confirmations.”status: pending / succeeded / failed
txId: A unique client identifier
transferId: A unique Mesh identifier
txHash?: A unique blockchain identifier
fromAddress: Address transfer is sent from
toAddress: Address transfer is sent to
symbol: Symbol of asset being transferred
amount: Amount being transferred
amountInFiat: Fiat equivalent of transfer amount
totalAmountInFiat: Total amount transferred, including transfer-related fees
networkId: Selected network identifier
networkName: Selected network name
refundAddress: The address that the user can receive back to
onExit()Allows you to run specific business logic when the user has exited Link at some point.Show the user some experience when they exit Link without successfully completing a transfer.errorMessage: Descriptive error message, if applicable
summary: // optional
page: the page the user was on when they exited
selectedIntegration: Name and Id of integration
transfer: previewId and other details about the transfer preview
onEvent()Allows you to run specific business logic in more granular scenarios, like when the user exits Link from specific parts in the user journey. The events that can be used in this callback function are listed below.Different payload structure for different events

SDK-specific instructions for setting up callback functions

const connection = createLink({
  renderType: 'overlay', // Opens SDK on top of your web app
  theme: 'system', // Possible values: 'system', 'dark', 'light'
  language: 'system', // See "Multi-language support" guide
  displayFiatCurrency: 'USD', // See "Fiat currency support" guide
  accessTokens: accessTokens, // See "Supercharge return users" guide
  onIntegrationConnected: payload => {
    // Payload contains integration tokens that can be passed to SDK for a return user experience, or calling certain Mesh APIs
    console.log('[MESH LINK integration connected]', payload)
  },
  onTransferFinished: payload => {
    // Called after a transfer flow completes successfully
    console.log('[MESH LINK transfer finished]', payload)
  },
  onExit: () => {
    // Called when Link is closed
    console.log('[MESH LINK exited]')
  },
  onEvent: ev => {
    // Allows you to handle other specific events
    console.log('[MESH LINK event]', ev)
  }
})

connection.openLink(linkToken) // Opens a popup that overlays your app
func launchMeshLink(
    linkToken: String,
    viewController: UIViewController,
    accessTokens: [IntegrationAccessToken]? = nil
) {
    var linkHandler: LinkHandler?

    let settings = LinkSettings(
        accessTokens: accessTokens, // See "Supercharge return users" guide
        language: "system", // See "Multi-language support" guide
        displayFiatCurrency: "USD", // See "Fiat currency support" guide
        theme: .system // Possible values: 'system', 'dark', 'light'
    )

    // Called after a user connects an exchange, wallet, or other integration.
    let onIntegrationConnected: (LinkPayload) -> Void = { linkPayload in
        switch linkPayload {
        case .accessToken(let accessTokenPayload):
            print(accessTokenPayload)
        case .delayedAuth(let delayedAuthPayload):
            print(delayedAuthPayload)
        @unknown default:
            print("unknown LinkPayload")
        }
    }

    // Called after a transfer flow completes successfully or fails.
    let onTransferFinished: (TransferFinishedPayload) -> Void = { transferFinishedPayload in
        switch transferFinishedPayload {
        case .success(let successPayload):
            print(successPayload)
        case .error(let errorPayload):
            print(errorPayload)
        @unknown default:
            print("unknown TransferFinishedPayload")
        }
    }

    // Called throughout the Link flow so you can track user progress.
    let onEvent: ([String: Any]?) -> Void = { payload in
        print("Event: \(payload ?? [:])")
    }

    // Called when the user exits Link
    let onExit: (Bool?) -> Void = { showAlert in
        // showAlert is true when 'x' button is tapped
        // showAlert is false when 'Done' button is tapped on a Transfer Success screen
        if showAlert ?? false {
            // in case a custom alert is implemented, linkHandler?.closeLink() must be called to close Link
            linkHandler?.showExitAlert() // default Exit alert
        } else {
            linkHandler?.closeLink()
        }
    }

    let configuration = LinkConfiguration(
        linkToken: linkToken,
        settings: settings,
        disableDomainWhiteList: false,
        onIntegrationConnected: onIntegrationConnected,
        onTransferFinished: onTransferFinished,
        onEvent: onEvent,
        // onExit is optional, a default alert is shown in case onExit is omitted
        onExit: onExit
    )

    let result = configuration.createHandler()

    // createHandler validates the configuration before Link is presented.
    switch result {
    case .success(let handler):
        linkHandler = handler
        // Present Link from the current UIViewController.
        handler.present(in: viewController)
    case .failure(let error):
        print(error)
    @unknown default:
        print("unknown LinkResult")
    }
}
// Register the Link launcher as an Activity or Fragment property
private val linkLauncher = registerForActivityResult(LaunchLink()) { result ->
    when (result) {
        is LinkSuccess -> {
            // Called when Link returns payloads, such as a connected account or completed transfer.
            Log.i(LOG_TAG, "LinkSuccess: ${result.payloads}")
        }
        is LinkExit -> {
            // Called when Link exits without payloads, including user exits or errors.
            Log.i(LOG_TAG, "LinkExit: ${result.errorMessage}")
        }
    }
}

private fun launchMeshLink(linkToken: String, accessTokens: List<IntegrationAccessToken>? = null) {
    // Create LinkConfiguration
    val configuration = LinkConfiguration(
        token = linkToken, // Link token returned by the Mesh backend
        theme = LinkTheme.SYSTEM, // Possible values: 'system', 'dark', 'light'
        language = "system", // See "Multi-language support" guide
        displayFiatCurrency = "USD", // See "Multi-language support" guide
        accessTokens = accessTokens, // See "Supercharge return users" guide
    )

    // Launch
    linkLauncher.launch(configuration)
}
return (
  <LinkConnect
    linkToken={linkToken}
    settings={{
      language: 'system', // See "Multi-language support" guide
      displayFiatCurrency: 'USD', // See "Fiat currency support" guide
      accessTokens, // See "Supercharge return users" guide
    }}
    onIntegrationConnected={(payload: LinkPayload) => {
      // Payload contains integration tokens that can be passed to SDK for a return user experience, or calling certain Mesh APIs
      console.log('[MESH LINK integration connected]', payload);
    }}
    onTransferFinished={(payload: TransferFinishedPayload) => {
      // Called after a transfer flow completes successfully or fails.
      console.log('[MESH LINK transfer finished]', payload);
    }}
    onEvent={(event: LinkEventType) => {
      // Allows you to handle other specific events
      console.log('[MESH LINK event]', event);
    }}
    onExit={(err?: string) => {
      // Called when Mesh Link exits, completes, is closed by the user, or fails during setup.
      console.log('[MESH LINK exited]');
    }}
  />
);
Future<void> _showMeshLinkPage(
    String linkToken, {
    List<IntegrationAccessToken> accessTokens = const [],
}) async {
  // Show MeshSdk
  final result = await MeshSdk.show(
    context,
    configuration: MeshConfiguration(
      language: 'system', // See "Multi-language support" guide
      displayFiatCurrency: 'USD', // See "Fiat currency support" guide
      theme: ThemeMode.system,
      integrationAccessTokens: accessTokens, // See "Supercharge return users" guide
      linkToken: linkToken,
      onEvent: (event) {
        // Allows you to handle other specific events
        print('Mesh event: $event');
      },
      onError: (errorType) {
        // Callback for when Mesh Link exits due to an error
        print('Mesh exit: $errorType');
      },
      onSuccess: (payload) {
        // Callback for when the Mesh Link is successfully completed
        print('Mesh success: ${payload.page}');
      },
      onIntegrationConnected: (integration) {
        // Payload contains integration tokens that can be passed to SDK for a return user experience, or calling certain Mesh APIs
        print('Integration connected: $integration');
      },
      onTransferFinished: (transfer) {
        // Called after a transfer flow completes successfully or fails.
        print('Transfer finished: $transfer');
      },
    ),
  );

  // Handle the result
  switch (result) {
    case MeshSuccess():
      print('Mesh link finished successfully');
    case MeshError():
      print('Mesh link error: ${result.type}');
  }

  // Alternatively, use `when` method
  result.when(
    success: (success) {
      final payload = success.payload;
      print('Mesh link success: ${payload.page}');
    },
    error: (error) {
      final errorType = error.type;
      print('Mesh link error: $errorType');
    },
  );
}

What’s next

Next up: Supercharge return-users — once you’re capturing accessTokens via onIntegrationConnected, you’re ready to set up Mesh Managed Tokens for a seamless return-user experience.
AI coding reference — a compact summary of this page’s APIs, parameters, and patterns for use by AI coding assistants (following the llms.txt standard). Human readers can safely ignore this.llms.txt — Use Mesh’s callback functionsThe 4 SDK callback functions for responding to key user journey events. Wire all 4 in every SDK initialization.onIntegrationConnected(payload) — fires when user connects an exchange or wallet. Key payload: accessToken.accountTokens[].tokenId (store this for MMT) | accessToken.brokerType | brokerBrandInfo (icons/logos)onTransferFinished(payload) — fires when transfer flow completes. Use for immediate UI updates only; use webhooks for business logic. Key payload: status (pending/succeeded/failed) | transferId | txHash | symbol | amount | amountInFiat | totalAmountInFiat | fromAddress | toAddress | refundAddress | networkId | networkNameonExit() — fires when user closes Link at any point. Key payload: errorMessage | summary.page | selectedIntegration (name + Id) | transfer.previewIdonEvent(ev) — fires for granular in-flow events. Use for analytics and specific UX logic. See Mesh SDK events guide for full event list.Critical: onTransferFinished fires when the provider acknowledges the request — not when it confirms on-chain. Always use webhooks for final confirmation before crediting users or releasing inventory.Web SDK — canonical initialization with all 4 callbacks:
const connection = createLink({
  renderType: 'overlay', // Opens SDK on top of your web app
  theme: 'system', // Possible values: 'system', 'dark', 'light'
  language: 'system', // See "Multi-language support" guide
  displayFiatCurrency: 'USD', // See "Fiat currency support" guide
  accessTokens: accessTokens, // See "Supercharge return users" guide
  onIntegrationConnected: payload => {
    // Payload contains integration tokens that can be passed to SDK for a return user experience, or calling certain Mesh APIs
    console.log('[MESH LINK integration connected]', payload)
  },
  onTransferFinished: payload => {
    // Called after a transfer flow completes successfully
    console.log('[MESH LINK transfer finished]', payload)
  },
  onExit: () => {
    // Called when Link is closed
    console.log('[MESH LINK exited]')
  },
  onEvent: ev => {
    // Allows you to handle other specific events
    console.log('[MESH LINK event]', ev)
  }
})

connection.openLink(linkToken) // Opens a popup that overlays your app