WordPress HTTP API Example: Fetch External APIs Safely With wp_safe_remote_get
Use the WordPress HTTP API and wp_safe_remote_get to fetch external JSON safely with timeouts, allowlists, error handling, and caching.
Published
April 19, 2026
Reading Time
4 min read
Updated
April 19, 2026

Hardening Notes
Baselines, access reduction, and default settings that stand up in production.
Best For
Teams preparing, launching, or maintaining WordPress as a backend service in a production stack.
Primary Topics
Editorial Focus
Control Ledger: Baselines, access reduction, and default settings that stand up in production. Updated on April 19, 2026.
Full Report
Last reviewed: April 19, 2026
WordPress plugins often need to call external APIs: license servers, vulnerability feeds, shipping providers, payment services, dashboards, analytics systems, or internal tools. The unsafe version of this feature is a raw file_get_contents() call, an unvalidated URL, no timeout, no error handling, and no protection against server-side request forgery.
This guide shows a safer WordPress HTTP API example using wp_safe_remote_get(). It focuses on GET requests because they are common in plugins and because a read-only integration is the best place to establish a secure baseline.
Who this guide is for
This article is for WordPress plugin developers, agencies maintaining integrations, and security-minded operators reviewing code that fetches data from external services.
Why use the WordPress HTTP API
The WordPress HTTP API gives plugins a consistent way to make requests, handle responses, configure timeouts, and process errors across hosting environments. It also provides helpers for retrieving response body, status code, and headers without depending on a specific PHP extension directly.
Use wp_safe_remote_get() for arbitrary URLs
If a URL may be configured by an administrator or provided by another system, prefer wp_safe_remote_get(). WordPress validates the URL and redirects to reduce SSRF risk. That does not mean every request is automatically safe, but it is a better default than calling arbitrary URLs directly.
Example: fetch a JSON feed safely
<?php
function vulnwp_fetch_security_feed( $feed_url ) {
$feed_url = esc_url_raw( $feed_url );
if ( '' === $feed_url ) {
return new WP_Error( 'vulnwp_missing_url', 'Feed URL is missing.' );
}
$response = wp_safe_remote_get(
$feed_url,
array(
'timeout' => 8,
'redirection' => 3,
'headers' => array(
'Accept' => 'application/json',
),
'user-agent' => 'VulnWP Feed Client/1.0; ' . home_url(),
)
);
if ( is_wp_error( $response ) ) {
return $response;
}
$status_code = wp_remote_retrieve_response_code( $response );
if ( 200 !== $status_code ) {
return new WP_Error(
'vulnwp_bad_status',
'Unexpected feed response status.',
array( 'status' => $status_code )
);
}
$body = wp_remote_retrieve_body( $response );
$data = json_decode( $body, true );
if ( JSON_ERROR_NONE !== json_last_error() || ! is_array( $data ) ) {
return new WP_Error( 'vulnwp_invalid_json', 'Feed response was not valid JSON.' );
}
return $data;
}
Do not ignore errors
Remote requests can fail for normal reasons: DNS problems, expired certificates, rate limits, firewall blocks, bad JSON, slow upstream services, or maintenance windows. Treat external APIs as unreliable and design the feature to degrade cleanly.
$feed = vulnwp_fetch_security_feed( 'https://example.com/feed.json' );
if ( is_wp_error( $feed ) ) {
error_log( 'VulnWP feed error: ' . $feed->get_error_message() );
return array();
}
Do not print raw upstream errors to visitors. Log what operators need, then show a safe fallback or cached previous result.
Use an allowlist for configurable endpoints
If administrators can enter the API URL, consider restricting allowed hosts. wp_safe_remote_get() validates URLs, but an allowlist gives the plugin a business rule: this integration should only talk to expected providers.
function vulnwp_is_allowed_feed_url( $url ) {
$host = wp_parse_url( $url, PHP_URL_HOST );
return in_array(
$host,
array( 'api.example.com', 'feeds.example.org' ),
true
);
}
Use this before making the request. If the integration is supposed to call one provider, there is usually no reason to permit arbitrary hosts.
Authenticated requests
Some APIs require bearer tokens or basic authentication. Store secrets in a safe configuration path and avoid logging request headers. The example below shows the shape of a bearer-token request without exposing a real token.
$response = wp_safe_remote_get(
'https://api.example.com/v1/items',
array(
'timeout' => 8,
'headers' => array(
'Accept' => 'application/json',
'Authorization' => 'Bearer ' . $token,
),
)
);
Never commit tokens into plugin files. Rotate credentials if a debug log, repository, or support ticket ever exposes them.
Add caching to reduce load
External API calls should rarely happen on every page load. Cache successful responses with a transient and refresh them on a schedule or after a short expiration.
function vulnwp_get_cached_security_feed( $feed_url ) {
$cache_key = 'vulnwp_security_feed_v1';
$cached = get_transient( $cache_key );
if ( false !== $cached ) {
return $cached;
}
$data = vulnwp_fetch_security_feed( $feed_url );
if ( is_wp_error( $data ) ) {
return $data;
}
set_transient( $cache_key, $data, 30 * MINUTE_IN_SECONDS );
return $data;
}
Security checklist
- Use
wp_safe_remote_get()when URLs are configurable or user-controlled. - Set a timeout instead of relying on defaults.
- Restrict configurable endpoints with an allowlist when possible.
- Limit redirects.
- Validate response status code before parsing the body.
- Validate JSON shape before trusting fields.
- Cache successful responses.
- Never expose API tokens or raw upstream errors publicly.
Common mistakes
- No timeout. A slow upstream service can slow down WordPress requests.
- Trusting configured URLs blindly. Arbitrary URL fetches are an SSRF risk.
- Parsing before checking status. Error pages are not valid API responses.
- No caching. Repeated external requests hurt performance and can trigger rate limits.
- Logging secrets. Request headers and tokens should not end up in debug logs.
Related reading
This pairs with our Transients API example for caching external results and the debug log exposure checklist for safe operational logging.


