# App shortcuts and Apps SDK

<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! -->

App shortcuts in Zoom Chat leverage a WebView and the [Apps SDK](/docs/zoom-apps/) can be leveraged to get chat context and send messages from the client side. You can add up to 20 shortcuts for an app. You have the option to add app shortcuts to a message, the compose textarea, or both.

![](/img/shortcut-text.png)

## App shortcuts

To enable App shortcuts, navigate to the Features -> Surface page. Then toggle App Shortcuts.

![](/img/appshortcuts.png)

When the shortcut is used your app's Home URL will be opened.

![](/img/homeurl.png)

-   Make sure any URLs you want to load in your WebView are added to the Domain Allow List.
-   If you see an OWASP headers error, check out this [document](/docs/zoom-apps/security/owasp/).

    To potentially save you some time, here is a working [ngrok](https://ngrok.com/) command to set the correct headers:

    ```shell
    ngrok http 4000 --response-header-add "content-security-policy: self;" --response-header-add "Strict-Transport-Security: max-age=31536000" --response-header-add "X-Content-Type-Options: nosniff" --response-header-add "Referrer-Policy: origin"
    ```

![](/img/appshortcuts.png)

### Client side:

```html
<p>Some text</p>
```

![](/img/shortcut-webview.png)

## Apps SDK

To use the Apps SDK inside your shortcut WebView, navigate to the Features -> Surface page. Then toggle Zoom Apps SDK.

Then, add the following APIs: `getRunningContext`, `getChatContext`, `composeCard`, `sendMessageToChat`.

![](/img/shortcuts-appssdk.png)

### Message shortcut

Here is an example shortcut on an existing message that reverses it.

**Client side:**

```javascript
import zoomSdk from "@zoom/appssdk";

zoomSdk
    .config({
        version: "0.16.26",
        capabilities: [
            "getRunningContext",
            "getChatContext",
            "composeCard",
            "sendMessageToChat",
        ],
    })
    .then((appInfo) => {
        if (appInfo.runningContext === "inChat") {
            zoomSdk.getChatContext().then((chatContext) => {
                if (chatContext.compose) {
                    // compose shortcut
                } else {
                    // existing message shortcut
                    zoomSdk.sendMessageToChat({
                        message: chatContext.content
                            .split("")
                            .reverse()
                            .join(""),
                    });
                }
            });
        }
    });
```

![](/img/shortcut-reverse-message.png)

### Compose shortcut

Here is an example shortcut in the compose box that takes the content of the compose box, reverses it, and attaches it as a Zoom Chat card message type. Due note, the `zoomSdk.composeCard()` function requires additional validation including a signature and timestamp that must be generated on the server side..

**Client side:**

```javascript
import zoomSdk from "@zoom/appssdk"

zoomSdk.config({
  version: '0.16.26',
  capabilities: ['getRunningContext', 'getChatContext', 'composeCard', 'sendMessageToChat']
}).then((appInfo) => {
  if(appInfo.runningContext === "inChat") {
    zoomSdk.getChatContext().then((chatContext) => {
      if(chatContext.compose) {
        // compose shortcut

        var content = JSON.stringify({
          "content": {
            "head": {
              "text": "A title",
              "sub_head": {
                "text": "A description"
              }
            },
            "body": [
              {
                "type": "message",
                "text": chatContext.content.split("").reverse().join("")
              }
            ]
          }
        })

        // generate signature and timestamp by encrypting content body on server side, example below
        // API request from client side to server side to generateSignature(content)

        zoomSdk.composeCard({
          "type": 'interactiveCard',
          "message": content,
          "signature": body.signature,
          "timestamp": body.timestamp,
          "previewCard": JSON.stringify({ "title": "A title", "description": "A description" })
        })
      } else {
        // existing message shortcut
        zoomSdk.sendMessageToChat({ message: chatContext.content.split("").reverse().join("") }
      }
    })
  }
})
```

**Server side:**

```javascript
import crypto from "crypto";

function generateSignature(content) {
    const timestamp = Date.now().toString();
    const message = `v0:${timestamp}:${JSON.stringify(content)}`;

    const hashForVerify = crypto
        .createHmac("sha256", process.env.ZOOM_CLIENT_SECRET)
        .update(message)
        .digest("hex");

    const signature = `${hashForVerify}`;

    const body = {
        signature: signature,
        timestamp: timestamp,
    };

    return body;
}

generateSignature(content);
```

**Message preview:**

![](/img/shortcut-reverse-compose-preview.png)

**Zoom Chat card message:**

![](/img/shortcut-reverse-compose.png)

For a full example on App Shortcuts and Apps SDK, check out this [sample](https://github.com/zoom/team-chat-shortcut-sample).
