A nightly product-enrichment job I built quietly dropped ~300 rows one night. No error, no alert. An upstream API had rate-limited us with a 429, UrlFetchApp.fetch threw, the loop died halfway, and the next run started fresh — the skipped rows just never came back.

Every UrlFetchApp integration hits this eventually. The fix isn't one clever function; it's four small layers that keep a transient failure from becoming silent data loss. Here's the stack I use, with the code.

The quotas you'll actually hit

Before the patterns, know the walls. UrlFetchApp allows 20,000 calls/day on consumer accounts and 100,000/day on Workspace. Each call times out at 60 seconds and caps at 50 MB each way. And the one that surprises people: concurrent calls per script are limited (undocumented, but roughly 10–20), so naive parallelism throws "Service invoked too many times."

The math sneaks up on you: 5,000 SKUs × 4 enrichment calls each = 20,000 — your entire daily budget in one run.