Third-Party API Integration Best Practices for AI-Built Apps
Why calls to another company's service belong in your backend, what to do when that call is slow or fails, and what to ask your AI coding agent for.
Quick answer
Your app calls a third-party API whenever it asks another company's service to do something: take a payment, send an email, look up an address or run an AI model. Make every call that needs a secret key from your backend, never from the browser, because anything in the browser is public.
Then plan for the call going wrong, because sooner or later it will. Give it a time limit. Retry only the calls that are safe to repeat. Wait when the service says you're sending too much (a 429). Give every payment or order an idempotency key, so a retry can't do it twice. Check what comes back before you use it, and keep keys out of your logs. The prompt at the end gets your AI to plan all of this before it writes any code.
What calling a third-party API means
An API is the way one program asks another for something. A third-party API belongs to a service you don't run: a payment gateway, an email service, an address lookup, a text-message service or an AI model. Your app sends a request, and the service sends back a response. Our guide to what an API is covers the idea from the start.
When you build with AI, you usually test the call once, it works, and you move on. But every call to someone else's service can be slow, fail, or come back with something you didn't expect, and a quick demo never tries any of those. Most of this guide is about those other outcomes, because that's where real customers get double-charged or left staring at a spinner.
Should an API be called from the frontend or the backend?
Call it from the backend whenever it needs a secret key, which covers most services that cost money or act on your behalf. Your backend is a small function running on a server, and the browser never downloads its code. Anything in the frontend is sent to every visitor, so a key there stops being secret.
That includes the frontend's so-called environment variables: they're built into the files the browser downloads, whatever they're named. Our guide to why you can't put an API key in the frontend shows what a visitor can see and which keys are made to be public.
The backend is also the only place where you can control the call: set a time limit, decide what to retry, and log what happened. So even a call that doesn't need a secret is often better made there.
If your AI coding agent wires the call up in the browser anyway, the first sign is often a CORS error: the browser refusing to hand your page the answer from another web address. That's a browser security check doing its job, not something to switch off. The usual fix is to move the call to your backend. Our CORS error guide explains it.
What a signed request is, and when you need one
Most APIs only need your key sent along with each request, much like a password. Some, mostly payment gateways, also want a signature: a code your backend works out from the request's contents plus a secret only you and the service know. The service works out the same code from what it received. A match proves the request came from you and that nothing in it was changed on the way.
The recipe for that code (which fields, in what order, written in what way, hashed with which method) comes from the service's own documentation, and a single character out of place breaks it. The usual culprits are fields in the wrong order, spaces or punctuation written differently, blank fields left in when they should be dropped (or the other way round), capital letters where the service expects lower case, and a stray space or line break copied into the secret. AI coding agents often write the recipe from memory, so give yours the service's documentation for it.
The same check runs in the other direction. When a service calls you (a webhook), with a payment notification or an incoming chat message, it signs the request, and your backend checks the signature before it trusts anything inside. The pattern is always receive, check, then act. Many services also expect a quick reply and send the message again if they don't get one, so your backend should be ready to see the same message twice. Our guide to a webhook signature that won't verify covers that side in full.
What to do when an API call fails or times out
Besides success, a call can end three ways: no answer in time, a failed connection, or an error answer. The first two leave you not knowing whether the service did the work. An error answer comes with an HTTP status code (the short number a service sends back), and that code tells you what went wrong and what to do next.
| What happens | What it means | What your app should do |
|---|---|---|
| No answer in time (a timeout) | The service was slow or the connection dropped. You don't know whether it did the work. | Stop waiting after a set time, tell the user, and check before repeating anything that creates or charges. |
| 429 Too Many Requests | You hit the service's rate limit: too many requests in a given amount of time. | Wait, then try again. If the answer includes a Retry-After header (a line in the reply saying how long to wait), wait at least that long. Find out what is sending so many. |
| 500, 502, 503 or 504 | A problem on the service's side, or on the way to it. Often temporary. | Retry a few times, with a longer wait each time, but only if the call is safe to repeat. |
| 400 Bad Request | The service couldn't make sense of what your app sent. | Don't retry. The same request will fail again. Fix what's being sent. |
| 401 or 403 | The key is missing, wrong or expired, or it isn't allowed to do this. | Don't retry. Check the key is set for the live site and has the right permissions. |
| The connection fails | Your backend couldn't reach the service at all. | Treat it like a timeout: tell the user, and retry only what's safe to repeat. |
Three habits follow from that table:
- Set a time limit. Without one, your backend can wait as long as the server lets it run, and the visitor watches a spinner the whole time. For something a person is waiting on, a few seconds is usually the most they'll tolerate.
- Retry with backoff, and stop. Backoff means waiting a little longer after each failed try, say one second, then two, then four, and giving up after a few tries. Adding a small random extra to each wait (called jitter) stops everyone's retries landing on the service at the same moment.
- Tell the user in plain words. "We couldn't confirm your payment with the payment service. Please don't pay again yet; we'll let you know as soon as we know whether it went through" beats a raw error or a page that never finishes loading. Never show them the service's raw error message; it can contain details they shouldn't see.
If a 401 appears only on the live site, the key usually wasn't set there. Our guide to environment variables that stop working after deploy covers why.
Is it safe to retry a failed API call?
Only if repeating it can't do the work twice. Reading something, such as looking up an address, is safe to retry. Creating or charging something, such as taking a payment, isn't safe on its own, because the first attempt may have worked and only the reply got lost. Those calls need an idempotency key or a check first.
The HTTP standard calls a request "idempotent" if "the intended effect on the server of multiple identical requests with that method is the same as the effect for a single such request". It also says a client "SHOULD NOT automatically retry" a request that isn't, unless it has some way to know the repeat is safe, or that the first attempt never went through.
| What the call does | Example | Safe to retry? |
|---|---|---|
| Reads something | Fetch a product list, look up an address | Yes. Asking twice changes nothing. |
| Sets or deletes one specific thing | Set a customer's address to a given value, delete one saved item | Usually. Doing it twice ends in the same place as doing it once. |
| Creates or charges something | Take a payment, create an order, send an email or a text message | Not on its own. It needs an idempotency key, or a check that the first try didn't work. |
The dangerous case is a timeout on a call from the last row. The payment may have gone through and only the reply got lost. A blind retry then charges the customer twice, and nothing in your app notices.
What an idempotency key is, and when you need one
An idempotency key is a unique reference your backend creates once for one action, such as one order, and sends with every attempt at that action. A service that supports these keys recognises the repeat and hands back the first result instead of acting again. Two rules make it work: every retry of the same action reuses the same key, and a genuinely new action gets a new one.
Not every API supports idempotency keys. The service's documentation will say, often under that name. If yours doesn't, your backend checks its own records before trying again: does this order already have a payment reference? Our guide to adding a payment gateway explains why your own records, updated from the gateway's signed notification, are the ones to trust.
Don't trust the response blindly
A reply from a service isn't automatically a useful one. Before your app uses it:
- Check it succeeded. An error reply still arrives as a reply. Code that only reads the data, without checking the status first, carries on with nothing.
- Check the parts you need are there. Services change their replies, and a missing field should produce a clear error, not a blank page or a price of zero.
- Treat it as data, never as code. Text from another service, including an AI model's output, shouldn't be dropped into your page as raw HTML or run as an instruction. Show it as plain text.
- Keep the reference. Store the service's own ID for each action (a payment reference, a message ID), so you can trace what happened later.
Keep keys and customer details out of your logs
Logs are how you find out what went wrong, and they tend to be read by more people and tools than your code is. Log the time, which service was called, the status code and the service's reference. Don't log the key, the hidden request details (headers) that carry it, or full customer details. Customer details in a log are still customer details you have to keep safe. If a key ever does end up in a log or in the browser, replace it with a new one at the service; deleting the log line doesn't un-publish it.
What isn't possible
- The browser can't hide a secret. There's no frontend-only way to use a secret key without publishing it.
- Retrying can't make a charge safe to repeat. Only an idempotency key, or a check against your own records, does that.
- You can't make someone else's service reliable. You can only decide what your app does when it isn't.
- Your AI doesn't know a service's current rules unless you show it. Field names, limits and signing recipes change. Give it the relevant part of the service's own documentation. It also can't see your live keys or your logs, so checking those is your job.
The prompt to give your AI
Copy this into your AI coding agent's chat. It asks for a plan before any code, so you can check the plan against this guide first.
I'm not a coder. I want my app to use [name of the
service] to [what it should do, e.g. take a payment /
look up an address / send a text message]. Here is the
relevant part of its documentation: [paste it or link
it]. Don't write any code yet. First give me a plan
that covers:
1. Where the call is made. If it needs a secret key,
it must be a backend function, not the browser.
Name the file, and show where the key is read from
a stored secret.
2. The time limit on the call, and what the user sees
if it runs out.
3. What happens for each outcome: a timeout, a 429,
a 500-range error, a 400, a 401 or 403, and a
failed connection. Say which ones are retried.
4. For retries: how many tries, how long between them,
and whether a Retry-After header is respected.
5. Whether this call creates or charges something. If
it does, how a retry is stopped from doing it twice
(an idempotency key if the service supports one, or
a check of my app's own records).
6. What in the response is checked before it is used.
7. What gets logged, with confirmation that the key
and customer details never are.
If the documentation doesn't answer something, say so
instead of guessing.What to check in the AI's answer
- The call is in a backend function. If the plan makes it from a page, a component or anything the browser loads, ask it to move the call.
- There's a real time limit. Look for an actual number. "Handles slow responses" isn't one.
- Not everything is retried. A 400, 401 or 403 should fail straight away, and retries should stop after a few tries.
- A payment or order can't happen twice. Ask it: "If the call times out and we retry, can the customer be charged twice?" The answer should name the idempotency key or the records check.
- The response is checked. The plan should say what happens when a field it needs is missing.
- The logs are clean. Ask it to list exactly what gets logged. The key shouldn't be on that list.
Test it before real customers do
Before launch, check where the key lives, then use the service's test (sandbox) mode to try the failures on purpose:
- Search for the key. Open your live site, view its source and the files it loads, and search for the start of your key. If you find it, the call is in the browser.
- Break the key. Set a wrong key in the test setup and trigger the call. You should see a clear error, not a spinner that never stops.
- Repeat an action. Trigger the same test order twice in quick succession, or ask your AI how to replay one. You should end up with one order, not two.
For a different service or a different job, the Custom Prompt Builder helps you write your own prompt from scratch, with the context and limits your AI needs.
Where to go next
- These practices applied to taking payments: How to Add a Payment Gateway to Your AI-Built Website.
- Why the key stays out of the browser, in full: Why You Can't Put an API Key in the Frontend.
- What a status code means when your app stops working: Why Is My AI-Built App Not Working? Error Codes Explained.
- What a demo never tests, a failed call to another service among them: Why Your Vibe-Coded App Isn't Production-Ready Yet.
- The two ideas this page builds on: What Is an API? and What Is a Webhook?
Not affiliated with the platforms we write about
AI Build South Africa is an independent resource. We're not endorsed by, or an official partner of, any API provider or AI website builder. This guide describes general practices, not a ready-made integration for any one service; confirm field names, limits and signing rules against that service's own current documentation. See our Disclaimer for the full disclosure and our Terms of Service for the wider terms.
Frequently asked questions
Should an API be called from the frontend or the backend?
From the backend whenever the call needs a secret key, which covers most services that cost money or act on your behalf. Anything in the frontend is downloaded by every visitor, so a key there is public. The backend is also the one place where you can set time limits, retries and logs for the call. A few services issue keys meant for the browser, and their documentation says so.
What does an idempotency key mean?
It's a label that tells a service "this is the same order as before, not a new one", so a retry after a timeout can't charge twice. Your backend creates it once per action and reuses it on every attempt. It's what makes it safe to retry a payment or an order after a timeout. If a service doesn't support one, your backend has to check its own records before it tries again.
What does 429 Too Many Requests mean, and how long should my app wait?
It means your app sent too many requests in a given amount of time and hit the service's rate limit. If the response includes a Retry-After header, wait at least that long before trying again. If it doesn't, wait a little longer after each try and give up after a few. Then find out what is sending so many requests, because a loop or a page that calls the service on every keystroke is the usual cause.
What does an API timeout mean?
It means your app stopped waiting for an answer, usually because the service was slow or the connection dropped. A timeout doesn't tell you whether the service did the work. It may have taken the payment and lost only the reply. So treat the outcome as unknown: tell the user, and check before repeating anything that creates or charges.
Is it safe to just retry a failed API call?
Only if the call is safe to repeat. Reading something, such as looking up an address, is safe to retry. Creating or charging something, such as taking a payment or placing an order, is not safe to retry on its own, because the first attempt may have worked. Those calls need an idempotency key, or a check that the first attempt didn't go through, before a retry. Errors that mean the request or the key is wrong, such as a 400 or a 401, shouldn't be retried at all.
What should I do when a third-party API call fails?
Look at what came back. No answer means a timeout or a network problem, and the outcome is unknown. A 429 means slow down and wait. A 500-range error is a problem on the service's side and is often temporary, so a few spaced-out retries of a safe call make sense. A 400, 401 or 403 means the request or the key is wrong, so fix that instead of retrying. In every case, show the user a clear message rather than an endless spinner, and log what happened without the key.
Related reading
- Webhook Signature Verification Failed? What to Tell Your AI: what to check when a signature doesn't match.
- How to Send Email From Your AI-Built App, and Keep It Out of Spam: the same practices applied to an email service.
- CORS Error Calling a Third-Party API: Causes & Fixes: the browser error that usually means the call is in the wrong place.