WordPress wp_safe_remote_post Example: Send Webhooks Safely
Send safer outbound POST requests from WordPress with JSON payloads, timeout handling, response checks, and SSRF-aware defaults.
Published
April 29, 2026
Reading Time
2 min read
Updated
April 29, 2026

Implementation Notes
Extension points, code paths, and implementation choices that should survive contact with production.
Best For
WordPress developers, agencies, and technical teams building custom plugin or theme functionality with cleaner operational defaults.
Primary Topics
Editorial Focus
Build Pattern: Extension points, code paths, and implementation choices that should survive contact with production. Updated on April 29, 2026.
Full Report
Last reviewed: April 29, 2026
Outbound HTTP integrations are common in WordPress plugins and themes: webhook relays, CRM handoffs, support ticket creation, and status pings all depend on them. wp_safe_remote_post() is the better default when the target URL may come from settings or other runtime inputs because WordPress validates the destination and redirect chain.
This guide shows how to send a safe POST request with explicit headers, timeout handling, and response validation.
Send JSON to a remote service
<?php
$payload = array(
'site' => home_url( '/' ),
'event' => 'backup_completed',
'occurred' => gmdate( 'c' ),
'job_id' => 1842,
);
$response = wp_safe_remote_post(
'https://hooks.example.com/site-events',
array(
'timeout' => 10,
'headers' => array(
'Content-Type' => 'application/json',
),
'body' => wp_json_encode( $payload ),
)
);
This is the right shape for webhook-style integrations that need structured JSON rather than form-encoded bodies.
Check transport errors and HTTP status explicitly
if ( is_wp_error( $response ) ) {
return $response;
}
$status = wp_remote_retrieve_response_code( $response );
if ( 200 !== $status && 202 !== $status ) {
return new WP_Error( 'remote_post_failed', 'Remote service rejected the request.' );
}
A successful transport is not the same thing as a successful business response. Validate both.
Use the safe variant when the URL is not fully hardcoded
The WordPress reference highlights that wp_safe_remote_post() validates the URL and redirects with wp_http_validate_url(). That matters when the destination is configurable and SSRF risk must stay low.
Keep request payloads minimal and intentional
Do not ship entire option arrays or user objects to a third party just because they are convenient to serialize. Send only the fields the remote system actually needs.
Production checklist
- Prefer
wp_safe_remote_post()when the destination is configurable. - Set a real timeout instead of relying on defaults.
- Use explicit headers for JSON payloads.
- Check both
WP_Errorand the HTTP response code. - Log failures in a way operations can actually diagnose.
- Send the smallest payload that satisfies the integration contract.
Common mistakes
- Using unrestricted remote POST calls to arbitrary URLs. That increases SSRF risk.
- Ignoring response codes. Many failed business events still return a transport response.
- Serializing oversized objects. Integrations should be explicit, not lazy dumps.
- Skipping timeouts. Slow remotes can pin requests longer than expected.
- Assuming JSON headers are optional. Many receiving systems depend on them.
Related reading
If the integration consumes remote APIs instead of sending to them, pair this with the HTTP API article. If the remote system later calls back into WordPress, review the webhook receiver guide.


