Most of a modern app is other people's software. Payments are Stripe, email is Resend, the clever text feature is OpenAI's API. You do not build any of it. What you do build is the thin, fragile seam where your server talks to theirs, and that seam is where the outages and the leaked keys live.

The idea

An is how one program asks another to do something. Your server sends a request to an address the other company publishes, attaches an to prove who is asking, and gets an answer back. That key is a password with a spending limit attached, the other company's servers are not always up, and both facts have to be designed for rather than discovered.

code
   YOUR SERVER                                    SOMEONE ELSE'S SERVER
   +---------------------+ POST /v1/payment_intents +--------------------+
   |  checkout handler   | -----------------------> |  Stripe            |
   |                     |   Authorization:         |                    |
   |  key from an env    |   Bearer sk_test_...     |  checks the key    |
   |  variable, never    |                          |  checks rate limits|
   |  in the repo        | <----------------------- |  does the work     |
   +---------------------+   200 / 429 / 503        +--------------------+
                                 |
             +-------------------+-------------------+
             |                   |                   |
          200 ok            429 too many        503 / timeout
          continue          requests            they are down
                            wait and retry      show a real error,
                            with a growing      do not silently
                            delay               pretend it worked

How it works

The key identifies your account and carries permissions. Stripe issues a publishable key that is safe in browser code and a secret key that is not, and a secret key in a frontend file lets a stranger issue refunds from your balance. Most services also let you scope a key down: read-only, one product, one domain. Take the narrowest one that does the job.

Rate limits are the second surprise. Every service caps how many requests you may make per minute, and OpenAI additionally caps tokens per minute, so a loop that calls it once per row stops partway down a long list rather than failing at the start. The exact ceiling depends on the account and the model, and it is on the vendor's rate-limit page. The signal is HTTP status 429, and the fix is waiting longer between retries rather than retrying harder: wait a second, then two, then four, and give up after a few attempts instead of hammering.

Then there is failure. A request can succeed slowly, fail cleanly, or time out with you never learning whether the other side did the work. That last case is why payment and email calls need to be safe to repeat. Safe to repeat has a mechanism, and it is worth knowing the word: you send an idempotency key, a unique string you make up for that one attempt, and the other company promises that two requests carrying the same key do one thing. Stripe supports it, and so does most of the industry. Without one, a retry after a timeout charges the card again.

What to do

  1. Keep every key in an environment variable in .env.local, and confirm that file is really ignored: git check-ignore -v .env.local should name the rule that catches it. Silence means it is not ignored, with one trap. Once git is already tracking a file, adding it to .gitignore changes nothing and that command stays quiet either way. Run git ls-files .env.local to settle it. If the file is listed, git rm --cached .env.local stops the tracking, and the key itself should be treated as public, because it is in the history and probably on GitHub.
  2. Use separate test and live keys. Stripe's test keys start with sk_test_, which makes a mistake visible on sight.
  3. Send the request from your own server. Browser code can safely hold a key the vendor publishes as public, like Stripe's publishable key, and it can safely upload a file to a link your server signed first. What it must never hold is the key that spends money or reads your database.
  4. Decide what the user sees when the call fails, before you ship. "Payment could not be completed, you were not charged" is a design decision, and the default is a blank screen.
  5. Rotate a key the moment it might have leaked, in this order: issue the new one, deploy it and confirm the app is using it, then revoke the old one. Revoking first takes your checkout down while you are already having a bad day.

Where it breaks

Your uptime is now the product of everyone else's. If Resend is down your signup email does not arrive, and no amount of correct code on your side changes that. Vendors also change: prices rise, endpoints get deprecated, an API version you depend on gets retired with six months of notice you did not read. An AI assistant writing integration code usually works from the version it was trained on, which for a service that ships weekly can be a year stale. Check the current docs page for anything that moves money.