Skip to content

Commit 0561595

Browse files
authored
Merge pull request #58 from webex/playbook/webhook-to-card
Add webhook-to-card playbook (WebexSamples sample)
2 parents eba181f + 319ecf7 commit 0561595

10 files changed

Lines changed: 543 additions & 0 deletions

File tree

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
# APPHUB.yaml — Playbook metadata for Webex App Hub
2+
# Copy this file into your Playbook folder under playbooks/<tool-slug>/
3+
# Fill in all required fields. See CONTRIBUTING.md for field rules.
4+
5+
# -----------------------------------------------------------------------------
6+
# friendly_id — Unique identifier. Must end with -playbook (e.g. epic-ehr-playbook)
7+
# -----------------------------------------------------------------------------
8+
friendly_id: "webhook-to-card-playbook"
9+
10+
# -----------------------------------------------------------------------------
11+
# title — Display name for the Playbook (matches ContentStack field)
12+
# -----------------------------------------------------------------------------
13+
title: "Incoming Webhook to Webex Messaging Adaptive Card"
14+
15+
# -----------------------------------------------------------------------------
16+
# tag_line — Short tagline for App Hub detail page (required, max 128 chars)
17+
# -----------------------------------------------------------------------------
18+
tag_line: "Receive HTTP webhooks and post Adaptive Card messages to Webex Messaging spaces with a bot"
19+
20+
# -----------------------------------------------------------------------------
21+
# description — App Hub listing / detail copy (markdown supported where CMS renders it)
22+
# -----------------------------------------------------------------------------
23+
description: |
24+
**Bring external events into Webex Messaging without a custom client.** Monitoring tools, CI/CD
25+
pipelines, ticketing systems, and internal services already speak HTTP and JSON. This Playbook
26+
shows how to turn those **webhook payloads** into **Adaptive Card** messages—structured facts,
27+
images, and action buttons—delivered to a **space** by a **bot** using the public Messages API.
28+
29+
**Why use this**
30+
31+
- **Meet people where they work:** Operators and stakeholders stay in Webex instead of checking
32+
another dashboard or email filter.
33+
- **Richer than plain text:** Cards summarize context at a glance and can link out to runbooks,
34+
tickets, or live views.
35+
- **Small, inspectable surface:** A single Flask route and a bot token are enough to prototype;
36+
you can harden auth, signing, and hosting once the flow is proven.
37+
38+
**What you get**
39+
40+
Sample **Python** code (`POST /webhook`), environment-based configuration, a worked **rocket-launch**
41+
JSON shape you can replace with your own fields, and a deployment guide aligned with
42+
[WebexSamples/webhook-to-card](https://github.com/WebexSamples/webhook-to-card).
43+
44+
# -----------------------------------------------------------------------------
45+
# product_types — Where this Playbook appears. Pick one or more.
46+
# Valid: teams | meetings | calling | rooms | contact_center
47+
# -----------------------------------------------------------------------------
48+
product_types:
49+
- "teams"
50+
51+
# -----------------------------------------------------------------------------
52+
# app_context — Where the integration runs. Pick one or more.
53+
# Valid: space | in_meeting | call | device | contact_center | sidebar | mcp | a2a
54+
# -----------------------------------------------------------------------------
55+
app_context:
56+
- "space"
57+
58+
# -----------------------------------------------------------------------------
59+
# categories — App Hub category slugs. Pick one or more.
60+
# Verticals: healthcare | financial-services | retail-ecommerce
61+
# App categories (use kebab-case slugs):
62+
# ai-agent-testing-observability | agent-supervisor-tools | analytics |
63+
# calendar-scheduling | collaboration-management | customer-relations |
64+
# customer-support | developer-tools | doc-management | education |
65+
# finance | government | healthcare | human-resources | internet-of-things |
66+
# marketing-sales | orchestration | platform | productivity |
67+
# project-management | recording-transcriptions | security-compliance |
68+
# self-service-bots | social-and-fun | strategy-team-planning |
69+
# workflow-automation | workforce-optimization | other
70+
# -----------------------------------------------------------------------------
71+
categories:
72+
- "developer-tools"
73+
- "workflow-automation"
74+
- "productivity"
75+
76+
# -----------------------------------------------------------------------------
77+
# company_name — Your company or team name
78+
# -----------------------------------------------------------------------------
79+
company_name: "Webex for Developers"
80+
81+
# -----------------------------------------------------------------------------
82+
# company_url — Your company or project URL
83+
# -----------------------------------------------------------------------------
84+
company_url: "https://developer.webex.com"
85+
86+
# -----------------------------------------------------------------------------
87+
# support_url — Issues or support link (e.g. GitHub issues)
88+
# -----------------------------------------------------------------------------
89+
support_url: "https://github.com/webex/WebexPlaybooks/issues"
90+
91+
# -----------------------------------------------------------------------------
92+
# product_url — Link to this Playbook in the repo (required)
93+
# -----------------------------------------------------------------------------
94+
product_url: "https://github.com/webex/WebexPlaybooks/tree/main/playbooks/webhook-to-card"
95+
96+
# -----------------------------------------------------------------------------
97+
# logo — (Optional) URL to your logo image. If not provided, defaults to the
98+
# standard Webex Playbook logo.
99+
# -----------------------------------------------------------------------------
100+
logo: "https://images.contentstack.io/v3/assets/bltd14fd2a03236233f/blta2de9daa773c6604/60f71f81e2de935fc7e35dbe/download"
101+
102+
# -----------------------------------------------------------------------------
103+
# estimated_implementation_time — e.g. "2-4 hours", "1 day"
104+
# -----------------------------------------------------------------------------
105+
estimated_implementation_time: "1-2 hours"
106+
107+
# -----------------------------------------------------------------------------
108+
# third_party_tool — (Optional) The tool being integrated (e.g. Salesforce, Epic)
109+
# Omit for generic playbooks (e.g. "any CMS")
110+
# -----------------------------------------------------------------------------
111+
third_party_tool: "HTTP webhooks"
112+
113+
# -----------------------------------------------------------------------------
114+
# privacy_url — Privacy policy URL (required; use Cisco default for Webex-authored)
115+
# -----------------------------------------------------------------------------
116+
privacy_url: "https://www.cisco.com/c/en/us/about/legal/privacy-full.html"
117+
118+
# -----------------------------------------------------------------------------
119+
# submission_date — (Optional) ISO date (e.g. 2025-03-01)
120+
# -----------------------------------------------------------------------------
121+
submission_date: "2026-04-01"
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
# Incoming Webhook to Webex Messaging Adaptive Card
2+
3+
This Playbook is adapted from the [Webhook to Adaptive Card](https://github.com/WebexSamples/webhook-to-card) sample on GitHub.
4+
5+
## Use Case Overview
6+
7+
Operations and platform teams often want **alerts and structured updates** in Webex spaces without building a full custom integration UI. A small **HTTP webhook** receiver can accept JSON from monitoring systems, CI/CD, or internal tools and **post a rich Adaptive Card** so members see facts, images, and action buttons in the client.
8+
9+
This sample uses a **rocket launch** themed payload as a teaching example; the same pattern applies to any JSON you map into card elements. The target persona is a **Webex developer** who can create a bot, add it to a space, and run Python locally or in a container. Expect roughly **1–2 hours** to configure tokens, expose the webhook URL (for example with a tunnel), and verify an end-to-end post.
10+
11+
## Architecture
12+
13+
An **external system** sends `POST /webhook` with JSON. The **Flask** app validates the body, builds an **Adaptive Card** object in memory, and calls the Webex **Messages** API (`POST https://webexapis.com/v1/messages`) with a **bot access token** and **room ID**. Webex delivers the message (including the card attachment) to the **space** where the bot is a member.
14+
15+
Authentication to Webex is **Bearer token** (bot). The inbound webhook endpoint in this sample does **not** verify caller identity; protect it in production (network rules, shared secrets, signatures).
16+
17+
For a sequence view of the flow, see [diagrams/architecture-diagram.md](diagrams/architecture-diagram.md). Upstream file layout and license notes are summarized in [docs/upstream-overview.md](docs/upstream-overview.md).
18+
19+
## Prerequisites
20+
21+
- **Webex**
22+
- Ability to create or use a **bot** at [developer.webex.com](https://developer.webex.com).
23+
- A **bot access token** with permission to post messages in the target space.
24+
- A **Webex space** and its **room ID**; the bot must be **added as a member**.
25+
26+
- **Runtime**
27+
- **Python 3.9+** recommended (3.6+ may work with the pinned dependencies; prefer a supported Python release).
28+
- `pip` for installing `src/requirements.txt`.
29+
30+
- **Network**
31+
- **Outbound HTTPS** from the app host to `webexapis.com`.
32+
- For external systems to call your app, a **reachable URL** (public host, reverse proxy, or tunnel such as ngrok). Configure your webhook sender to POST to `https://<your-host>/webhook`.
33+
34+
## Code Scaffold
35+
36+
Under `src/`:
37+
38+
- **`app.py`** — Flask app: `POST /webhook` builds the card and posts to Webex; `GET /status` returns a minimal HTML line. Uses `WEBEX_BOT_TOKEN`, `WEBEX_ROOM_ID`, and optional `PORT`. Request bodies are capped at 256 KiB.
39+
- **`requirements.txt`** — Pinned dependencies (Flask, requests, python-dotenv, etc.).
40+
- **`templates/status.html`** — Static text for the status route.
41+
- **`webhook-payload.json`** — Example JSON for local `curl` tests.
42+
- **`adaptive_card.json`** — Reference card JSON (the live path builds the card in code).
43+
- **`env.template`** — Required environment variables; copy to `.env` beside `app.py`.
44+
45+
The code demonstrates **documented Webex Messaging with Adaptive Cards**. It does **not** provide inbound webhook authentication, URL allowlisting for images/links, high availability, or comprehensive error handling—treat it as a **learning scaffold**, not a production service.
46+
47+
## Deployment Guide
48+
49+
1. **Open a terminal** at the Playbook’s `src` directory:
50+
```bash
51+
cd playbooks/webhook-to-card/src
52+
```
53+
54+
2. **Create and activate a virtual environment** (recommended):
55+
```bash
56+
python3 -m venv .venv
57+
source .venv/bin/activate
58+
```
59+
60+
3. **Install dependencies:**
61+
```bash
62+
pip install -r requirements.txt
63+
```
64+
65+
4. **Create a Webex bot** at [developer.webex.com](https://developer.webex.com) and copy the **bot access token**.
66+
67+
5. **Create or open a Webex space**, add the bot, and copy the space **Room ID**.
68+
69+
6. **Configure environment variables:**
70+
```bash
71+
cp env.template .env
72+
```
73+
Edit `.env` and set `WEBEX_BOT_TOKEN` and `WEBEX_ROOM_ID`. Optionally set `PORT` (default `5000`).
74+
75+
7. **Run the application:**
76+
```bash
77+
python app.py
78+
```
79+
80+
8. **Verify the service** (from another terminal):
81+
```bash
82+
curl -s http://127.0.0.1:5000/status
83+
```
84+
85+
9. **Send a test webhook** (adjust host/port if needed). The bundled `webhook-payload.json` uses **HTTPS URLs Webex can fetch** for the card image and open-link action. If `mission_patch` points at a host that does not return a real image (for example `https://example.com/...`), the Messages API responds with **Unable to retrieve content** because Webex retrieves image URLs when creating the message.
86+
```bash
87+
curl -s -X POST -H "Content-Type: application/json" \
88+
-d @webhook-payload.json \
89+
http://127.0.0.1:5000/webhook
90+
```
91+
Expect `{"success":true}` when the bot token and room ID are valid. A JSON body with `"success":false` and a nested `Unable to retrieve content` message usually means an image URL in the payload is missing, blocked, or not a valid image—fix `mission_patch` and retry.
92+
93+
10. **Confirm in Webex** that the space received a message with the Adaptive Card.
94+
95+
11. **Optional — expose to the internet:** Run a TLS-terminated reverse proxy or tunnel, then register the public `https://.../webhook` URL with the system that sends webhooks.
96+
97+
## Known Limitations
98+
99+
- **Inbound webhook security:** The sample does **not** authenticate or sign webhook requests. Anyone who can reach `/webhook` can trigger a post to your configured space. Use network restrictions, tokens, or signatures before production use.
100+
101+
- **Payload shape:** The handler expects the **rocket launch** field names shown in `webhook-payload.json`. Extending to other events requires code changes or additional routes.
102+
103+
- **Images and links:** `mission_patch` and `video_stream` are passed through to the card. **Webex fetches `mission_patch` server-side** when posting; it must be **HTTPS** and return a **reachable, valid image** or the API returns errors such as **Unable to retrieve content**. Untrusted URLs may affect clients; validate or allowlist in production.
104+
105+
- **Bot token:** Treat the bot token as a secret; rotate it if exposed. The sample does not implement OAuth or Integration refresh flows.
106+
107+
- **Dependencies:** Pins match the upstream sample; upgrade paths and compatibility testing are your responsibility.
108+
109+
- **License:** The upstream sample is under the **Cisco Sample Code License**. This repository’s licensing for contributed material is described in the root [LICENSE](../../LICENSE). This Playbook is provided as a starting point. Webex does not guarantee the functional accuracy of the source code. Test thoroughly before use in a production environment.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Architecture — Incoming Webhook to Webex Messaging Adaptive Card
2+
3+
External systems can signal events with HTTP POSTs. This sample turns a structured JSON payload into a **Webex message** that includes an **Adaptive Card** attachment.
4+
5+
```mermaid
6+
sequenceDiagram
7+
participant Ext as ExternalSystem
8+
participant App as FlaskWebhookApp
9+
participant Api as WebexMessagesAPI
10+
participant Space as WebexSpace
11+
Ext->>App: POST /webhook JSON payload
12+
App->>App: Validate body build AdaptiveCard
13+
App->>Api: POST /v1/messages Bearer bot token
14+
Api->>Space: Message with card attachment
15+
```
16+
17+
Authentication: the **Webex bot token** is stored server-side (environment only). Callers of `/webhook` are **not** authenticated in this sample.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Upstream sample notes
2+
3+
This Playbook vendors code adapted from [WebexSamples/webhook-to-card](https://github.com/WebexSamples/webhook-to-card).
4+
5+
## Layout in the upstream repo
6+
7+
- `app.py` — Flask routes `/webhook` and `/status`
8+
- `requirements.txt` — Python dependencies
9+
- `templates/status.html` — Simple status line for `/status`
10+
- `webhook-payload.json` — Example POST body for local testing
11+
- `adaptive_card.json` — Static example of the card shape (the app builds the card in code)
12+
- `.env.example` — Environment variable names
13+
14+
## Sample image URLs in `webhook-payload.json`
15+
16+
The upstream sample uses `https://example.com/...` for `mission_patch` and `video_stream`. Those hosts do not serve real card assets; Webex returns **Unable to retrieve content** when it cannot fetch the **Image** URL. This Playbook’s `webhook-payload.json` uses public HTTPS URLs that work for local testing.
17+
18+
## Environment variable name
19+
20+
Upstream uses **`WEBEX_BOT_TOKEN`** consistently in `.env.example` and `app.py`. Some narrative docs elsewhere may mention `WEBEX_ACCESS_TOKEN`; this Playbook standardizes on **`WEBEX_BOT_TOKEN`** (see `src/env.template`).
21+
22+
## License
23+
24+
The upstream project uses the **Cisco Sample Code License**. See the upstream repository for the full text.
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
{
2+
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
3+
"type": "AdaptiveCard",
4+
"version": "1.3",
5+
"body":
6+
[{
7+
"type": "TextBlock",
8+
"text": "Rocket Launch Successful!",
9+
"weight": "Bolder",
10+
"size": "Large",
11+
"color": "Accent",
12+
"wrap": true
13+
},
14+
{
15+
"type": "ColumnSet",
16+
"columns": [
17+
{
18+
"type": "Column",
19+
"width": "auto",
20+
"items": [
21+
{
22+
"type": "Image",
23+
"url": "https://adaptivecards.io/content/cats/1.png",
24+
"size": "Small",
25+
"style": "Person"
26+
}
27+
]
28+
},
29+
{
30+
"type": "Column",
31+
"width": "stretch",
32+
"items": [
33+
{
34+
"type": "TextBlock",
35+
"text": "Rocket Launch Details",
36+
"weight": "Bolder",
37+
"wrap": true
38+
},
39+
{
40+
"type": "FactSet",
41+
"facts": [
42+
{
43+
"title": "Rocket Name",
44+
"value": "Falcon 9"
45+
},
46+
{
47+
"title": "Payload Type",
48+
"value": "Satellite"
49+
},
50+
{
51+
"title": "Payload Description",
52+
"value": "Communications satellite for commercial use"
53+
},
54+
{
55+
"title": "Launch Time",
56+
"value": "2023-03-25T16:30:00Z"
57+
},
58+
{
59+
"title": "Launch Site",
60+
"value": "Cape Canaveral, FL"
61+
}
62+
]
63+
}
64+
]
65+
}
66+
]
67+
}
68+
],
69+
"actions": [
70+
{
71+
"type": "Action.OpenUrl",
72+
"title": "Watch the Launch",
73+
"url": "https://developer.webex.com/docs/getting-started"
74+
}
75+
]
76+
}

0 commit comments

Comments
 (0)