How to securely integrate HubSpot Contacts endpoints into WordPress custom plugins using WP HTTP API
Prerequisites and Setup
Before diving into the integration, ensure you have a working WordPress installation and a HubSpot account. You’ll need to generate a HubSpot API key. Navigate to your HubSpot account settings, then to “Integrations” > “Private Apps”. Create a new private app, grant it the necessary “Contacts” scopes (e.g., “crm.objects.contacts.read”, “crm.objects.contacts.write”), and copy the generated API key. This key will be used to authenticate your requests to the HubSpot API.
For this guide, we’ll assume you’re developing a custom WordPress plugin. The WP HTTP API provides a robust and secure way to make external HTTP requests from within WordPress, abstracting away many low-level details and handling common tasks like SSL verification and redirects. We’ll leverage its `wp_remote_request()` function for maximum control.
Authentication and API Key Management
Storing API keys directly in your plugin’s code is a significant security risk. A better approach is to store sensitive credentials in WordPress’s options API or, for enhanced security, use environment variables if your hosting environment supports it. For this example, we’ll use the WordPress options API. You’ll need a way for the user to input their HubSpot API key, typically via your plugin’s settings page.
// In your plugin's settings page or initialization file:
// Function to save the API key
function my_plugin_save_hubspot_api_key() {
if ( isset( $_POST['my_plugin_hubspot_api_key'] ) && ! empty( $_POST['my_plugin_hubspot_api_key'] ) ) {
update_option( 'my_plugin_hubspot_api_key', sanitize_text_field( $_POST['my_plugin_hubspot_api_key'] ) );
// Add success message
}
}
add_action( 'admin_init', 'my_plugin_save_hubspot_api_key' );
// Function to retrieve the API key
function my_plugin_get_hubspot_api_key() {
return get_option( 'my_plugin_hubspot_api_key' );
}
The HubSpot API uses a bearer token for authentication. This token is your private API key. You’ll include it in the `Authorization` header of your HTTP requests.
Making a GET Request: Fetching Contacts
Let’s start with a common task: fetching a list of contacts from HubSpot. The HubSpot API endpoint for contacts is typically `/crm/v3/objects/contacts`. We’ll use `wp_remote_request()` to send a GET request.
function my_plugin_get_hubspot_contacts() {
$api_key = my_plugin_get_hubspot_api_key();
if ( ! $api_key ) {
return new WP_Error( 'hubspot_api_key_missing', __( 'HubSpot API key is not configured.', 'my-plugin-textdomain' ) );
}
$api_url = 'https://api.hubapi.com/crm/v3/objects/contacts';
$args = array(
'method' => 'GET',
'headers' => array(
'Authorization' => 'Bearer ' . $api_key,
'Content-Type' => 'application/json',
),
'timeout' => 30, // Set a reasonable timeout
);
$response = wp_remote_request( $api_url, $args );
if ( is_wp_error( $response ) ) {
return $response; // Return the WP_Error object
}
$response_code = wp_remote_retrieve_response_code( $response );
$response_body = wp_remote_retrieve_body( $response );
$data = json_decode( $response_body, true );
if ( $response_code && $response_code < 400 ) {
return $data; // Return the decoded JSON data
} else {
// Log the error or return a WP_Error with details
$error_message = isset( $data['message'] ) ? $data['message'] : 'Unknown HubSpot API error.';
return new WP_Error( 'hubspot_api_error', sprintf( __( 'HubSpot API Error (%d): %s', 'my-plugin-textdomain' ), $response_code, $error_message ) );
}
}
// Example usage:
// $contacts = my_plugin_get_hubspot_contacts();
// if ( is_wp_error( $contacts ) ) {
// echo 'Error: ' . $contacts->get_error_message();
// } else {
// // Process $contacts data
// print_r( $contacts );
// }
Making a POST Request: Creating a Contact
To create a new contact in HubSpot, you’ll send a POST request to the same endpoint, but with a JSON payload containing the contact’s properties.
function my_plugin_create_hubspot_contact( $contact_data ) {
$api_key = my_plugin_get_hubspot_api_key();
if ( ! $api_key ) {
return new WP_Error( 'hubspot_api_key_missing', __( 'HubSpot API key is not configured.', 'my-plugin-textdomain' ) );
}
$api_url = 'https://api.hubapi.com/crm/v3/objects/contacts';
// Ensure $contact_data is in the correct format for HubSpot
// Example: $contact_data = array( 'properties' => array( 'email' => '[email protected]', 'firstname' => 'John', 'lastname' => 'Doe' ) );
$body = json_encode( $contact_data );
$args = array(
'method' => 'POST',
'headers' => array(
'Authorization' => 'Bearer ' . $api_key,
'Content-Type' => 'application/json',
),
'body' => $body,
'timeout' => 30,
);
$response = wp_remote_request( $api_url, $args );
if ( is_wp_error( $response ) ) {
return $response;
}
$response_code = wp_remote_retrieve_response_code( $response );
$response_body = wp_remote_retrieve_body( $response );
$data = json_decode( $response_body, true );
if ( $response_code && $response_code < 300 ) { // 201 Created is typical for successful POST
return $data;
} else {
$error_message = isset( $data['message'] ) ? $data['message'] : 'Unknown HubSpot API error.';
return new WP_Error( 'hubspot_api_error', sprintf( __( 'HubSpot API Error (%d): %s', 'my-plugin-textdomain' ), $response_code, $error_message ) );
}
}
// Example usage:
// $new_contact_details = array(
// 'properties' => array(
// 'email' => '[email protected]',
// 'firstname' => 'Jane',
// 'lastname' => 'Doe',
// 'company' => 'Example Corp'
// )
// );
// $created_contact = my_plugin_create_hubspot_contact( $new_contact_details );
// if ( is_wp_error( $created_contact ) ) {
// echo 'Error creating contact: ' . $created_contact->get_error_message();
// } else {
// echo 'Contact created successfully!';
// // print_r( $created_contact );
// }
Handling API Responses and Errors
The WP HTTP API returns a `WP_Error` object if the request fails at the transport level (e.g., network issues, invalid URL). Always check for this using `is_wp_error()`. If the request is successful, `wp_remote_request()` returns a response array. You can then use functions like `wp_remote_retrieve_response_code()`, `wp_remote_retrieve_headers()`, and `wp_remote_retrieve_body()` to inspect the response. HubSpot APIs return JSON, so you’ll need to `json_decode()` the body. Pay close attention to the HTTP status code returned by HubSpot. Codes in the 2xx range generally indicate success, while 4xx and 5xx codes signal client or server errors, respectively. The error response body from HubSpot often contains a `message` field with specific details.
Advanced Considerations: Rate Limiting and Pagination
HubSpot APIs have rate limits to prevent abuse. You’ll typically find these limits documented in their API reference. When making multiple requests, especially in loops or during bulk operations, you must implement logic to respect these limits. This might involve adding delays between requests or using a queueing system. HubSpot’s response headers often include information about your current rate limit status (e.g., `X-RateLimit-Remaining`).
For endpoints that return lists of items (like contacts), HubSpot uses pagination. You’ll usually see `limit` and `after` (or `offset`) parameters in the API request to control which page of results you receive. The response body will often contain a `paging` object with a `next` cursor or URL to fetch the subsequent page. Your code should loop through these pages until no more results are returned.
function my_plugin_get_all_hubspot_contacts() {
$api_key = my_plugin_get_hubspot_api_key();
if ( ! $api_key ) {
return new WP_Error( 'hubspot_api_key_missing', __( 'HubSpot API key is not configured.', 'my-plugin-textdomain' ) );
}
$all_contacts = array();
$after = null; // Initialize for pagination
do {
$api_url = 'https://api.hubapi.com/crm/v3/objects/contacts';
$query_params = array(
'limit' => 100, // Max limit is often 100
);
if ( $after ) {
$query_params['after'] = $after;
}
$api_url .= '?' . http_build_query( $query_params );
$args = array(
'method' => 'GET',
'headers' => array(
'Authorization' => 'Bearer ' . $api_key,
'Content-Type' => 'application/json',
),
'timeout' => 30,
);
$response = wp_remote_request( $api_url, $args );
if ( is_wp_error( $response ) ) {
return $response;
}
$response_code = wp_remote_retrieve_response_code( $response );
$response_body = wp_remote_retrieve_body( $response );
$data = json_decode( $response_body, true );
if ( $response_code && $response_code < 400 ) {
if ( isset( $data['results'] ) ) {
$all_contacts = array_merge( $all_contacts, $data['results'] );
}
// Check for next page
if ( isset( $data['paging']['next']['after'] ) ) {
$after = $data['paging']['next']['after'];
} else {
$after = null; // No more pages
}
} else {
$error_message = isset( $data['message'] ) ? $data['message'] : 'Unknown HubSpot API error.';
return new WP_Error( 'hubspot_api_error', sprintf( __( 'HubSpot API Error (%d): %s', 'my-plugin-textdomain' ), $response_code, $error_message ) );
}
// Implement a small delay to respect rate limits if necessary
// usleep( 200000 ); // 200ms delay
} while ( $after );
return $all_contacts;
}
Security Best Practices
Always use HTTPS for API requests. The WP HTTP API handles this by default when the URL is `https://`. Sanitize all user inputs before sending them to the HubSpot API. Never expose your API key directly in client-side JavaScript. Implement proper error handling and logging to diagnose issues in production. Consider using a dedicated HubSpot integration plugin if your needs are complex, as they often handle many of these advanced scenarios out-of-the-box.