What each status code means when a webhook or a scheduled request gets it back, what to fix, and whether retrying will help.
Worked Retry Retry after a wait Fix before retrying Not a final answer
Interim answers while a request is still in progress. Your HTTP client handles them, so you rarely see one as the final status.
The server has the request headers and the client can send the body.
HTTP clients deal with this for you. If a tool reports it as the final status, the request never finished.
Not a final answer
The server agreed to switch protocols, usually to a WebSocket.
Not something a webhook or scheduled request should get. Check that the URL is an HTTP endpoint and not a WebSocket one.
Not a final answer
The server sends link headers early so a browser can start loading assets.
Meant for browsers. Your client skips it and waits for the real status.
Not a final answer
The request worked. Any status from 200 to 299 counts as a success, including for Delay.
The request worked and the response has a body.
The normal answer from a webhook receiver or a cron endpoint.
Worked
The request worked and created something, often with its URL in the Location header.
A common answer to a POST. Senders treat it as success.
Worked
The server accepted the request and will process it later.
A good answer for an endpoint that queues slow work and replies right away, so the caller never times out. It says nothing about whether the work itself later succeeds.
Worked
The request worked and there is no body.
Fine for a webhook receiver that has nothing to say back.
Worked
The response is part of the resource, for a request with a Range header.
Unusual for webhooks. You only get it if the request asked for a byte range.
Worked
The resource is somewhere else, named in the Location header. Many webhook senders and schedulers, Delay included, don't follow redirects for these calls, so a redirect counts as a failure until the URL is fixed.
The URL moved for good. The Location header has the new one.
Update the URL you call to the one in Location. The usual causes are http instead of https, a missing or extra trailing slash, or www.
Fix before retrying
The resource is at another URL for now.
Often a login redirect: the route sits behind session authentication and sends unauthenticated requests to /login. Exclude the route from that middleware and check a token or signature instead.
Fix before retrying
The server wants the client to fetch another URL with GET, typically after a form POST.
The URL points at a web form handler. Call an API route that answers the request directly.
Fix before retrying
The cached copy is still current. Only sent when the request had If-None-Match or If-Modified-Since.
Only happens if your request sends conditional headers. Remove them if you want the full response every time.
Worked
Like 302, but the client must repeat the same method and body at the new URL.
Call the URL in Location, or fix the server so the original URL answers.
Fix before retrying
Like 301, but the client must repeat the same method and body at the new URL.
Update the URL you call to the one in Location.
Fix before retrying
The server refused the request as sent. Sending the same request again gets the same answer, except for 408, 425 and 429.
The server couldn't read the request or rejected it as malformed.
Check the body and the Content-Type header: invalid JSON and a body that doesn't match its declared type are the usual causes. The response body often says what is wrong.
Fix before retrying
The request had no valid credentials.
Check the Authorization header or API key, and whether a token expired. For a signed webhook, the receiver's signature check failed: compare secrets, and make sure it verifies the raw body before parsing it.
Fix before retrying
The server knows who is asking but won't allow it.
Check the key's permissions and any IP allow list. A firewall or bot protection (Cloudflare's, for example) can also block server-to-server calls with a 403.
Fix before retrying
Nothing answers at that URL.
Look for a typo, a route that isn't deployed yet, the wrong environment, or a trailing slash the router doesn't accept.
Fix before retrying
The URL exists, but not for that HTTP method. The Allow header lists the methods it takes.
Send the method the route expects, usually POST instead of GET or the other way round.
Fix before retrying
The server can't produce a response in a format the Accept header asks for.
Send Accept: application/json, or */*.
Fix before retrying
The server gave up waiting for the request to arrive.
Usually a slow or dropped connection on the way. A retry normally gets through.
Retry
The request conflicts with the current state, such as a duplicate or a version clash.
Many endpoints answer 409 to a delivery they already processed. If yours does, the work is done and there is nothing to retry.
Fix before retrying
The resource was removed on purpose and won't come back.
Stop calling the URL, or replace it with the new one.
Fix before retrying
The server needs a Content-Length header.
Rare. Send the body with a known length instead of streaming it.
Fix before retrying
The body is bigger than the server accepts.
Send a smaller payload, such as an ID instead of the full record, or raise the limit. nginx allows 1 MB by default (client_max_body_size).
Fix before retrying
The URL is longer than the server accepts.
Usually a GET with a large query string. Move the data into a POST body.
Fix before retrying
The server doesn't accept the body's format.
Set Content-Type to match the body, usually application/json.
Fix before retrying
An April Fools' code from RFC 2324. Some servers use it to turn away traffic they think is a bot.
If you get it from a real API, you are being blocked. Check the User-Agent and any bot protection.
Fix before retrying
The request is well formed but fails validation.
Laravel, Rails and many APIs use it for validation errors, and list the invalid fields in the body. Fix the payload.
Fix before retrying
The server won't process a request sent in TLS early data, in case it is replayed.
Retry on a normal connection. Clients handle this rarely, so it usually means a proxy setting.
Retry
The server requires a conditional request, such as one with If-Match.
Fetch the resource, then send its ETag in If-Match with the change.
Fix before retrying
The client is rate limited.
Wait as long as the Retry-After header says. If scheduled jobs trip it, spread them out instead of starting them all at the top of the hour, or call less often.
Retry after a wait
The headers are bigger than the server accepts.
Usually a large cookie or token. Send only the headers the endpoint needs.
Fix before retrying
The server can't serve this for legal reasons, such as a court order or sanctions.
Nothing to fix on your side. The resource isn't available where the request comes from.
Fix before retrying
The server failed while handling the request. Many of these are temporary, so retrying often works. When one keeps coming back, the logs of the server at that moment have the cause.
The endpoint crashed while handling the request.
Look at the application's logs at the time of the request. Retrying helps if the cause was temporary, like a database blip, and not if it's a bug.
Retry
The server doesn't support what the request asks, usually the method.
Use a method the server supports.
Fix before retrying
A proxy or load balancer got an invalid answer from the app behind it.
The app crashed, was restarting during a deploy, or closed the connection. Usually temporary.
Retry
The server is overloaded or down for maintenance.
Laravel answers 503 while in maintenance mode (php artisan down). Wait and retry, as long as Retry-After says when there is one.
Retry after a wait
A proxy gave up waiting for the app behind it.
The request takes too long. Make the endpoint answer quickly and do the slow work in a background job, or raise the proxy's timeout.
Retry
The server doesn't support the HTTP version the request used.
A client or proxy setting. Use HTTP/1.1.
Fix before retrying
The server can't store what it needs to finish the request.
The server ran out of disk. Retry once there is space.
Retry after a wait
The server found an infinite loop while processing the request.
A server-side bug or misconfiguration, often redirects or proxies pointing at each other.
Fix before retrying
The network wants the client to log in first, like a hotel Wi-Fi portal.
Not something a server-to-server call should hit. Check the network the request leaves from.
Fix before retrying
Not in the HTTP standard, but common in logs: nginx's 499 and Cloudflare's 52x, which come from the proxy in front of your app rather than the app itself.
nginx logs it when the client hung up before the server answered.
The caller's timeout is shorter than the request takes. To the caller it looks like a timeout. Make the endpoint answer faster, or give the caller a longer timeout.
Retry
Cloudflare got an empty or unexpected answer from your server.
The app crashed or closed the connection. Check its logs at that time.
Retry
Your server refused Cloudflare's connection.
The app or server is down, or a firewall blocks Cloudflare's IP ranges.
Retry
Cloudflare couldn't open a connection to your server in time.
The server is overloaded, or a firewall drops the connection silently.
Retry
Cloudflare can't route to your server.
Check the DNS record that points Cloudflare at your server.
Fix before retrying
Cloudflare connected, but your server didn't answer within 100 seconds.
The request runs too long for Cloudflare. Reply right away and finish the work in a background job. Retrying the same long request times out again.
Fix before retrying
Cloudflare couldn't set up TLS with your server.
Check the certificate and TLS settings on the server.
Fix before retrying
Your server's certificate isn't valid, under Cloudflare's Full (strict) mode.
Renew or replace the certificate, for example with a Cloudflare origin certificate.
Fix before retrying
No status code matches that. Try a number like 429, or a word like redirect.
Delay keeps the status code, response body and timing of every request it makes on your schedule, and explains failures in plain words: a redirect, a missing credential, a timeout. Your team gets an alert when a cron keeps failing. Free for 1,000 requests a month.
A status code is the endpoint's one-line answer. 2xx means it worked, 3xx means it lives somewhere else, 4xx means the request was wrong, and 5xx means the server failed while handling it. For an automated request with nobody watching, that first digit decides what happens next.
The response body usually says more than the code. A 422 lists the invalid fields, a 401 names the missing header, and a 500 page from a framework in debug mode shows the exception.
Retry what is likely temporary: timeouts, 429, 502, 503 and 504, and the Cloudflare 52x errors. Wait between attempts, longer each time, and honour Retry-After when it is there, so a struggling server gets room to recover.
Don't retry a 400, 401, 403, 404 or 422 unchanged. The same request gets the same answer, and a queue of retries only hides the problem. Fix the URL, the credentials or the payload, then send it again. Retrying is only safe when the endpoint is idempotent, so a request that half-succeeded the first time doesn't do the work twice.
Delay counts any status from 200 to 299 as a success, and anything else as a failed run, with the status, response body and headers kept so you can see what came back. It doesn't follow redirects, so a 301 or 302 shows up as a failure with the new location instead of quietly calling another URL.
Jobs sent through the API retry on the delays you set for their queue, and go to the dead letter queue when the retries run out. Crons don't retry: the next scheduled run is the retry, and an alert goes out after the number of failures in a row you choose.
401 means the server doesn't know who is asking: credentials are missing or invalid. 403 means it knows and the answer is still no, because of permissions, an IP rule or a firewall. Fix a 401 with the right credentials; a 403 needs access granted.
Either works: senders treat any 2xx as delivered. Return it quickly, before slow work. If processing takes long, queue it and answer 202 or 200 right away, so the sender doesn't time out and retry.
It is nginx's code for a request the client gave up on before the server answered. The caller saw a timeout. Make the endpoint answer faster, or give the caller a longer timeout.
The URL is behind session authentication, which redirects unauthenticated visitors to a login page. Server-to-server calls have no session. Exclude that route from the login middleware and protect it with a token or a request signature instead.
All three come from something in front of your app. 502: the app sent back something invalid or closed the connection. 503: the server is overloaded or in maintenance. 504: the app took too long to answer. 502 and 503 are usually brief; a 504 that repeats means the request is too slow.
For a browser, no: it follows the redirect. For webhooks and scheduled calls, usually yes, because many senders don't follow redirects, Delay included. Update the URL to the one in the Location header.