VIH Messenger Custom Discover

Custom Integration Guide

Discover in your app, chat in the SDK

List the Discover enterprises in your own native UI, put whatever button you like on each row, and deep-link straight into that channel's SDK chat. Three calls, Android and iOS. No custom build, no new backend endpoint โ€” and the SDK keeps its usual Discover ยท Chats ยท Settings tabs.

๐Ÿ“ฆ

Available on Android and iOS. This is the same VIH Messenger SDK from the base integration guide โ€” it adds a public VihDiscover facade. Android needs vih-sdk-staging 1.1.4+; iOS the matching SwiftPM package. Drop-in helpers live in custom-sdk/android/VihDiscoverKit.kt and custom-sdk/ios/VihDiscoverKit.swift.

๐Ÿงญ The shape of it

You keep the discovery experience in your app and hand off to the SDK only for the actual conversation:

  • Your app renders the enterprise list (your layout, your button, your search).
  • The SDK owns auth, the chat screen, real-time messaging and push โ€” unchanged.

There is no new API to build: the enterprise list is the same GET main/enterprises/?channel_id=<hashcode> the Discover tab already calls, surfaced as a clean SDK method that returns a flat VihEnterprise list.

๐Ÿ”ฉ How it works โ€” three calls

StepCallWhat happens
1 ยท Sign inprepareSession(phone, hashcode)Passwordless phone sign-in; stores the session token so the list & chat are authenticated โ€” before any SDK screen is shown.
2 ยท ListfetchAllEnterprises(hashcode)Returns every Discover enterprise (auto-paginated) as VihEnterprise. Render it in your own UI.
3 ยท Open chatopenChat(โ€ฆ, enterprise)Deep-links into that enterprise's SDK chat screen โ€” your row's button action. Backing out of the chat lands on the SDK's main page (Discover ยท Chats ยท Settings), then back again returns to your app.
โœ…

Two layers, use whichever fits. VihDiscover is the stable public facade inside the SDK. VihDiscoverKit is a small drop-in helper (in this folder) you copy into your app for lambda / async callbacks and the fetchAllEnterprises auto-pagination convenience โ€” it just delegates to VihDiscover, so it's optional.

๐Ÿ—‚๏ธ The VihEnterprise model

Each row you render is a VihEnterprise. Use enterpriseId as the id you pass to openChat; raw is the full underlying model if you need a field not surfaced here.

kotlin / swiftVihEnterprise
enterpriseId : String    // the id to pass to openChat (enterprise user_id)
name         : String    // resolved display name
logoUrl      : String?   // logo/avatar URL (may be null โ†’ show a placeholder)
category     : String
industry     : String
description  : String?   // short blurb, when the channel provides one
raw          : EnterPriseModel   // full underlying model (escape hatch)
๐Ÿ–ผ๏ธ

Rendering rows. Show each enterprise's logoUrl as a circular avatar before the name โ€” the same way the SDK's Discover tab does โ€” and overlay a small VIH Messenger logo badge at its bottom-right corner to signal it's a VIH channel. logoUrl may be null; show a placeholder then.

Android Kotlin

Copy custom-sdk/android/VihDiscoverKit.kt into your app (rename its package), or call com.vihmessenger.vihchatbot.discover.VihDiscover directly. All callbacks arrive on the main thread.

1

Sign the user in

Call once โ€” e.g. when your Discover screen opens. phone is digits only, with country code, no +.

kotlinDiscoverActivity.kt
import com.example.vihdiscover.VihDiscoverKit

VihDiscoverKit.prepareSession(
    context  = this,
    phone    = "919876543210",
    hashcode = "your-channel-hashcode",
    onReady  = { loadEnterprises() },
    onError  = { e -> showError(e.message) }
)
2

List the enterprises in your own UI

fetchAllEnterprises walks every page and hands you the full list. Bind it to your own RecyclerView / Compose list.

kotlinDiscoverActivity.kt
private fun loadEnterprises() {
    VihDiscoverKit.fetchAllEnterprises(
        hashcode = "your-channel-hashcode",
        onResult = { enterprises ->          // List<VihEnterprise>
            adapter.submitList(enterprises)   // your adapter, your layout
        },
        onError = { e -> showError(e.message) }
    )
}

// Prefer to page lazily instead? Use one page at a time:
// VihDiscoverKit.listEnterprises(hashcode, page = 1, search = "", industries = "", โ€ฆ)
3

Open the chat from your button

In your row's click listener, hand the tapped VihEnterprise to openChat โ€” the SDK presents its chat screen for that channel.

kotlinDiscoverAdapter.kt
holder.chatButton.setOnClickListener {
    VihDiscoverKit.openChat(
        context    = holder.itemView.context,
        hashcode   = "your-channel-hashcode",
        enterprise = item          // the VihEnterprise for this row
    )
}
โ†ฉ๏ธ

Back navigation. On Android, openChat places the SDK dashboard (Discover ยท Chats ยท Settings) underneath the chat, so the flow is your list โ†’ chat โ†’ back โ†’ SDK dashboard โ†’ back โ†’ your app. This is on by default (landOnDashboard = true); it needs the phone from prepareSession. Pass landOnDashboard = false to open the chat standalone (back returns straight to your list).

๐Ÿงฉ

Calling the facade directly? The same three methods exist on VihDiscover with a Callback<T> interface: VihDiscover.prepareSession(context, phone, hashcode, cb), VihDiscover.listEnterprises(hashcode, page, search, industries, cb), and VihDiscover.openChat(context, hashcode, enterprise).

iOS Swift

Copy custom-sdk/ios/VihDiscoverKit.swift into your target, or call VihDiscover directly. Both async and completion-handler forms are provided; here's the async flow.

1

Sign in & list

swiftDiscoverViewController.swift
import VihChatBotSDK

func loadDiscover() {
    Task {
        do {
            try await VihDiscoverKit.prepareSession(
                phone: "919876543210", hashcode: "your-channel-hashcode")

            let enterprises = try await VihDiscoverKit.fetchAllEnterprises(
                hashcode: "your-channel-hashcode")   // [VihEnterprise]

            await MainActor.run { self.render(enterprises) }  // your own UI
        } catch {
            await MainActor.run { self.showError(error) }
        }
    }
}
2

Open the chat from your button

swiftDiscoverViewController.swift
@objc func onChatTapped(_ enterprise: VihEnterprise) {
    VihDiscoverKit.openChat(
        from: self,
        hashcode: "your-channel-hashcode",
        enterprise: enterprise)   // pushed onto your nav controller
}

// Land on the SDK dashboard after backing out of the chat (opt-in on iOS):
// VihDiscover.openChat(from: self, hashcode: hashcode,
//                      enterprise: enterprise, landOnDashboard: true)
โ†ฉ๏ธ

Back navigation differs on iOS. iOS navigation is a UITabBarController, not an activity stack, so landOnDashboard defaults to false here (Android defaults to true). With the default, backing out of the chat returns to your list. Set landOnDashboard: true to present the SDK dashboard (Discover ยท Chats ยท Settings) and push the chat on top โ€” then your app dismisses that dashboard to return to the host. Verified on Android; smoke-test the iOS path in your app.

โœ…

Prefer callbacks over async? Every method has a completion form, e.g. VihDiscoverKit.fetchAllEnterprises(hashcode:) { result in โ€ฆ } โ€” delivered on the main thread.

๐Ÿ›Ž๏ธ The floating widget on your bottom nav

The SDK's FloatingButtonView sits centered on your app's bottom navigation bar as the always-visible launcher into the SDK โ€” the standard entry point alongside your Discover list. Drop it into the middle slot of your bottom bar:

  • Set your own artwork with setCenterImageResource(...) + imageOnly = true (full-bleed, no background circle).
  • It pops (animates up) automatically when the SDK receives a message (popOnMessageEnabled / popUp()).
  • Shows an unread-count badge via unreadCount โ€” auto-increments per message and clears on tap; drive it yourself with countUnreadOnMessage = false.
  • By default a tap opens the SDK; set launchesSdkOnClick = false + your own setOnClickListener to handle it.
kotlinCenter it on your bottom nav
val widget = FloatingButtonView(context).apply {
    setCenterImageResource(R.drawable.ic_vih_widget) // your widget artwork
    imageOnly = true            // full-bleed, no background circle
    launchesSdkOnClick = false
    setOnClickListener {
        FloatingButtonView.startSdk(context, "919876543210", "your-channel-hashcode")
    }
}
// place `widget` in the center slot of your bottom navigation bar;
// it pops + updates its unread badge automatically as messages arrive.
๐Ÿ’ก

These are the same FloatingButtonView capabilities documented in the base integration guide.

๐Ÿ”Ž Search & pagination

The enterprise endpoint is paged and searchable server-side:

  • Search: pass search = "acme" to filter by name.
  • Industry filter: pass industries = "Banking,Retail" (comma-separated).
  • Paging: fetchAllEnterprises auto-walks pages until one returns empty (capped at maxPages, default 20). To page lazily yourself, call listEnterprises(page = n, โ€ฆ) and stop when a page comes back empty.
kotlinFiltered fetch
VihDiscoverKit.fetchAllEnterprises(
    hashcode   = "your-channel-hashcode",
    search     = "bank",
    industries = "Banking,Fintech",
    onResult   = { list -> adapter.submitList(list) },
    onError    = { e -> showError(e.message) }
)

๐Ÿ” Auth & session โ€” read this once

  • Sign in first. The list and chat endpoints are authenticated. Call prepareSession (once) before fetchAllEnterprises or openChat, or those calls will fail with an auth error.
  • Channel switch resets the session. Passing a different hashcode than last time clears the previous channel's stored token โ€” intentionally, so you never send a stale token to the new channel.
  • Session persists. Once prepareSession succeeds the token is stored (encrypted on Android, Keychain on iOS); you don't need to call it on every screen โ€” only after a fresh install, logout, or channel change.
  • Already using the full SDK? If the user has already signed in through the SDK's normal launch on this channel, the session exists and you can skip prepareSession and go straight to listing.

๐Ÿฉบ Troubleshooting

SymptomLikely cause โ†’ fix
Empty list, no errorNo session yet โ†’ call prepareSession first and start listing in its onReady / after await. Also confirm the hashcode is the one VIH issued for this channel.
Auth / 401 error on list or chatSession missing or stale โ†’ run prepareSession again for the current hashcode (a channel switch clears the old token).
Chat opens but history/sending failsSame as above โ€” the chat screen needs the authenticated session. Ensure prepareSession completed before openChat.
Row title/logo blankSome channels leave a field null; name falls back through display name โ†’ company name, and logoUrl may be null (show a placeholder). Inspect raw for other fields.

๐Ÿ“ฎ Support

Questions on the custom Discover flow, a field you need on VihEnterprise, or session/auth behavior? Reach the VIH team with your channel hashcode, SDK version, and the call you're making.