Depending on somebody else’s service
Every external service you connect is a part of your product you do not control and cannot fix. That is fine — as long as you decided it deliberately.
Connecting to an outside API is usually the fastest way to get a capability, and it quietly moves part of your reliability into somebody else’s hands. The work is in deciding what happens when that hand slips.
Decide what happens when it is down before it is down
Every service has an outage eventually, at a time you did not choose. The question worth answering while nothing is wrong: does your feature fail, degrade, or wait?
Failing is acceptable for something optional — a map that does not render, an enrichment that stays empty. It is not acceptable for anything in a payment or a login path, where you need a fallback or an honest error that tells the person what to do next. A spinner that never resolves is the worst of all outcomes, because it teaches people your product is broken rather than someone else’s.
Keys are credentials, not configuration
An API key is a password that happens to be written in a config file, and it gets treated as configuration because it looks like a setting. Then it ends up in the repository, in a screenshot, in a message thread.
Keep keys out of the code entirely, use a separate key per environment so a test can never touch live data, and rotate them when someone with access leaves. Also give each key the narrowest scope the service offers — most APIs let you restrict what a key can do, and almost nobody uses it until after the incident that made them wish they had.
Rate limits and the retries that make them worse
The first thing most integrations do when a call fails is try again immediately. If the failure was a rate limit, you have just made it worse, and a busy morning turns into a self-inflicted outage.
Retry with an increasing delay, cap the number of attempts, and stop entirely after that rather than looping. And never blindly retry a write that is not idempotent — the classic version of this bug is a customer charged twice because the first call actually succeeded and only the response was lost.
It will change under you
Services change response formats, deprecate endpoints and adjust limits, usually announced somewhere you were not reading. The integration that has worked for a year is not stable; it is untested since the last time it changed.
Pin a version if the service offers one, subscribe someone real to the provider’s change announcements rather than a shared inbox nobody reads, and keep one small automated call that runs daily and tells you when its answer stops looking like it used to. That last one costs an hour to build and finds the breakage before a customer does.
Questions people actually ask
What should I decide before integrating an external service?
What happens when it is down: fail, degrade, or wait. Failing is fine for something optional; in a payment or login path you need a fallback or an honest error. A spinner that never resolves is the worst outcome.
How should API keys be handled?
As credentials, not configuration. Keep them out of the repository, use a separate key per environment so tests cannot touch live data, rotate them when someone with access leaves, and restrict each key's scope.
How should retries work?
With an increasing delay and a capped number of attempts, then stop. Retrying immediately turns a rate limit into a self-inflicted outage, and blindly retrying a non-idempotent write is how a customer gets charged twice.