diff --git a/docs/labs/calling/README.md b/docs/labs/calling/README.md
new file mode 100644
index 00000000000..bfc6e4cc4f5
--- /dev/null
+++ b/docs/labs/calling/README.md
@@ -0,0 +1,89 @@
+# Calling SDK Lab
+
+This lab mirrors the Contact Center lab structure and demonstrates Webex Calling WebRTC SDK basics:
+
+- Initialize Calling with a Personal Access Token
+- Register and obtain a `line`
+- Acquire microphone and wire media
+- Make and answer calls
+- Control calls (mute/hold/end)
+- Send DTMF digits using a dial pad
+
+## Files
+
+```
+docs/labs/calling/
+├── index.html # Lab UI
+├── index.js # Orchestration
+├── styles.css # Styles
+└── modules/
+ ├── auth.js # Initialization
+ ├── registration.js # Register/deregister/line helpers
+ └── call-controls.js# Call control helpers (placeholder)
+```
+
+## Notes
+
+- DTMF: Use `call.sendDigit('123#')` or per-key press from the dial pad. This calls through to the SDK which inserts DTMF on the media connection.
+- The lab expects the calling UMD from `docs/samples/calling.min.js` already built by the repo.
+
+## DTMF Dialer and IVR Use Case
+
+Interactive Voice Response (IVR) systems commonly prompt callers to navigate menus (e.g., "Press 1 for Sales") or enter information (e.g., account numbers). During an established call, you can send DTMF tones either one-by-one or as a sequence:
+
+```javascript
+// Single selection (e.g., Press 1 for Sales)
+call.sendDigit('1');
+
+// Enter an account number followed by #
+const accountNumber = '123456';
+call.sendDigit(accountNumber + '#');
+
+// If using the lab's dialpad: per-key presses call sendDigit(key)
+// automatically; the Send button submits the current input field.
+```
+
+Tips:
+- Only call `sendDigit` once the call is established and you can hear the IVR prompts.
+- The dialpad in this lab sends each key immediately, but also lets you batch send when needed.
+
+## OAuth (Implicit) Flow — Calling
+
+For production, use OAuth instead of a PAT. Create an Integration at the Webex Developer Portal and configure:
+
+- Client ID (public)
+- Redirect URI (e.g., `http://localhost:/` while testing)
+- Scopes (minimum for Calling):
+ - `spark:webrtc_calling`
+ - `spark:calls_read`
+ - `spark:calls_write`
+ - `spark:kms`
+ - `spark:xsi`
+
+Example (also shown in `index.html`):
+
+```javascript
+const webex = Webex.init({
+ config: {
+ credentials: {
+ client_id: 'YOUR_PUBLIC_CLIENT_ID',
+ redirect_uri: window.location.origin + window.location.pathname,
+ scope: [
+ 'spark:webrtc_calling',
+ 'spark:calls_read',
+ 'spark:calls_write',
+ 'spark:kms',
+ 'spark:xsi'
+ ].join(' ')
+ }
+ }
+});
+
+await webex.authorization.initiateLogin();
+
+// After redirect back, the access_token is in the URL hash. The lab auto-detects
+// it and initializes Calling using that token.
+```
+
+
+
diff --git a/docs/labs/calling/index.html b/docs/labs/calling/index.html
new file mode 100644
index 00000000000..7bebe6f2f7f
--- /dev/null
+++ b/docs/labs/calling/index.html
@@ -0,0 +1,276 @@
+
+
+
+
+ Calling SDK Lab
+
+
+
+
+
+
+
+
+
+
+
+
+
Webex Calling SDK Lab
+
+
+
+ This lab demonstrates how to build a basic Calling experience using the
+ Webex Calling WebRTC SDK. You'll authenticate, register, acquire media,
+ place/answer calls, and send DTMF digits using a dial pad.
+
+
+
+
+
+
Step 1: Authentication
+
+ Initialize the Calling SDK with a Personal Access Token (PAT). The
+ initialized Calling instance is used for all subsequent
+ operations.
+
+ To use OAuth, first create an Integration in the
+ Webex Developer Portal.
+ You will receive a Client ID and configure one or more
+ Redirect URIs. For local testing, set your redirect to
+ http://localhost:<PORT>/ (matching the port you serve this page on).
+
+
+ This lab uses OAuth (implicit) to obtain an access token that is then
+ used to initialize the Calling SDK. The required scopes for Calling are:
+ spark:webrtc_calling spark:calls_read spark:calls_write spark:kms spark:xsi.
+
+
// OAuth (Implicit) flow (Calling scopes)
+const webex = Webex.init({
+ config: {
+ credentials: {
+ client_id: 'YOUR_PUBLIC_CLIENT_ID', // From your Integration
+ redirect_uri: window.location.origin + window.location.pathname, // Must match Integration
+ scope: [
+ 'spark:webrtc_calling',
+ 'spark:calls_read',
+ 'spark:calls_write',
+ 'spark:kms',
+ 'spark:xsi'
+ ].join(' ')
+ }
+ }
+});
+
+// 1) Initiate OAuth; user is redirected to Webex for login/consent
+await webex.authorization.initiateLogin();
+
+// 2) After redirect back to this page, Webex places the access_token in the URL hash
+// This lab automatically detects it and initializes Calling with that token.
+// See: auto-init logic in index.js (autoInitFromHash()).
+
+
+
+
+
Step 2: Registration
+
+ Register and create a line to receive incoming calls and
+ place outgoing calls.
+
+
+
+
+
+
Not registered
+
// Register and get first line
+await calling.register();
+const callingClient = calling.callingClient;
+const line = Object.values(callingClient.getLines())[0];
+// Next step: explicitly register the line (see Step 3)
+
+
+
+
+
Step 3: Line Registration
+
+ Register the line to enable placing and receiving calls. This
+ must be done after Calling registration.
+
+
+
+
+
Line not registered
+
// Register the primary line
+line.register();
+line.on('registered', (deviceInfo) => {
+ console.log('Line registered', deviceInfo);
+});
+
+
+
+
+
Step 4: Media
+
Get microphone access and prepare local media for calls.