Debugging outbound calls and the errors you report
Every outbound call is a promise about a machine you do not control, and every error response is a promise to the callers of your own API. The skill this section trains is making the dependency misbehave on purpose and checking what your service says about it.
Every call needs a timeout
httpx lets you set timeout=None, which waits forever. A waiting request holds a database connection and often a row lock, so a slow provider starves unrelated endpoints until the pool is empty. Decide the longest you will wait (connect and read), turn that into a clear error for the caller (a 504), and take the value from configuration. The lab environment ships a payments stand-in with a fault switch so you can reproduce the slow provider.
Status codes are the contract
Load balancers, retry logic, SDKs, dashboards and alerts decide success from the status code, not from the body. A handler that turns a failure into 200 {"status": "error"} is invisible to all of them: zero errors on the dashboard while customers cannot pay. Map each failure to the status that matches it (402 for a decline, 504 for a provider timeout, 502 for an unreachable provider) and keep the human-readable message in the body. Then test the mapping with a fake client that fails in each way.