Check a callback_url is public HTTPS before you submit a Sume video

Sume's callback_url must be public HTTPS. A Python pre-check rejects http, embedded credentials, unresolvable hosts and private addresses before you pay.

5 min readSume
All posts

Reject any callback_url that is not https, that carries credentials in the URL, or that resolves to a non-public address, before you call POST /v1/videos. Sume documents callback_url as public HTTPS only, and a pre-check turns a late 400 into an immediate, readable message in your own code.

This matters in a migration because OpenAI lists the Videos API as removed on 2026-09-24, so ported code sends the callback with each request. That URL comes from config, and config is where http://localhost values hide.

What counts as public

The Sume docs say the callback URL must be public HTTPS and describe delivery as up to 10 attempts at a fixed 30-second spacing with a 10-second timeout each. A URL that points at your laptop, at a private network address or at a hostname that only resolves inside your VPC cannot receive any of those attempts.

Python's ipaddress module has an is_global flag that is false for loopback, private ranges, link-local and other reserved blocks, so one attribute covers all of them. Check every address the hostname resolves to, not just the first.

Cases the pre-check rejects (Sume docs, read 2026-10-05)
callback_urlResultReason
http://example.com/hookrejectnot https
https://127.0.0.1/hookrejectloopback is not global
https://10.0.0.5/hookrejectprivate range
https://user:pw@example.com/hookrejectembedded credentials
https://hooks.example.com/sumeacceptpublic https host, if it resolves to global addresses

The check

The function returns a message string for a problem and None when the URL passes. It needs DNS, so the last case in a sandbox without a network may report that the host does not resolve; that is the correct answer there. Call it where you build the request, and fail the row before the submit.

import ipaddress, socket
from urllib.parse import urlparse

def check_callback(url):
    u = urlparse(url)
    if u.scheme != "https":
        return "callback_url must be https"
    if not u.hostname or u.username or u.password:
        return "callback_url needs a plain host"
    try:
        infos = socket.getaddrinfo(u.hostname, u.port or 443, proto=socket.IPPROTO_TCP)
    except socket.gaierror:
        return "host does not resolve"
    for info in infos:
        ip = ipaddress.ip_address(info[4][0])
        if not ip.is_global:
            return f"{ip} is not a public address"
    return None

if __name__ == "__main__":
    for url in ["http://example.com/hook", "https://127.0.0.1/hook",
                "https://user:pw@example.com/hook", "https://10.0.0.5/hook"]:
        print(url, "->", check_callback(url))

Limits of a pre-check

DNS answers change. A hostname can be public when you check and point elsewhere later, and the check says nothing about whether your endpoint is up. Treat it as a guard against configuration mistakes, not as a security control, and keep your receiver's own verification of the signature, which the webhook docs describe as HMAC-SHA256 over the timestamp and raw body.

Also keep polling as the backstop. If a callback never arrives, the job still finishes, and a poll of GET /v1/videos/{id} will show it.

  • Run the check in config load for static URLs, and per request for dynamic ones.
  • Log the failing message but not the full URL if it carries a token in the path.
  • Use a stable tunnel for development; the stored posts on tunnels cover the options.

Where it fits in the submit path

Run the callback check first, then the catalog check, then the submit. Order matters only for cost of failure: the callback check is local and instant, the catalog check is one free read, and the submit is the first call that can bill. If every earlier check passes, the remaining failures are things only the provider can tell you, such as a capacity error, and those belong in a retry policy rather than in validation.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume