WordPress API integration: REST, keys, and security
WordPress API integration done safely: outbound keys, REST permissions, rate limits, and what Security Ninja does and does not cover.
WordPress API integration done safely: outbound keys, REST permissions, rate limits, and what Security Ninja does and does not cover.
APIs let WordPress talk to other services: weather, payments, CRMs, maps, stock data. Done well, your site shows live data without hand-editing pages. Done badly, you leak API keys, hammer third-party quotas, or ship a custom REST route that exposes admin data to strangers.
This is REST, keys, and permission callbacks on a WordPress site, not a pitch to hire an agency for “API integration services.”
This guide covers outbound calls (WordPress talks to Stripe) and inbound REST security (other apps call your WordPress). Both matter for a typical agency build.
| Direction | What it is | Common mistake |
|---|---|---|
| Outbound | WordPress PHP calls api.stripe.com or similar | Keys in the theme; no caching; trusting JSON blindly |
| Inbound (REST) | Clients call /wp-json/ on your site | Custom routes with permission_callback => true |
| Admin AJAX | Legacy admin-ajax.php handlers | Missing nonces and capability checks |
The WordPress REST API is how apps talk to WordPress. wp_remote_get() is how WordPress talks out. Many sites use both.
Public read endpoints for posts are by design. Risk clusters in custom plugin routes:
register_rest_route() needs a real permission_callback, not __return_true for sensitive data.current_user_can() to the data returned. Subscriber-only data should not leak to anonymous callers./wp-json/ lists routes. Hiding the index is optional; fixing permissions is mandatory.Audit custom plugins and headless front ends after major updates. A route that was “internal only” often becomes public when someone forgets the callback.
Prefer the WordPress HTTP API over raw curl unless you have a specific need.
$response = wp_remote_get(
'https://api.example.com/v1/status',
array(
'timeout' => 15,
'headers' => array(
'Authorization' => 'Bearer ' . EXAMPLE_API_TOKEN,
),
)
);
if ( is_wp_error( $response ) ) {
return;
}
$code = wp_remote_retrieve_response_code( $response );
$body = wp_remote_retrieve_body( $response );
$data = json_decode( $body, true );
wp_remote_post() follows the same pattern for writes. Put reusable logic in a small custom plugin, not only in the theme’s functions.php, so the integration survives theme switches.
Goal: show a short status string from https://api.example.com/v1/status without exposing the API token to browsers.
wp-config.php (or the host env), not in the database options screen:define( 'EXAMPLE_API_TOKEN', 'replace-me' );
function example_get_remote_status() {
$cached = get_transient( 'example_api_status' );
if ( false !== $cached ) {
return $cached;
}
$response = wp_remote_get(
'https://api.example.com/v1/status',
array(
'timeout' => 15,
'headers' => array(
'Authorization' => 'Bearer ' . EXAMPLE_API_TOKEN,
),
)
);
if ( is_wp_error( $response ) || 200 !== wp_remote_retrieve_response_code( $response ) ) {
return '';
}
$data = json_decode( wp_remote_retrieve_body( $response ), true );
if ( ! is_array( $data ) || empty( $data['status'] ) ) {
return '';
}
$status = sanitize_text_field( $data['status'] );
set_transient( 'example_api_status', $status, 5 * MINUTE_IN_SECONDS );
return $status;
}
add_shortcode(
'example_status',
function () {
$status = example_get_remote_status();
if ( '' === $status ) {
return '<p>Status unavailable.</p>';
}
return '<p>Status: ' . esc_html( $status ) . '</p>';
}
);
Optional REST wrapper if JavaScript needs the value: register a custom route that calls the same helper and returns JSON. Still keep EXAMPLE_API_TOKEN only in PHP. Check capabilities if the data is not public.
Operate it: log failures, watch provider rate limits, rotate the token when people leave, and delete the plugin when the integration dies.
WordPress Application Passwords let scripts authenticate to REST without sharing the main admin password. Use them for:
Give each integration its own user with the minimum role. Revoke the application password when the tool is removed. Pair with 2FA on human admin accounts. Guide: login security.
No-code API plugins (WPGetAPI-style tools) help non-developers map endpoints in wp-admin. Custom code gives you control, tests, and clearer security review.
Either way:
Protect keys. Do not hardcode secrets in public repos or paste them into page content. wp-config.php constants, environment variables, or a secrets store beat committing tokens to Git.
Least privilege. Use scoped API keys. Revoke keys you no longer need. See least privilege.
Validate responses. Never trust remote JSON blindly. Check HTTP status codes. Escape output when rendering HTML (XSS lives in bad prints).
Rate limit and cache. Call APIs on cron or on demand with transients, not on every anonymous page hit, unless the provider and your host can take it.
Error handling. Failed calls should degrade gracefully, not white-screen the site.
Log without leaking. When debugging, do not log full API responses that contain PII or tokens.
WP Security Ninja helps with site security posture: tests, vulnerability scanning, Cloud Firewall, malware tools, and login hardening. It is not an API connector builder and it does not “auto-integrate” Stripe or weather feeds for you.
Use Security Ninja to keep the WordPress install harder to abuse while your integration code (or a dedicated API plugin) handles the external calls. Broader baseline: WordPress security checklist, plugin risks.
wp_remote_get / wp_remote_post, parse JSON, handle errorsAPIs make WordPress more useful. Treat every key like a password, every REST route like a public door unless proven otherwise, and every remote payload like untrusted input.
Found this useful? Share it.
It exposes structured endpoints with permission callbacks. Public read routes are intentional. Risk rises when plugins register custom routes with weak permission checks or expose user data without authentication.
Outside the theme and public repos: wp-config.php constants, environment variables, or a host secrets store. Never paste private keys into posts, options screens, or JavaScript sent to browsers.
No. Security Ninja hardens the WordPress site (tests, vulnerabilities, firewall, malware, login). Your integration code or API plugin must handle keys, validation, and outbound calls safely.