Webhook URL rejected as invalid? Sume's webhook URL rules

Sume answers 400 invalid_request when a webhook URL is not public HTTPS. The rules for scheme, host, port, and credentials, and the check at delivery.

5 min readSume
All posts

Sume rejects a webhook URL with 400 invalid_request when it is not a public HTTPS URL. Plain http://, localhost, private-network addresses, and credentials in the URL are refused on every job and run, and current code also refuses a non-default port such as :8443. The check runs before anything is created, so fix the URL and submit again.

The documented rules come from Run webhooks, Runs and results, and Webhooks, read 2026-09-27. Rules marked as current code are read from the API source; the docs do not list them. Failed or missing deliveries after a URL was accepted are covered in Sume webhook not received?

Which webhook URLs does Sume refuse?

In current code one check covers webhook_url and its alias callback_url on generation jobs, including callback_url on POST /v1/videos, communication.webhook_url on Format, Action, and Agent Completion runs, and Send test. For hosts written as IP addresses, current code also refuses link-local addresses such as 169.254.169.254, carrier-grade NAT, multicast, and the IPv6 loopback, unique-local, and link-local ranges.

From Run webhooks, Runs and results, and Webhooks, plus current API code where marked, read 2026-09-27.
Webhook URLResultRule from
http://hooks.example.com/sume400: not HTTPSDocs
https://localhost/sume, https://127.0.0.1/sume400: localhostDocs
https://10.0.0.5/sume, https://192.168.1.20/sume400: private networkDocs
https://user:pass@hooks.example.com/sume400: credentials in the URLDocs (runs), current code (jobs)
A URL longer than 2048 characters400Docs
https://hooks.example.com:8443/sume400: a port other than the default 443Current code
https://api.default.svc.cluster.local/sume, https://host.docker.internal/sume400: a name ending in .local, .internal, .test, or .localhostCurrent code
https://hooks.example.com/sumeAcceptedDocs

What does the 400 response look like?

Every refusal is 400 invalid_request, but in current code the wording depends on the surface. Run creates and Send test name the field in the message and in details.field. Generation-job submits answer Invalid request body. and put the reason in details.errors[]: a path naming the field, and the message webhook_url must be a valid public HTTPS URL whichever field you used. Both are validation errors with retryable: false and next_action: fix_input, so sending the same URL again fails the same way. A run create's error, trimmed to the fields the docs show:

{
  "error": {
    "code": "invalid_request",
    "message": "webhook_url must be a public HTTPS URL without credentials or an explicit port.",
    "request_id": "req_…",
    "details": { "field": "webhook_url" }
  }
}

Why was a URL that works in my browser refused?

Reachable from your browser is not the same as allowed. Reasons to check:

  • It has a port. https://staging.example.com:8443/hooks may open in a browser, but current code refuses any port other than the default 443 and delivers on port 443. Serve the handler on the default HTTPS port.
  • It is an internal name, such as api.default.svc.cluster.local or host.docker.internal. Current code refuses names ending in .local, .internal, .test, or .localhost.
  • It uses plain HTTP, or puts a user and password in the URL. Sume signs its deliveries with HMAC-SHA256, so verify the signature instead; Signed webhooks for video runs shows how.
  • It is your own machine. The POST comes from Sume, so for local work put a public HTTPS tunnel in front of the handler, as in Test Sume webhooks locally.
  • The body disagrees with itself: webhook_url and callback_url with different values, or, on a job submit, mode: "webhook" with no URL. Both are 400 invalid_request too.

Is the URL checked again when Sume delivers?

Yes. The docs say the URL is re-validated as a public HTTPS URL at delivery time, and redirects are not followed: a 3xx is a failed attempt, so register the final URL. Current code also resolves the hostname at delivery, refuses the delivery if any address it resolves to is non-public, and connects only to the addresses it checked.

So a public-looking name that resolves to an internal address passes the submit and fails at delivery. The job or run keeps its real outcome, its webhook_delivery shows failed with the reason in last_error, and current code does not retry a blocked target. A name that does not resolve at all is treated as a transient failure and retried. Redeliver never sends to a different URL, so a corrected URL needs a new job or run.

How do I check a URL before I submit real work?

Use Send test, the control on /dashboard/webhooks or POST /v1/webhooks/test-deliveries with account:write; it never creates a job or run. It applies the same URL rules, so it answers 400 invalid_request for the same URLs. In current code it also runs the delivery-time DNS check: a name that resolves to a non-public address comes back with status_code: null and the reason in error. Sume webhook not received? covers the rest of its response.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume