Join video sessions with a short link

View as Markdown

When a Contact Center agent uses the Zoom client to invite a user to an unscheduled video session, Contact Center sends an invitation email containing a shortened link like https://shortlink.zoom.com/cc/bMefyOFPf to invite the user to join the video session. When the user opens or pastes that shortened link into your Contact Center app, have your app route the URL to the handler.

Configure URL handling

Call handleShortLinkVideoURL(url) after your app receives a Contact Center short link from either the clipboard or an app.

For a clipboard flow:

  1. Read the primary clip only when clipboard checking is enabled.
  2. Trim the text and reject an empty value or text longer than 512 characters.
  3. Ask the user to confirm before opening the link.
private static final String TAG = "ShortLinkVideo";
private static final int MAX_CLIPBOARD_LINK_LENGTH = 512;

// Call this method from the positive action of your clipboard confirmation dialog.
private void handleShortLinkVideoURL(String shortLink) {
    // Normalize and limit clipboard text before passing it to the SDK.
    String normalizedLink = shortLink == null ? "" : shortLink.trim();
    if (normalizedLink.isEmpty() || normalizedLink.length() > MAX_CLIPBOARD_LINK_LENGTH) {
        return;
    }

    ZoomCCVideoService service = ZoomCCInterface.INSTANCE.getZoomCCVideoService();
    ZoomCCVideoListener shortLinkVideoListener = new ZoomCCVideoListener() {
        @Override
        public void onError(int error, long detail, @NonNull String description) {
            // Called when link handling fails after the request is accepted.
            // Show a generic message; keep details in logs only.
            Log.e(TAG, "Short-link video error: error=" + error + ", detail=" + detail);
        }

        @Override
        public void onClientEvent(@NonNull ClientEvent event) {
        }

        @Override
        public void unreadMsgCountChanged(int count) {
        }

        @Override
        public void onEngagementEnd(@NonNull String engagementId) {
        }

        @Override
        public void onEngagementStart(@NonNull String engagementId) {
        }

        @Override
        public void onLoginStatus(@Nullable IMStatus status) {
        }
    };

    service.addListener(shortLinkVideoListener);
    // true means handling started, not that joining has finished.
    boolean accepted = service.handleShortLinkVideoURL(normalizedLink);
    if (!accepted) {
        service.removeListener(shortLinkVideoListener);
        Toast.makeText(this, "Unable to open short link", Toast.LENGTH_SHORT).show();
        return;
    }
}

private String getClipboardJoinLink() {
    if (clipboardManager == null) {
        return null;
    }

    try {
        if (!clipboardManager.hasPrimaryClip()) {
            return null;
        }
        ClipData clip = clipboardManager.getPrimaryClip();
        if (clip == null || clip.getItemCount() == 0) {
            return null;
        }

        // Use the first clipboard item as plain text.
        CharSequence clipText = clip.getItemAt(0).coerceToText(this);
        String text = clipText == null ? null : clipText.toString().trim();
        if (text == null || text.isEmpty() || text.length() > MAX_CLIPBOARD_LINK_LENGTH) {
            return null;
        }
        return text;
    } catch (RuntimeException e) {
        Log.w(TAG, "Unable to read clipboard text.", e);
        return null;
    }
}

@Override
protected void onResume() {
    super.onResume();
    // Listen only while the Activity is visible.
    if (clipboardJoinLinkCheckEnabled && clipboardManager != null && clipboardListener != null) {
        clipboardManager.addPrimaryClipChangedListener(clipboardListener);
    }
}

@Override
public void onWindowFocusChanged(boolean hasFocus) {
    super.onWindowFocusChanged(hasFocus);
    if (hasFocus && clipboardJoinLinkCheckEnabled) {
        checkClipboardJoinLink();
    }
}

@Override
protected void onPause() {
    // Stop clipboard callbacks while the Activity is paused.
    if (clipboardManager != null && clipboardListener != null) {
        clipboardManager.removePrimaryClipChangedListener(clipboardListener);
    }
    super.onPause();
}

@Override
protected void onDestroy() {
    if (clipboardManager != null && clipboardListener != null) {
        clipboardManager.removePrimaryClipChangedListener(clipboardListener);
    }
    // Close the confirmation dialog before releasing the Activity.
    if (clipboardDialog != null) {
        clipboardDialog.dismiss();
        clipboardDialog = null;
    }
    super.onDestroy();
}

If handleShortLinkVideoURL(url) returns false, the SDK did not accept the link or could not start the flow. Show a generic invalid-link message and do not open a video session.

A return value of true means that handling started. It does not guarantee that link resolution or joining completed successfully. Later failures are delivered to onError.

If the SDK can't process the link, return false from your URL-handling path and execute this callback method.

@Override
public void onError(int error, long detail, @NonNull String description) {
}

After this completes, onError returns an error code and relevant error information.