Mattermost incoming webhook for Sume jobs: markdown, 16,383 chars
Post a Sume job result to Mattermost with an incoming webhook: text is markdown, attachments sit at top level, and posts up to 16,383 characters are supported.

A Mattermost incoming webhook takes a JSON body with a text field written in markdown, so a Sume job result fits in one short message: the job id, the status and the artifact link. Mattermost documents support for posts of up to 16,383 characters, and says that longer text is split into several posts. That is far more than a link needs.
What Mattermost documents
The incoming webhook page is short, and these are the points that matter for a job notifier.
| Topic | Mattermost documents |
|---|---|
| Body | JSON with a text field |
| Formatting | text is markdown |
| Attachments | Must be top-level in the JSON, not nested in another object |
| Length | Posts up to 16,383 characters; longer text is split |
| Rate limit | None documented on that page |
Sume payload in, markdown out
A Sume job webhook has event, job_id, status (OK or ERROR) and payload.artifacts[]. Verify the signature first. The header is x-sume-webhook-signature: sume-v1=<hex>, an HMAC-SHA256 over <timestamp>.<raw_body>; the SDK ships verifyWebhook. Then build the markdown.
import json, urllib.request
def to_markdown(event: dict) -> str:
arts = (event.get("payload") or {}).get("artifacts") or []
lines = ["**Sume job** `%s` is %s" % (event["job_id"], event["status"])]
for a in arts:
lines.append("- [%s](%s)" % (a.get("type", "file"), a["url"]))
return "\n".join(lines)
def post(hook_url: str, event: dict) -> None:
body = json.dumps({"text": to_markdown(event)}).encode()
req = urllib.request.Request(hook_url, data=body,
headers={"Content-Type": "application/json"})
urllib.request.urlopen(req, timeout=8).read()No documented rate limit is not no limit
Mattermost does not state a rate limit on that page, but your server and any proxy in front of it may have one. Sume sends terminal events only, one per job, and retries a failed delivery up to 10 times at 30 second spacing by default. If many jobs finish at once, put a queue between the receiver and Mattermost, return 2xx to Sume first, and post at a modest pace.
Limits
The webhook can only post, so it cannot update the message when a job changes state. A failed job arrives as status: "ERROR" with no artifacts; show the id and an error line. Do not paste the Sume API key or the signing secret into a message, and do not include private prompts in a shared channel.
Before you ship
- Post the artifact URL, not the file bytes.
- Include the job id so a person can ask for a Redeliver.
- Keep attachments at the top level of the JSON.
- Treat the webhook URL as a secret.
- Verify the Sume signature before you build any message.
- Skip the post for events you do not need, such as test deliveries.
Sources
Related posts
More in Integrations
- MCP agent: trim, then captions? video-captions create is not listed
On Sume's hosted MCP, video_trim is a listed tool but captions are not creatable from tools_list. Use the REST endpoint for the burn step in an agent chain.
- Sume MCP allow_write and allow_paid: accepted, not required, no bypass
Old agent prompts still send allow_write and allow_paid to Sume MCP. The server accepts both, but only the OAuth scope or an API key grants access.
- MCP conflicting_payload_fields: image_url or avatar_id, not both
Sume's avatar-image-to-video_create and kling-motion-control_create take image_url XOR avatar_id or avatar_handle. Both returns conflicting_payload_fields.
- Sume MCP OAuth opens a consent page on mcp.sume.com, not app.sume.com
Hosted Sume MCP sign-in redirects to a consent page on the MCP host with Read locked on and a Write toggle off. Do not point clients at app.sume.com or www.
Written by Sume