FastAPI 0.142 native OpenTelemetry: tag spans with a Sume job id
FastAPI 0.142.0 added native OpenTelemetry. Put the Sume job_id on the current span in a webhook route so a failed render shows up next to the HTTP trace.

To find a slow or failed Sume render in your traces, add the Sume job_id as an attribute on the span that FastAPI 0.142 already creates for the request. The 0.142.0 release (2026-09-29) added native OpenTelemetry support, and the OpenTelemetry API lets any route read the current span with trace.get_current_span(). You add one line and no new library.
What the FastAPI releases say
The releases page lists five releases between 2026-09-29 and 2026-10-07, most of them about telemetry. They tell you that the feature is new and still moving, so pin the version and read each note before you upgrade.
| Version | Date | Release note |
|---|---|---|
| 0.142.0 | 2026-09-29 | Add native OpenTelemetry support |
| 0.142.1 | Date not read | Fix repeated endpoint wrapping in included routers |
| 0.142.2 | Date not read | Allow startup when automatic OTel config fails |
| 0.142.3 | 2026-10-07 | Cache OTel tracers |
| 0.142.4 | 2026-10-07 | Isolate telemetry for excluded requests |
Which Sume id to attach
A job webhook body has request_id and job_id, and the status URL for the job uses the same id. Put it on the span as sume.job_id, plus the event name, so a trace search by job id returns the delivery.
Run webhooks use the same signature scheme but carry request_id for dedupe. Attach whichever id the body has.
A webhook route that tags its span
The route below verifies the sume-v1 signature by hand. It accepts the comma-separated header that Sume sends during the 24 hour secret rotation, and it refuses an empty secret.
import hashlib, hmac, json, os, time
from fastapi import FastAPI, Request, HTTPException
from opentelemetry import trace
app = FastAPI()
def valid(body: bytes, ts: str, header: str, secret: str) -> bool:
if not secret or abs(time.time() - int(ts)) > 300:
return False
mac = hmac.new(secret.encode(), ts.encode() + b"." + body, hashlib.sha256).hexdigest()
sigs = [p.split("=", 1)[1] for p in header.split(",") if p.startswith("sume-v1=")]
return any(hmac.compare_digest(mac, s) for s in sigs)
@app.post("/hooks/sume")
async def sume(request: Request):
body = await request.body()
h = request.headers
secret = os.environ.get("SUME_COM_WEBHOOK_SIGNING_SECRET", "")
if not valid(body, h.get("x-sume-webhook-timestamp", "0"), h.get("x-sume-webhook-signature", ""), secret):
raise HTTPException(401)
event = json.loads(body)
trace.get_current_span().set_attribute("sume.job_id", event.get("job_id", ""))
return {"ok": True}Notes before you ship
How you turn the native instrumentation on is described in the FastAPI release notes, which this post does not repeat. The span call works with any OpenTelemetry SDK setup.
int(ts)raises on a bad header; wrap it if you do not trust the sender, or rely on the 401 path.- Dedupe on
job_idbefore you do work; Sume retries up to 10 times. - Exclude health checks from tracing; 0.142.4 isolates telemetry for excluded requests.
Finding the delivery later
Once the attribute is on the span, a trace search for sume.job_id returns the HTTP request, its duration and its status code. Sume shows each delivery with a status that moves through pending, delivering, retrying, delivered, failed or exhausted, and the signing-secret fingerprint. Put the two views side by side: if Sume says retrying and your trace shows a 401, the secret is wrong; if the trace shows nothing, the request never reached you.
A delivery that ended exhausted can be replayed with POST /v1/jobs/{job_id}/webhook/redeliver, which re-sends the real terminal event with a fresh signature and does not spend one of the 10 automatic attempts.
Add the job id and the event name. Do not add the body, the signature or the secret to a span, because trace backends keep attributes for a long time and often share them widely.
Sources
Related posts
More in Developers
- FastAPI background poll of a Sume job: use next_poll_after_seconds
Poll a Sume job from an asyncio task in a FastAPI 0.142 app, wait for the server-provided interval, stop at terminal, and never resubmit after a timeout.
- Fastify: verify a Sume video webhook where Sora's video.completed was
Swap the Sora video.completed handler for Sume's job.completed in Fastify. Keep the raw string body, verify sume-v1 with the SDK, and refuse an empty secret.
- Find the timestamp of a quote in a recording with Sume STT words
Sume's STT result returns every word with start and end seconds. A short Python function finds a quoted phrase and returns where to cut. About a cent a minute.
- First-frame image for /v1/videos: public HTTPS only, no signed URLs
Image and video inputs to Sume generation must be fetchable public HTTPS URLs. Localhost, private IPs, signed URLs and wrong content types are rejected.
Written by Sume