Retry only what is safe to retry

A retry policy applied at the HTTP client level retries everything, including the POST that succeeded and whose response was lost. The safety of a retry is a property of the operation, not of the transport.

// safe: GET, PUT with a full body, DELETE — idempotent by definition
// unsafe: POST that creates something, unless it carries an idempotency key

$response = $client->post('/charges', [
    'headers' => ['Idempotency-Key' => $order->idempotencyKey()],
    'json'    => $payload,
]);

A connect timeout is safe to retry because the request never arrived. A read timeout is not, because it may have. That distinction is available in most clients and almost never used. Where the far end offers idempotency keys, use them and retry freely; where it does not, a retry on a write is a decision to occasionally double-charge someone.