ChatGPT MCP events start automations: the Sume webhook and API trigger

ChatGPT plugins can use MCP events to start an automation. Sume's hosted MCP lists tools, so react with a signed run webhook or an API-trigger run.

5 min readSume
All posts

ChatGPT's release notes dated September 29, 2026 say supported plugins can use MCP events to start an automation when something changes in a connected app (OpenAI release notes, read 2026-10-04). Sume's hosted MCP documents tools, not an event or subscription surface, so a Sume job finishing does not arrive as an MCP event.

What Sume does ship for "tell me when it is done" is a signed webhook on every run, and an API trigger that starts a saved schedule from your own service.

What each side offers

The hosted MCP at https://mcp.sume.com/mcp exposes a tool inventory: discovery tools, jobs, assets, generation, crawl and media tools. Long jobs are read with jobs_status or jobs_wait, which holds up to 55 seconds per call (MCP tools and gates).

For work that finishes minutes later, the run surfaces accept communication.webhook_url. When a run completes or fails, Sume sends one signed POST with the same receipt the poll endpoint returns (Run webhooks).

Ways to learn that Sume work finished. Sources: OpenAI release notes and Sume docs, read 2026-10-04.
NeedWhere it livesSume option
Start work when an app changesChatGPT plugin MCP events, per OpenAI's notesYour service calls POST /v1/actions/{id}/runs on an API-trigger schedule
Know a short job is doneInside one assistant turnjobs_wait, up to 55 seconds per call
Know a long run is doneOutside the chatSigned webhook: action.run.terminal, format.run.terminal or agent.run.terminal

Verify the delivery before you trust it

Each delivery carries x-sume-webhook-timestamp and x-sume-webhook-signature: sume-v1=<hex>. The signature is HMAC-SHA256 over <timestamp>.<raw_body>. Verify against the raw bytes, reject a stale timestamp (five minutes is a reasonable window), and dedupe on the envelope request_id, which is stable across retries.

import hashlib, hmac, os, time

def verify(raw: bytes, ts: str, header: str, secret: str, window: int = 300) -> bool:
    if not secret:
        raise ValueError("signing secret is empty")
    try:
        stamp = int(ts)
    except ValueError:
        return False
    if abs(int(time.time()) - stamp) > window:
        return False
    mac = hmac.new(secret.encode(), f"{stamp}.".encode() + raw, hashlib.sha256)
    return hmac.compare_digest(header, "sume-v1=" + mac.hexdigest())

secret = os.environ.get("SUME_COM_WEBHOOK_SIGNING_SECRET") or "local-demo-secret"
body = b'{"event":"action.run.terminal","request_id":"demo"}'
ts = str(int(time.time()))
sig = "sume-v1=" + hmac.new(secret.encode(), f"{ts}.".encode() + body, hashlib.sha256).hexdigest()
print(verify(body, ts, sig, secret))

What the receiver should do

Return a 2xx quickly after recording the event, then process. Sume retries up to 10 attempts with a 10-second timeout each, and a 3xx counts as a failed attempt. Branch on outcome (ok, degraded or error) rather than status alone, and fetch the receipt from result_url if the payload arrives as null on overflow.

What not to build

Do not hold a chat turn open waiting for a long run, and do not paste the signing secret into a plugin. Read the secret from the Webhooks tab of the dashboard, or from GET /v1/webhooks/signing-secret with a key that carries account:read, and store it as SUME_COM_WEBHOOK_SIGNING_SECRET on the receiver only.

Compare the x-sume-webhook-secret-fingerprint header with the fingerprint shown next to the secret if verification fails. It confirms both sides hold the same secret without sending it anywhere.

Sources

Related posts

More in Integrations

All Integrations posts

Written by Sume