Blog

HTTP status codes

The returned HTTP status code lets you know whether your request was successful. If not, the code indicates why. We recommend configuring your application to automatically retry HTTP requests when the returned status code indicates there was a temporary fault. A subsequent request may well succeed.

HTTP response status codes

In general a returned HTTP status code of:

  • 200-299 means the request was successfully completed
  • 400-499 means the request failed due to a client error
  • 500-599 means the request failed due to a server error

Our API follows that convention, returning this subset of the available codes:

200-299 (success)

200 OK

The request succeeded. We return a status code of 200 for a successful GET (to fetch a resource), PATCH (to update a resource), POST (to create a resource) or DELETE (to delete a resource).

Some APIs will instead return a 204 No Content status code in response to a successful DELETE, returning no data in the response body.

400-499 (error due to the client)

400 Bad Request

A 400 error means the request failed because the data sent was somehow invalid. That could be because it was malformed (such as JSON missing a comma or bracket), or because it did not follow the expected/required structure.

Make sure to check our developer documentation to ensure your data matches what the endpoint expected to be sent.

401 Unauthorized

A 401 means the request was missing authentication. This is likely because no API key was sent. Make sure you are sending one.

403 Forbidden

A 403 means the request was forbidden. For our API, this is likely due to your API key being incorrect, expired and/or not having permission to do that particular action upon that resource.

404 Not Found

404 means the server could not find that resource. That could be because you are requesting an incorrect endpoint (such as /video instead of /videos) or the particular item does not exist (such as /videos/a-deleted-id).

429 Too Many Requests

A 429 status code means too many requests have been made recently. The system is under load. A 429 would be returned in response to rate-limiting.

This is an ideal example of a HTTP status code where a request should be retried, since after several seconds/minutes it is likely that same request will be permitted.

500-599 (error due to the server)

500 Internal Server Error

This is a somewhat generic status code which essentially means something went wrong. The request could not be fulfilled. That issue might be temporary and so the same request may succeed in future depending on what the cause of the error actually was.

502 Bad Gateway

A 502 means a gateway/proxy server received an invalid response from upstream. Our API does not directly return a 502 error, however we do utilize proxy servers (such as Cloudflare) and so they may return this HTTP status code.

503 Service Unavailable

A 503 means the server is not currently able to handle the request. That may be due to the server being overloaded, or it being down for maintenance. As such it is worth retrying the request as this is likely temporary.

504 Gateway Timeout

A gateway/proxy server did not receive a response from upstream in time. Like with the 502 status code (above) our API does not directly return a 504 however a proxy server (such as Cloudflare) may do.

525 SSL handshake failed

525 is an unofficial HTTP status code that is used by Cloudflare. Many websites and APIs are protected by Cloudflare and so you could see this status code if there is a temporary issue with the SSL handshake between it and the servers it is protecting. It will normally be temporary. Unless intervention is required, a subsequent handshake will likely succeed and so these requests are worth retrying.

Retry requests

As you can see from the explanations above, a returned HTTP status code of 429 or 500+ means the request is worth retrying. Those status codes suggest the issue is temporary. The next time you make the same HTTP request (sending the same data, the same headers, and so on), it may succeed.

A good example is the 429 status code. That likely means you have hit a rate-limit on the number of requests per second/minute. That rate-limited state is temporary and so that same HTTP request will likely succeed once a period of time has passed.

How you retry a HTTP request depends upon your application. For Node.js, we often use Got. For PHP, we use Guzzle:

Node.js: Got

By default Got will automatically retry requests, however you may want to customise its settings. For example you can change how many times it retries, and what status codes trigger a retry.

As mentioned above, generally we recommend retrying a request if it receives a 429 or 500+ HTTP status code. If it fails after multiple attempts you can probably assume the issue will take longer to resolve. For example:

import got from 'got'

let response = await got('https://api.example.com/v2/videos/id', {
  retry: {
    limit: 3,
    statusCodes: [429, 500, 502, 503, 504, 525],
  },
})

PHP: Guzzle

Guzzle won’t automatically retry requests. There is no option for retries listed in its documentation.

However you can add middleware to ask it to retry. Here we’ve used a handler stack to add our API key and then configure the retry logic we want to use in our Guzzle client:

use GuzzleHttp\Client
use GuzzleHttp\HandlerStack
use GuzzleHttp\Middleware
use Psr\Http\Message\RequestInterface
use Psr\Http\Message\ResponseInterface
use GuzzleHttp\Exception\ConnectException
use Exception

// stack of middleware
$stack = HandlerStack::create();

// middleware 1: authentication
$stack->push(Middleware::mapRequest(function (RequestInterface $request) {
	// this client will be used to call the API, so add a header for the API key:
	return $request->withHeader('Authorization', 'Bearer ' . API_KEY_HERE);
}));

$retry_decision = function (
	$retries,
	RequestInterface $request,
	ResponseInterface $response = null,
	Exception $exception = null
) {
	if ($retries > 3) {
	// tried too many times: give up
		return false;
	}

	if ($exception instanceof ConnectException) {
	//  may be a temporary network issue and so it is worth retrying the request
		return true;
	}

	if ($response) {
		if ($response->getStatusCode() === 429 || $response->getStatusCode() >= 500) {
		// may be a temporary issue and so it is worth retrying the request
			return true;
		}
	}

	return false;
};

$retry_delay = function ($numberOfRetries) {
	return 2000 * $numberOfRetries; // exponential backoff (in ms)
};

// middleware 2: retries
$stack->push(Middleware::retry($retry_decision, $retry_delay));

// create client, passing the stack of middleware as 'handler'
$client = new Client([
	'base_uri' => 'https://api.example.com/v2/',
	'timeout' => 10,
	'connect_timeout' => 20,
	'headers' => [
		'Accept' => 'application/json',
		'Content-Type' => 'application/json'
	],
	'handler' => $stack
]);

// example request using the client:
$response = $client->request('GET', 'videos');

If you have any questions about the returned HTTP status codes, or how to handle them, please get in touch.

Updated: November 24, 2022