Asana webhooks for Sume: handshake, compact payloads, task-keyed job
Asana needs the X-Hook-Secret echoed within 10 seconds and sends compact payloads. Fetch the task, then submit to Sume with a key built from the task gid.

An Asana webhook does not hand you the task, only a compact event, so the handler has to fetch the task from Asana before it can build a Sume prompt. Complete the X-Hook-Secret handshake inside 10 seconds, ack every later delivery quickly, and submit to Sume with an Idempotency-Key made from the task gid so repeated events collapse into one job.
This post covers the Sume side and the delivery rules. It does not give signature code, because the Asana page names an HMAC-SHA256 X-Hook-Signature but does not say how the digest is encoded, and a verifier guessed from that would be wrong half the time.
Delivery rules worth designing around
The handshake: when you create the webhook, Asana sends a request with an X-Hook-Secret header, and your endpoint must echo it in the response with a 200 or 204 within 10 seconds, or creation fails. After that, events arrive with an X-Hook-Signature header computed from the body and that secret.
Asana retries failed deliveries for up to 24 hours and then deletes the webhook, and it sends a heartbeat roughly every 8 hours so you can tell the hook is alive. Payloads are described as compact, meaning an event names a resource and an action rather than carrying the full record. Hence the two-step flow: receive a change event for a task, call Asana for the task fields, then call Sume.
| Asana rule | Value | Design consequence |
|---|---|---|
| Handshake | Echo X-Hook-Secret with 200/204 in 10 seconds | Make the endpoint cold-start safe |
| Retries | Up to 24 hours, then the webhook is deleted | Return 2xx fast; queue the work |
| Heartbeat | About every 8 hours | Treat silence beyond that as a broken hook |
| Payload | Compact event, not the full task | Fetch the task before prompting |
| Repeats | Several events can name the same task | Key the Sume job by task gid |
Submitting from a task
After you have fetched the task, call Sume with a key tied to the task gid. If you also want a new job when the task's brief changes, add a short hash of the brief to the key; leave it out for one-image-per-task.
import os, requests
def submit_for_task(task_gid: str, name: str, notes: str) -> str:
r = requests.post(
"https://api.sume.com/v1/images",
headers={
"Authorization": f"Bearer {os.environ['SUME_API_KEY']}",
"Idempotency-Key": f"asana-{task_gid}",
},
json={"model": "sume/auto", "mode": "async",
"prompt": f"{name}. {notes}"[:1500]},
timeout=20,
)
r.raise_for_status()
data = r.json()["data"]
return data["job"]["id"]Writing the result back
Do the write-back to Asana from your Sume webhook receiver, not from this function, and keep the task gid in your own table next to the Sume job id. The Sume event names the job, not the Asana task, and you want that lookup to be a database read, not a search. Because Asana deletes a hook that fails for 24 hours, keep the Asana endpoint thin and let your own queue absorb Sume and Asana API slowness.
Sources
Related posts
More in Integrations
- Chatbox MCP one-click install link for Sume (base64 deep link)
Chatbox documents a chatbox://mcp/install deep link carrying a base64 server config. Build one for Sume's hosted MCP URL and know what the page leaves out.
- ChatGPT desktop app and Codex share one MCP config: add Sume
OpenAI says the ChatGPT desktop app, Codex CLI and IDE extension share one config.toml. Add Sume once with a url, plus the 60 second tool timeout to check.
- ChatGPT Plugins: Public endpoint or Secure MCP Tunnel for Sume?
Sume's MCP server is already public at mcp.sume.com/mcp, so pick Public endpoint in ChatGPT. The Secure MCP Tunnel is for servers that are not exposed.
- Claude allowedPluginMcpServers and denied list for Sume URL
Claude admins can allow or deny plugin MCP servers by URL pattern. How to allow mcp.sume.com/mcp and what a deny match does even when allowed.
Written by Sume