REST API & Integrations

Integrating Third-Party APIs into WordPress Safely

How to call an external API from WordPress without slowing the site down: caching, queuing, timeouts, credentials, error handling and rate limits.

By 6 min read
Network diagram with a central WordPress node linked to connected services

Pulling data from an external service into WordPress is a common request: show live stock from an ERP, display reviews from a platform, pull events from a calendar. The naive implementation works perfectly in testing and falls over in production.

The reason is always the same — the remote service is slower or less available than you assumed. Here's how to build one that degrades gracefully.

The rule: never call an API during page render

If your template calls a remote API, then every page view waits for that API. When it's fast, nobody notices. When it's slow, your page is slow. When it's down, your page hangs until the timeout — and on a badly configured request, that timeout can be measured in tens of seconds.

One unreachable third-party service can take a whole site down this way, and the cause is invisible: the server is fine, the database is fine, and the page just hangs.

So: fetch on a schedule or on an event, store the result, and have the page read the stored copy. The page never waits for anyone else's server.

Caching the response

  • Store the result in a transient, with an expiry appropriate to how fast the data actually changes. Exchange rates might be an hour; a product catalogue might be a day.
  • Key the cache by every parameter that affects the result, or you'll serve one query's answer to another.
  • Serve stale data rather than nothing. If the refresh fails, keep showing the last good copy and try again later — a slightly old price is better than an error message.
  • Refresh in the background rather than on the request that finds the cache expired, so one unlucky visitor doesn't pay for everyone's refresh.
  • Have a manual way to clear the cache, for when someone needs the new data now.

Making the request properly

Use WordPress's HTTP API — wp_remote_get and wp_remote_post — rather than cURL directly. It handles proxies, filters and transports consistently, and other code can observe it.

  • Set a timeout explicitly, and keep it short. Five seconds is generous for a background job and far too long for anything a visitor waits on. WordPress's default is longer than you want.
  • Check for a WP_Error before touching the response, and check the status code before decoding the body.
  • Don't assume the response is valid JSON. Services return HTML error pages under load more often than you'd think.
  • Set a descriptive user agent so the service's logs identify you when you need support.
  • Leave TLS verification on. Disabling it to fix a certificate problem turns a warning into a vulnerability.

Credentials

  • Keep API keys in environment variables or constants in wp-config.php, not in a plugin settings field visible to every administrator.
  • Never commit them. A key in a repository is a key that leaks.
  • Use the minimum scope the integration needs. A read-only key can't be used to change anything if it escapes.
  • Rotate them periodically, and immediately when someone with access leaves.
  • For OAuth, implement token refresh properly. An integration that silently dies after sixty days because nobody handled refresh is a classic.

Rate limits

Every API has them, and hitting one usually means being blocked temporarily rather than getting a polite warning.

Read the documentation for the limit and the window, and design within it. Caching is the main defence — fewer requests is better than clever throttling.

Respect a 429 response and its Retry-After header rather than retrying immediately, which is how a temporary block becomes a longer one.

Watch for the multiplying case: a loop calling the API once per item turns a page of fifty products into fifty requests. Batch endpoints exist for this reason.

Queuing writes

Sending data out — a form submission to a CRM, an order to a fulfilment system — has the same rule and a sharper consequence: the visitor is waiting.

Store the data locally first and confirm success to the visitor based on that. Then queue the send as a background task, with retries and exponential backoff.

Distinguish retryable failures from permanent ones. A timeout is worth retrying; a 400 because a required field is missing will fail identically forever.

After the final attempt, surface the failure somewhere a human will see it. Silent permanent failure is how integrations rot.

Handling failure in the interface

Decide what the page shows when the data isn't available, and make it a deliberate choice rather than whatever happens.

Usually the right answer is to show the last known good data, perhaps with a quiet note about when it was updated. Sometimes it's to hide the section entirely. Almost never is it to show an error message about an API the visitor has never heard of.

Log the failure properly on the server so you can see it, even when the visitor can't.

Monitoring

  • Alert on repeated failures, not on a single one — every API has transient errors.
  • Alert on stale data: if the cache hasn't refreshed in three times its expected interval, something is wrong.
  • Track response times. A service getting steadily slower is a problem coming.
  • Log requests and responses at a level you can turn up for debugging and down for normal running.
  • Test the whole path after any plugin, theme or API version change.

Before you build it

A few questions worth asking up front. How fresh does this data genuinely need to be? People usually say real-time and mean daily, and the difference in architecture is large.

What happens if the service disappears permanently, or changes its pricing? An integration that's load-bearing for your business is a dependency worth naming.

Is there a webhook instead of polling? One notification when something changes beats a request every minute asking whether it has.

And is the integration worth its maintenance cost at all? Plenty of 'live data' features are looked at by nobody and break silently for months.

Frequently asked questions

How do I call an external API from WordPress?

Use wp_remote_get or wp_remote_post rather than cURL directly, with an explicitly short timeout. Check for a WP_Error before touching the response and the status code before decoding the body. Crucially, do it on a schedule or event and cache the result — never during a page render.

Why does an API integration slow down my WordPress site?

Because the page is waiting for someone else's server. If the request happens during rendering, every visitor pays for the remote service's latency, and an outage hangs your pages until the timeout. Fetch in the background, store the result, and have the page read the stored copy.

How long should I cache third-party API responses?

As long as the data can tolerate. Ask how fresh it genuinely needs to be — people say real-time and usually mean daily. Whatever you pick, serve stale data rather than an error when a refresh fails: a slightly old value beats an empty section.

Where should API keys be stored in WordPress?

In environment variables or constants in wp-config.php, not in a plugin settings field where every administrator can see them, and never in the repository. Use the minimum scope the integration needs, so a leaked key is limited in what it can do.

What should I do when a third-party API is rate limiting me?

Respect the 429 response and its Retry-After header rather than retrying immediately, which extends the block. Then reduce request volume: cache more aggressively, and look for loops calling the API once per item where a batch endpoint exists.

Topics

  • WordPress API integration
  • wp_remote_get
  • WordPress third party API
  • API caching WordPress