Laravel HTTP client: a returned response is not a successful integration
Your synchronization job finishes without an exception, but the supplier returned HTTP 500. The application recorded the run as successful because it treated receiving a response as proof of business success.
Require a successful response and a valid shape
use Illuminate\Support\Facades\Http;
$response = Http::acceptJson()
->connectTimeout(3)
->timeout(12)
->get(config('services.supplier.url').'/products/AX-204');
$response->throw();
$product = $response->json();
if (!is_array($product)
|| !isset($product['sku'])
|| !is_string($product['sku'])) {
throw new UnexpectedValueException('Invalid supplier product');
}
Configure the supplier URL server-side. Do not let visitors choose it. The timeout values are illustrative and should fit your worker's execution budget.
Decide what each response means
For a particular endpoint, 404 may mean a product was removed, or it may mean a misconfigured URL. A 401 usually needs configuration or credential attention, not rapid retries. A 429 needs the provider's rate-limit handling. Write those cases down before adding automatic retries.
A successful status with malformed or unexpected JSON is still an integration failure. Preserve the previous valid product until the replacement has passed validation.
Make the test independent of the network
Use Http::fake with a valid response, a 500 response, and an invalid JSON shape. Also prevent stray HTTP requests in the test environment so a missing fake cannot contact a live supplier.
Check the stored record after each failure. A test that only expects an exception can miss a partial update made before the exception. Avoid logging API tokens or the complete supplier response while diagnosing the problem.
Laravel's HTTP client reference explains response error handling and explicit exceptions. Pair transport checks with your own schema checks; neither replaces the other.