• Skip to secondary menu
  • Skip to main content
  • Skip to primary sidebar
  • Home
  • Projects
  • Products
  • Themes
  • Tools
  • Request for Quote

Vengala Vinay

Having 12+ Years of Experience in Software Development

  • Home
  • WordPress
  • PHP
    • Codeigniter
  • Django
  • Magento
  • Selenium
  • Server
Home » How to securely integrate HubSpot Contacts endpoints into WordPress custom plugins using WP HTTP API

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.

Primary Sidebar

A little about the Author

Having 12+ Years of Experience in Software Development, Vinay is a principal software architect, senior systems engineer, and elite technical consultant. He specializes in bespoke PHP/WordPress development, high-performance Magento 2 & Shopify architectures, custom plugin/theme development from scratch, and legacy code modernization (including VB6, VB.NET, PyQt, and Crystal Reports). Known for solving complex database bottlenecks, speed optimization (Core Web Vitals), and advanced security code auditing, Vinay engineers production-ready systems designed to scale under heavy concurrent load conditions.



Chat on WhatsApp

Recent Posts

  • Debugging Guide: Diagnosing PHP-FPM child process pool exhaustion in multi-site network environments with modern tools
  • Debugging and Resolving complex namespace class loading collisions issues during heavy concurrent database traffic
  • Step-by-Step Guide: Offloading high-frequency customer support tickets metadata writes to a Redis KV store
  • How to refactor legacy event ticket registers queries using modern WP_Query and custom Transient caching
  • Step-by-Step Guide: Offloading high-frequency member profile directories metadata writes to a Redis KV store

Categories

  • apache (1)
  • Business & Monetization (390)
  • Centos (4)
  • Comparisons & Decision Making (55)
  • Debian (2)
  • Debugging & Troubleshooting (662)
  • Desktop Applications (14)
  • DevOps (7)
  • DevOps & Cloud Scaling (962)
  • Django (1)
  • Laravel (4)
  • Migration & Architecture (192)
  • Mobile Applications (24)
  • MySQL (1)
  • Performance & Optimization (873)
  • PHP (5)
  • PHP Development (49)
  • Plugins & Themes (244)
  • Programming Languages (9)
  • Python (20)
  • Ruby on Rails (1)
  • Security & Compliance (647)
  • SEO & Growth (492)
  • Server (118)
  • Ubuntu (9)
  • VB6 & VB.NET (8)
  • Web Applications & Frontend (19)
  • Web Assembly (Wasm) (2)
  • WordPress (22)
  • WordPress Plugin Development (726)
  • WordPress Theme Development (357)

Recent Posts

  • Debugging Guide: Diagnosing PHP-FPM child process pool exhaustion in multi-site network environments with modern tools
  • Debugging and Resolving complex namespace class loading collisions issues during heavy concurrent database traffic
  • Step-by-Step Guide: Offloading high-frequency customer support tickets metadata writes to a Redis KV store

Top Categories

  • DevOps & Cloud Scaling (962)
  • Performance & Optimization (873)
  • WordPress Plugin Development (726)
  • Debugging & Troubleshooting (662)
  • Security & Compliance (647)
  • SEO & Growth (492)

Our Products

  • ERP & LMS Systems (4)
  • Directories & Marketplaces (4)
  • Healthcare Portals (3)
  • Point of Sale (POS) (2)
  • E-Commerce Engines (2)

Our Services

  • E-Commerce Development (10)
  • WordPress Development (8)
  • Python & Desktop GUI (7)
  • General Consulting (7)
  • Legacy Modernization (5)
  • Mobile App Development (4)

Copyright © 2026 · Vinay Vengala