<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Rahul Sharma</title>
    <description>The latest articles on DEV Community by Rahul Sharma (@rahul_sharma_15bd129bc69e).</description>
    <link>https://dev.to/rahul_sharma_15bd129bc69e</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3476785%2F7115035a-75f6-4d9a-926e-0da2af1b4b40.png</url>
      <title>DEV Community: Rahul Sharma</title>
      <link>https://dev.to/rahul_sharma_15bd129bc69e</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rahul_sharma_15bd129bc69e"/>
    <language>en</language>
    <item>
      <title>CF7 Bearer Token vs API Key vs Basic Auth: When to Use Which</title>
      <dc:creator>Rahul Sharma</dc:creator>
      <pubDate>Thu, 01 Oct 2026 07:19:21 +0000</pubDate>
      <link>https://dev.to/rahul_sharma_15bd129bc69e/cf7-bearer-token-vs-api-key-vs-basic-auth-when-to-use-which-4ce5</link>
      <guid>https://dev.to/rahul_sharma_15bd129bc69e/cf7-bearer-token-vs-api-key-vs-basic-auth-when-to-use-which-4ce5</guid>
      <description>&lt;p&gt;You are configuring your Contact Form 7 form to send data to an external API. You open the plugin's authentication settings and see three options: Basic Auth, API Key, and Bearer Token.&lt;/p&gt;

&lt;p&gt;Which one do you choose?&lt;/p&gt;

&lt;p&gt;The answer depends entirely on what the target API expects. Using the wrong method is one of the most common causes of 401 errors, and it is entirely preventable. This guide explains each method, when to use it, and how to configure it correctly.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Three Authentication Methods at a Glance
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;How It Works&lt;/th&gt;
&lt;th&gt;Security Level&lt;/th&gt;
&lt;th&gt;Best For&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Basic Auth&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Username and password encoded in Base64&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;td&gt;Legacy systems, simple integrations, testing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;API Key&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A static key passed in a header or query parameter&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;Internal APIs, simple token-based auth&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Bearer Token&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A token (often JWT) passed in the Authorization header&lt;/td&gt;
&lt;td&gt;Medium-High&lt;/td&gt;
&lt;td&gt;Modern APIs, OAuth 2.0 flows, expiring tokens&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Basic Auth: Simple but Limited
&lt;/h2&gt;

&lt;p&gt;Basic Auth is the oldest and simplest authentication method. You send a username and password with every request, encoded in Base64.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How it works:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The credentials are combined as &lt;code&gt;username:password&lt;/code&gt; and encoded. The request header looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;When to use it:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Basic Auth is appropriate for legacy systems that were built before modern authentication standards existed. It is also useful for quick testing and debugging because it requires no token generation or refresh logic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When to avoid it:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Basic Auth is not inherently secure. The Base64 encoding is not encryption. Anyone who intercepts the request can decode the credentials in seconds. For production integrations, especially those handling sensitive customer data, a more secure method is strongly recommended.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Common use case in CF7 integrations:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Zendesk uses Basic Auth for its API. The username format is &lt;code&gt;email/token&lt;/code&gt;, and the password is your API token. This is a case where Basic Auth is the required method, not a choice. For a full walkthrough of Zendesk authentication, see this guide on &lt;a href="https://www.contactformtoapi.com/contact-form-7-api-authentication-error/" rel="noopener noreferrer"&gt;Contact Form 7 API authentication errors&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  API Key: Simple and Static
&lt;/h2&gt;

&lt;p&gt;An API Key is a static token that identifies your application or account. Unlike Bearer tokens, API keys typically do not expire. You generate them once and use them indefinitely.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How it works:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The key can be passed in several ways, depending on the API. Common locations include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Authorization header:&lt;/strong&gt; &lt;code&gt;Authorization: YOUR_API_KEY&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custom header:&lt;/strong&gt; &lt;code&gt;X-API-Key: your-key-here&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Query parameter:&lt;/strong&gt; &lt;code&gt;?api_key=your-key-here&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The plugin supports custom header configuration, so you can place the API key wherever the target API expects it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When to use it:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;API Keys are common for internal APIs, simple integrations, and services where the key identifies the application rather than a specific user. HubSpot private apps, for example, use an access token that functions like an API key.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Security considerations:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;API keys provide authorization but not authentication. This means the key grants access to resources, but it does not verify who is making the request. If the key is intercepted, anyone can use it. Store API keys in environment variables or secure configuration, never in version control.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bearer Token: Modern and Expiring
&lt;/h2&gt;

&lt;p&gt;Bearer Token authentication is the most common method for modern APIs. The token is typically a JSON Web Token (JWT) or an OAuth 2.0 access token.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How it works:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You first obtain a token from the API's authentication endpoint. Then you include that token in the Authorization header:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Authorization: Bearer your-token-here
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The word "Bearer" means that whoever holds the token can use it. The token itself is a cryptic string that proves your identity.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When to use it:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Bearer Tokens are the standard for OAuth 2.0 flows. If the API documentation mentions OAuth, access tokens, or token expiration, you need Bearer Token authentication. This is common with enterprise platforms like Salesforce, Google Workspace, and Microsoft 365.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Token expiration:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Unlike API keys, Bearer tokens expire. HubSpot access tokens, for example, expire after 30 minutes (1800 seconds). When a token expires, you need to refresh it using a refresh token.&lt;/p&gt;

&lt;p&gt;This is where the plugin's OAuth add-on becomes valuable. The free version does not support automatic token renewal. The PRO add-on handles this automatically, refreshing tokens in the background so your integrations continue running without interruption.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Common use case in CF7 integrations:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;HubSpot private apps use Bearer Token authentication. You generate a token in HubSpot's private app settings and paste it into the plugin's Bearer Token field. The Community forum confirms this is the standard approach for HubSpot integrations.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Choose: A Decision Framework
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Check the API documentation.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is non-negotiable. The API documentation tells you exactly which authentication method it requires. Look for sections labeled "Authentication," "Authorization," or "API Keys."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2: Match the method to the API's requirements.&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;API Says&lt;/th&gt;
&lt;th&gt;Use This Method&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;"Basic Auth" or "username/password"&lt;/td&gt;
&lt;td&gt;Basic Auth&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"API Key" or "X-API-Key"&lt;/td&gt;
&lt;td&gt;API Key&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"Bearer Token" or "OAuth 2.0"&lt;/td&gt;
&lt;td&gt;Bearer Token&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"JWT" or "access token"&lt;/td&gt;
&lt;td&gt;Bearer Token&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Step 3: Consider the security requirements.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If the API supports multiple methods, choose the most secure one. Bearer Tokens with expiration are generally more secure than static API keys, which are more secure than Basic Auth.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 4: Test with the simplest method first.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you are debugging a connection issue, start with Basic Auth or API Key. These are easier to configure and have fewer moving parts. Once the connection works, switch to the more secure method if needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring Authentication in the Plugin
&lt;/h2&gt;

&lt;p&gt;The plugin provides header input fields where you configure authentication manually.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For Basic Auth:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You need to Base64-encode your credentials before pasting them into the header field. The plugin does not execute PHP code in the header textarea, so you must encode the string externally.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For API Key:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Add a custom header with the API key. The exact header name depends on the API. Some use &lt;code&gt;Authorization&lt;/code&gt;, others use &lt;code&gt;X-API-Key&lt;/code&gt;, and some use &lt;code&gt;api-key&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For Bearer Token:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Add the Authorization header with the value &lt;code&gt;Bearer your-token-here&lt;/code&gt;. If your token expires, you will need to update it manually unless you use the PRO add-on with automatic token refresh.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Mistakes to Avoid
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Using Bearer Token for an API that expects Basic Auth.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is the most common 401 error cause. If the API documentation says "Basic Auth" and you send &lt;code&gt;Authorization: Bearer&lt;/code&gt;, the request will be rejected.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Forgetting the "Bearer" prefix.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The header value must be &lt;code&gt;Bearer token-here&lt;/code&gt;, not just &lt;code&gt;token-here&lt;/code&gt;. The prefix tells the API how to interpret the token.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Using an expired token.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Bearer tokens expire. If your integration suddenly stops working after previously working fine, the token may have expired. Check the token's expiration settings in the API's dashboard.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hardcoding credentials in the header without encoding.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For Basic Auth, the credentials must be Base64 encoded. Sending plain &lt;code&gt;username:password&lt;/code&gt; will fail.&lt;/p&gt;

&lt;p&gt;For a deeper dive into JSON structure mapping and header configuration, read this guide on &lt;a href="https://www.contactformtoapi.com/contact-form-7-json-mapping/" rel="noopener noreferrer"&gt;Contact Form 7 JSON mapping&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Beyond Authentication: One Form, Multiple Destinations
&lt;/h2&gt;

&lt;p&gt;Once your authentication is configured correctly, you might want to send the same form submission to multiple tools: a CRM, an email marketing platform, or a help desk system.&lt;/p&gt;

&lt;p&gt;A good connector plugin supports multiple API integrations from a single form submission. You can create a CRM contact, send an SMS via Twilio, and create a Zendesk ticket, all from one CF7 submission, without Zapier. For a cost comparison, see this article on &lt;a href="https://www.contactformtoapi.com/zapier-vs-contact-form-to-api-plugin-cost-comparison/" rel="noopener noreferrer"&gt;Zapier vs a dedicated API plugin&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Check the API documentation first.&lt;/strong&gt; The API tells you which method it requires. Guessing leads to 401 errors.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Basic Auth is for legacy systems and testing.&lt;/strong&gt; It is simple but not secure. Use it when the API requires it, not by choice.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;API Keys are for static integrations.&lt;/strong&gt; They do not expire, which is convenient but less secure. Store them carefully.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bearer Tokens are for modern APIs.&lt;/strong&gt; They expire, which is more secure but requires refresh logic. The PRO add-on handles this automatically.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Match the header format exactly.&lt;/strong&gt; &lt;code&gt;Bearer&lt;/code&gt;, &lt;code&gt;Basic&lt;/code&gt;, and custom prefixes are not interchangeable. One wrong character means a failed request.&lt;/p&gt;

&lt;p&gt;With the right authentication method, correct header formatting, and an understanding of token lifecycle, your CF7 form will connect to any API reliably.&lt;/p&gt;

</description>
      <category>wordpress</category>
      <category>contactform7</category>
      <category>api</category>
      <category>apiintegration</category>
    </item>
    <item>
      <title>CF7 Submit Button Stays Disabled After 422 API Response: A Complete Troubleshooting Guide</title>
      <dc:creator>Rahul Sharma</dc:creator>
      <pubDate>Wed, 30 Sep 2026 08:08:48 +0000</pubDate>
      <link>https://dev.to/rahul_sharma_15bd129bc69e/cf7-submit-button-stays-disabled-after-422-api-response-a-complete-troubleshooting-guide-25df</link>
      <guid>https://dev.to/rahul_sharma_15bd129bc69e/cf7-submit-button-stays-disabled-after-422-api-response-a-complete-troubleshooting-guide-25df</guid>
      <description>&lt;p&gt;You have built a Contact Form 7 form. You have connected it to an external API through a connector plugin. When the API returns a successful response, everything works perfectly the form submits, the button resets, and the user sees a confirmation message.&lt;/p&gt;

&lt;p&gt;But when the API returns a &lt;strong&gt;422 Unprocessable Entity&lt;/strong&gt; error, something strange happens. The form appears to hang. The submit button stays greyed out and disabled. The user cannot retry. They cannot correct their input. They are stuck.&lt;/p&gt;

&lt;p&gt;This is a frustrating and often misunderstood problem. The good news is that it has a clear cause and several possible fixes. This guide walks through the exact debugging process and verified solutions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding What Happens on a 422 Response
&lt;/h2&gt;

&lt;p&gt;When a user clicks the CF7 submit button, several things happen in sequence:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;CF7 validates&lt;/strong&gt; the form fields on the client side.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;CF7 sends&lt;/strong&gt; the submission to WordPress via AJAX.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;The connector plugin intercepts&lt;/strong&gt; the submission and sends a request to your external API.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;The API returns&lt;/strong&gt; a response — either success or an error.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;CF7 receives&lt;/strong&gt; the result and updates the UI accordingly.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A 422 response means the API received the request but could not process it. This is common when a required field is missing, a value is in the wrong format, or a validation rule fails on the API side.&lt;/p&gt;

&lt;p&gt;The problem occurs at step 5. CF7 expects a clean success or failure signal. When the connector plugin passes through a 422 response without properly translating it into CF7's expected format, CF7 does not know how to reset the form. The submit button remains in its disabled state.&lt;/p&gt;

&lt;h2&gt;
  
  
  Failure #1: The Plugin Passes Through the Raw 422 Response
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What you see:&lt;/strong&gt; The form hangs. The submit button stays disabled. No error message appears. The browser console may show a failed AJAX request with a 422 status code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it happens:&lt;/strong&gt; CF7 expects a JSON response with a specific structure. It looks for a &lt;code&gt;status&lt;/code&gt; property with a value of &lt;code&gt;mail_sent&lt;/code&gt;, &lt;code&gt;mail_failed&lt;/code&gt;, &lt;code&gt;validation_failed&lt;/code&gt;, or &lt;code&gt;spam&lt;/code&gt;. When the connector plugin passes through the raw API response which has a different structure CF7 does not recognize it. The JavaScript that re-enables the submit button never runs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fix:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option A: Check your plugin's error handling settings.&lt;/strong&gt; Some connector plugins have an option to "Return CF7-compatible response" or "Handle API errors gracefully." Enable this option if available. This tells the plugin to translate API errors into a format CF7 understands.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option B: Use a custom hook to normalize the response.&lt;/strong&gt; If your plugin does not have this option, you can add a filter to intercept the API response and reformat it before CF7 processes it. Add this to your theme's &lt;code&gt;functions.php&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nf"&gt;add_filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'cf7_to_api_response'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'normalize_422_response'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;normalize_422_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$form_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;isset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'code'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'code'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;422&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="s1"&gt;'status'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'validation_failed'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;'message'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'The form could not be submitted. Please check your input.'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;'invalid_fields'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
        &lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The exact filter name depends on your connector plugin. Check the plugin documentation for the correct hook.&lt;/p&gt;

&lt;p&gt;For a deeper dive into JSON structure mapping and error response handling, read this guide on &lt;a href="https://www.contactformtoapi.com/contact-form-7-json-mapping/" rel="noopener noreferrer"&gt;Contact Form 7 JSON mapping&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Failure #2: JavaScript Error Prevents Button Reset
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What you see:&lt;/strong&gt; The form hangs. The browser console shows a JavaScript error, often related to &lt;code&gt;undefined&lt;/code&gt; or &lt;code&gt;cannot read property of null&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it happens:&lt;/strong&gt; When the API returns a 422, the connector plugin may attempt to display error messages for specific fields. If the API response references a field name that does not exist in the CF7 form, the JavaScript fails. This prevents the button reset code from running.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fix:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Open your browser's developer console.&lt;/strong&gt; Look for red error messages. Note the exact error and the file where it occurs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2: Check field name alignment.&lt;/strong&gt; Compare the field names in your API request with the field names in your CF7 form. A common mistake is using &lt;code&gt;your-email&lt;/code&gt; in the form but &lt;code&gt;email&lt;/code&gt; in the API mapping. When the API returns an error about &lt;code&gt;email&lt;/code&gt;, the plugin cannot find a matching field and crashes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3: Disable error message display temporarily.&lt;/strong&gt; In your connector plugin settings, turn off the option to display API error messages inline. This prevents the JavaScript from attempting to map errors to fields. The form will still fail, but the button should reset.&lt;/p&gt;

&lt;h2&gt;
  
  
  Failure #3: The API Returns 422 Without a Recognized Error Format
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What you see:&lt;/strong&gt; The form hangs. The plugin logs show a 422 response, but the response body does not contain field-specific errors.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it happens:&lt;/strong&gt; Some APIs return a generic 422 response without specifying which field caused the problem. The connector plugin may expect a structured error format and fail when it does not receive one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fix:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option A: Configure a fallback error message.&lt;/strong&gt; In your plugin settings, set a generic error message to display when the API returns an unrecognized error format. This gives the user feedback and allows the form to reset.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option B: Add a timeout to the AJAX request.&lt;/strong&gt; If the API does not return a recognizable response, the JavaScript may wait indefinitely. Add a timeout to force the form to reset after a set period. This can be done with a small JavaScript snippet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;wpcf7submit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;submitButton&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.wpcf7-submit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;submitButton&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;submitButton&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;disabled&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;submitButton&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;disabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="nx"&gt;submitButton&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;disabled&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This snippet waits five seconds after a submit event and force-enables the button if it is still disabled. It is a workaround, not a fix, but it prevents users from being permanently stuck.&lt;/p&gt;

&lt;h2&gt;
  
  
  Failure #4: The Plugin Does Not Reset the Form on API Failure
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What you see:&lt;/strong&gt; The form hangs specifically when the API returns an error. When the API succeeds, the form resets correctly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it happens:&lt;/strong&gt; Some connector plugins only handle the success path. They do not have logic to reset the form when the API call fails. This is a plugin limitation, not a configuration issue.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fix:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option A: Update the plugin.&lt;/strong&gt; Check if a newer version of your connector plugin addresses this issue. Many plugin developers fix error handling in later releases.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option B: Report the issue.&lt;/strong&gt; If the plugin is actively maintained, report the problem with specific details: the API endpoint, the 422 response body, and the observed behavior. Include screenshots of the console error.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option C: Use a different submission mode.&lt;/strong&gt; Some plugins offer a "redirect" mode instead of AJAX. In redirect mode, the form submission navigates to a new page. If the API fails, the user sees the error on the new page and can navigate back. This avoids the disabled button problem entirely.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Debugging Checklist
&lt;/h2&gt;

&lt;p&gt;Work through this sequence every time the submit button stays disabled:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Step&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;th&gt;What It Tells You&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Open browser console&lt;/td&gt;
&lt;td&gt;Is there a JavaScript error? Note the exact message.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Check the plugin's API Logs&lt;/td&gt;
&lt;td&gt;What response did the API return? Is it a 422?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Inspect the 422 response body&lt;/td&gt;
&lt;td&gt;Does it contain field-specific errors?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Compare field names&lt;/td&gt;
&lt;td&gt;Do API error field names match CF7 field names?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Disable inline error display&lt;/td&gt;
&lt;td&gt;Does the button reset when errors are not mapped to fields?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;Check plugin documentation&lt;/td&gt;
&lt;td&gt;Is there a setting for "CF7-compatible response"?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;Test with a successful API call&lt;/td&gt;
&lt;td&gt;Does the button reset correctly on success?&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For a comprehensive breakdown of authentication and error handling across different APIs, see this guide on &lt;a href="https://www.contactformtoapi.com/contact-form-7-api-authentication-error/" rel="noopener noreferrer"&gt;Contact Form 7 API authentication errors&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preventing the Problem: Best Practices for API Error Handling
&lt;/h2&gt;

&lt;p&gt;The best way to avoid the disabled button problem is to ensure your API integration is configured to handle errors gracefully.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Always map API errors to CF7-compatible responses.&lt;/strong&gt; Your connector plugin should translate 422 responses into CF7's &lt;code&gt;validation_failed&lt;/code&gt; status. If it does not, use a filter to do it manually.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Use consistent field names.&lt;/strong&gt; Align your CF7 field names with the API's expected field names. This makes error mapping straightforward and prevents JavaScript crashes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Test error scenarios explicitly.&lt;/strong&gt; Do not just test the happy path. Submit forms with missing required fields, invalid email formats, and values that violate API rules. Verify that the submit button resets in every case.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Set a fallback error message.&lt;/strong&gt; Even if the API returns an unrecognized error format, the user should see a generic message and be able to retry.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Monitor your plugin logs.&lt;/strong&gt; The API Logs page shows every request and response. Review it regularly to catch error handling issues before users report them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Beyond Error Handling: One Form, Multiple Destinations
&lt;/h2&gt;

&lt;p&gt;Once your error handling is solid, you might want to send the same form submission to multiple tools: a CRM, an email marketing platform, or a help desk system.&lt;/p&gt;

&lt;p&gt;A good connector plugin supports multiple API integrations from a single form submission. You can create a CRM contact, send an SMS via Twilio, and create a Zendesk ticket, all from one CF7 submission, without Zapier. For a cost comparison, see this article on &lt;a href="https://www.contactformtoapi.com/zapier-vs-contact-form-to-api-plugin-cost-comparison/" rel="noopener noreferrer"&gt;Zapier vs a dedicated API plugin&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;A 422 response means the API received the request but could not process it.&lt;/strong&gt; This is a validation error, not a connection error.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CF7 expects a specific response structure.&lt;/strong&gt; When the connector plugin passes through a raw API error, CF7 does not know how to reset the form.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;JavaScript errors can prevent the button from re-enabling.&lt;/strong&gt; Check the browser console for errors related to field mapping.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A fallback error message and a timeout script can prevent users from being permanently stuck.&lt;/strong&gt; These are workarounds, not fixes, but they improve the user experience.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The best fix is to configure your plugin to return CF7-compatible responses.&lt;/strong&gt; Check the plugin settings for an option like "Return CF7-compatible response" or use a filter to normalize the response.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Test error scenarios explicitly.&lt;/strong&gt; Do not assume the form will behave correctly when the API fails. Verify it.&lt;/p&gt;

&lt;p&gt;With proper error handling configuration, consistent field naming, and a fallback mechanism, your CF7 form will reset correctly after a 422 response. Users will see a clear error message and be able to retry, instead of being stuck with a disabled button.&lt;/p&gt;

</description>
      <category>wordpress</category>
      <category>contactform7</category>
      <category>api</category>
      <category>wordpressdevelopment</category>
    </item>
    <item>
      <title>CF7 to Odoo ERP Not Creating Leads: A Complete Troubleshooting Guide</title>
      <dc:creator>Rahul Sharma</dc:creator>
      <pubDate>Tue, 29 Sep 2026 09:43:29 +0000</pubDate>
      <link>https://dev.to/rahul_sharma_15bd129bc69e/cf7-to-odoo-erp-not-creating-leads-a-complete-troubleshooting-guide-147o</link>
      <guid>https://dev.to/rahul_sharma_15bd129bc69e/cf7-to-odoo-erp-not-creating-leads-a-complete-troubleshooting-guide-147o</guid>
      <description>&lt;p&gt;You have configured your Contact Form 7 form to create leads in Odoo. You have entered your Odoo URL, database name, and API credentials. And yet, no leads appear in your Odoo CRM after a form submission.&lt;/p&gt;

&lt;p&gt;This is a frustratingly common problem. The good news? The issue is almost always one of four things, and each has a clear fix. This guide walks through the exact debugging process, common error patterns, and verified solutions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding the Data Flow
&lt;/h2&gt;

&lt;p&gt;When a user submits your CF7 form with Odoo lead creation enabled, here is what should happen:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User submits form → Plugin captures data → API request sent to Odoo → Lead created
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Odoo supports multiple API protocols depending on your version. The most common are XML-RPC (older versions) and JSON-RPC (all versions), with newer REST endpoints available in Odoo 17+. Your integration plugin handles the protocol details, but you need to ensure the payload matches what Odoo expects.&lt;/p&gt;

&lt;p&gt;Your first diagnostic tool is the &lt;strong&gt;plugin's API Logs&lt;/strong&gt;. It shows whether a request was sent, the exact JSON payload, and the response from Odoo. If no request appears in the logs, the problem is on the WordPress side. For a deeper breakdown of that specific scenario, see this guide on &lt;a href="https://www.contactformtoapi.com/contact-form-7-data-not-reaching-api/" rel="noopener noreferrer"&gt;Contact Form 7 data not reaching the API&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Failure #1: Invalid Field Error (KeyError: 'is_company')
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What you see:&lt;/strong&gt; An error in Odoo's server logs referencing &lt;code&gt;KeyError: 'is_company'&lt;/code&gt; or &lt;code&gt;ValueError: Invalid field 'is_company' on model 'crm.lead'&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it happens:&lt;/strong&gt; This is a known issue with some Odoo integration plugins. The plugin is sending a field called &lt;code&gt;is_company&lt;/code&gt; to the &lt;code&gt;crm.lead&lt;/code&gt; model, but that field does not exist on that model.&lt;/p&gt;

&lt;p&gt;In Odoo, &lt;code&gt;is_company&lt;/code&gt; is a field on the &lt;code&gt;res.partner&lt;/code&gt; model, not on &lt;code&gt;crm.lead&lt;/code&gt;. When you create a lead, Odoo may automatically create or link a partner record, but the &lt;code&gt;is_company&lt;/code&gt; flag belongs to the partner, not the lead itself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fix:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option A: Update the plugin.&lt;/strong&gt; If you are using a plugin with this known bug, check for a patch or update. In one reported case, the developer released version 3.3.1 specifically to fix this issue. Update your plugin and retry.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option B: Remove the field from your mapping.&lt;/strong&gt; If updating is not possible, check your field mapping configuration. If you have mapped any CF7 field to &lt;code&gt;is_company&lt;/code&gt;, remove that mapping. This field is not required for lead creation and should not be sent.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to verify:&lt;/strong&gt; After updating or removing the mapping, submit a test form. Check Odoo's logs and your CRM. If the lead appears, the issue is resolved.&lt;/p&gt;

&lt;h2&gt;
  
  
  Failure #2: Missing Required Field (Name)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What you see:&lt;/strong&gt; An error message stating: "The operation cannot be completed: Create/update: a mandatory field is not set. Model: Lead/Opportunity (crm.lead), Field: Opportunity (name)".&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it happens:&lt;/strong&gt; The &lt;code&gt;name&lt;/code&gt; field is mandatory for the &lt;code&gt;crm.lead&lt;/code&gt; model in Odoo. Every lead must have a title or name. If your CF7 form does not include a field mapped to &lt;code&gt;name&lt;/code&gt;, or if that field is left empty, Odoo will reject the request.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fix:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Verify your mapping.&lt;/strong&gt; Ensure at least one CF7 field is mapped to the Odoo &lt;code&gt;name&lt;/code&gt; field. This could be a subject field, a concatenation of name and company, or a generic "Website Lead" title.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2: Use a hidden field if needed.&lt;/strong&gt; If your form does not have a natural field for the lead name, add a hidden field with a default value. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[hidden lead-title default:get "Website Lead"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or use a static value:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[hidden type "lead"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As demonstrated in a WordPress support thread, adding a hidden field with a default value and mapping it to the Odoo field works reliably.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3: Ensure the field is never empty.&lt;/strong&gt; If you are using a user-filled field for the lead name, make it required in CF7. If you want to allow it to be empty, use a hook to inject a fallback value before submission.&lt;/p&gt;

&lt;h2&gt;
  
  
  Failure #3: Connection Refused (Port Blocked)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What you see:&lt;/strong&gt; An error message stating "Connect error: Connection refused (111)" or similar connection failure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it happens:&lt;/strong&gt; Your WordPress hosting server is blocking outbound requests to Odoo's port (typically 8069 or 443). This is a common security measure on shared hosting environments.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fix:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Contact your hosting provider.&lt;/strong&gt; Ask them to open outbound cURL requests to Odoo's port. In one reported case, the user's hosting provider had blocked port 8069. After opening it, the integration worked immediately.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2: Verify with Postman.&lt;/strong&gt; Before blaming the plugin, test the connection directly. Use Postman to send a POST request to your Odoo instance. If that works but the plugin does not, the issue is likely the hosting firewall blocking the specific request path.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3: Check your Odoo URL.&lt;/strong&gt; Ensure you are using the correct URL format. For Odoo Online, it should be &lt;code&gt;https://yourcompany.odoo.com&lt;/code&gt;. For self-hosted, it should be &lt;code&gt;https://yourdomain.com:8069&lt;/code&gt; or your configured port.&lt;/p&gt;

&lt;h2&gt;
  
  
  Failure #4: Authentication Failure
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What you see:&lt;/strong&gt; A 401 Unauthorized or 403 Forbidden response in the plugin logs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it happens:&lt;/strong&gt; Odoo's authentication is strict. The plugin is either using the wrong credentials, or the user account lacks permission to create leads.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fix:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Verify your credentials.&lt;/strong&gt; Odoo requires:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Database name&lt;/strong&gt; (for multi-database setups)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Username&lt;/strong&gt; (your Odoo login email)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Password or API Key&lt;/strong&gt; (API keys are recommended for security)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Step 2: Create a dedicated API user.&lt;/strong&gt; For production integrations, do not use your personal admin account. Create a dedicated "bot" user in Odoo with only the minimum permissions needed to create leads. Generate an API key for this user.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3: Check user permissions.&lt;/strong&gt; The user account must have permission to create records in the &lt;code&gt;crm.lead&lt;/code&gt; model. Verify this in Odoo's Settings &amp;gt; Users &amp;amp; Companies &amp;gt; Users.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 4: Check Odoo plan restrictions.&lt;/strong&gt; If you are using Odoo Online, the external API for write operations (like creating leads) may require a Custom plan for high-volume usage. Basic read operations work on all plans, but write access at scale may be restricted.&lt;/p&gt;

&lt;p&gt;For a comprehensive breakdown of authentication errors across different APIs, see this guide on &lt;a href="https://www.contactformtoapi.com/contact-form-7-api-authentication-error/" rel="noopener noreferrer"&gt;Contact Form 7 API authentication errors&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Debugging Checklist
&lt;/h2&gt;

&lt;p&gt;Work through this sequence every time a lead fails to create:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Step&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;th&gt;What It Tells You&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Check the plugin's API Logs&lt;/td&gt;
&lt;td&gt;Was a request sent? If not, the problem is in WordPress.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Inspect the Response Code&lt;/td&gt;
&lt;td&gt;401/403 = Auth issue. 422 = Field validation issue. 500 = Odoo server error.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Check Odoo's server logs&lt;/td&gt;
&lt;td&gt;Look for specific KeyError or ValueError messages.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Test with a minimal payload&lt;/td&gt;
&lt;td&gt;Hardcode values (name, email) to isolate field mapping issues.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Verify field mapping&lt;/td&gt;
&lt;td&gt;Ensure &lt;code&gt;name&lt;/code&gt; is mapped. Remove any &lt;code&gt;is_company&lt;/code&gt; mapping.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;Test connection with Postman&lt;/td&gt;
&lt;td&gt;Isolates hosting firewall issues from plugin issues.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For a deeper dive into JSON structure mapping, read this guide on &lt;a href="https://www.contactformtoapi.com/contact-form-7-json-mapping/" rel="noopener noreferrer"&gt;Contact Form 7 JSON mapping&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Beyond Odoo: One Form, Multiple Destinations
&lt;/h2&gt;

&lt;p&gt;Once your Odoo integration works, you might want to send the same form submission to other tools: a CRM, an email marketing platform, or a help desk system.&lt;/p&gt;

&lt;p&gt;A good connector plugin supports multiple API integrations from a single form submission. You can create an Odoo lead, add the contact to HubSpot, subscribe them to Mailchimp, and create a Zendesk ticket, all from one CF7 submission, without Zapier. For a cost comparison, see this article on &lt;a href="https://www.contactformtoapi.com/zapier-vs-contact-form-to-api-plugin-cost-comparison/" rel="noopener noreferrer"&gt;Zapier vs a dedicated API plugin&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The &lt;code&gt;name&lt;/code&gt; field is mandatory.&lt;/strong&gt; Every Odoo lead must have a title. Map a CF7 field to it, or use a hidden field with a default value.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Remove &lt;code&gt;is_company&lt;/code&gt; from lead mappings.&lt;/strong&gt; This field belongs to the partner model, not the lead model. Sending it to &lt;code&gt;crm.lead&lt;/code&gt; causes a KeyError.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Check for blocked ports.&lt;/strong&gt; Shared hosting often blocks outbound requests to Odoo's port. Contact your hosting provider if you see "Connection refused."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use API keys, not passwords.&lt;/strong&gt; Odoo 19 and newer versions support API keys as the preferred authentication method. Create a dedicated bot user for integrations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Odoo is modular.&lt;/strong&gt; The fields available on &lt;code&gt;crm.lead&lt;/code&gt; depend on which modules are installed. A field that works in your Odoo instance may not exist in another.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Test in Postman first.&lt;/strong&gt; If Postman works but the plugin does not, the problem is plugin configuration or hosting firewall. If Postman fails, the problem is Odoo configuration or credentials.&lt;/p&gt;

&lt;p&gt;With the correct field mapping, valid authentication, and a quick check of the logs when things go wrong, your CF7-to-Odoo integration will create leads reliably every time.&lt;/p&gt;

</description>
      <category>wordpress</category>
      <category>contactform7</category>
      <category>odoo</category>
      <category>apiintegration</category>
    </item>
    <item>
      <title>CF7 + WPML Multilingual Forms Not Sending Correct Data to CRM: A Complete Troubleshooting Guide</title>
      <dc:creator>Rahul Sharma</dc:creator>
      <pubDate>Mon, 28 Sep 2026 10:19:39 +0000</pubDate>
      <link>https://dev.to/rahul_sharma_15bd129bc69e/cf7-wpml-multilingual-forms-not-sending-correct-data-to-crm-a-complete-troubleshooting-guide-250k</link>
      <guid>https://dev.to/rahul_sharma_15bd129bc69e/cf7-wpml-multilingual-forms-not-sending-correct-data-to-crm-a-complete-troubleshooting-guide-250k</guid>
      <description>&lt;p&gt;You have built a Contact Form 7 form on your WordPress site. You have translated it into multiple languages using WPML. You have configured the integration to send submissions to your CRM. And yet, when a visitor submits the form in a non-default language, the CRM either receives nothing, receives the wrong data, or creates records with missing fields.&lt;/p&gt;

&lt;p&gt;This is one of the most frustrating multilingual integration problems. The form works. The translation displays correctly. But the data pipeline breaks somewhere between the form submission and the CRM record.&lt;/p&gt;

&lt;p&gt;This guide walks through the exact causes, the debugging process, and verified solutions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding the WPML + CF7 + CRM Architecture
&lt;/h2&gt;

&lt;p&gt;When you use WPML with Contact Form 7, the architecture involves multiple layers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;WPML Translation Layer → CF7 Form Rendering → Form Submission → API Plugin → CRM
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each layer introduces potential failure points. The most common issues fall into four categories:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Translation configuration problems&lt;/strong&gt; (WPML not set up correctly for CF7)&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Field mapping issues&lt;/strong&gt; (CF7 field names not matching API expectations)&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Pipe-separated value handling&lt;/strong&gt; (dropdown options behaving unexpectedly)&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Integration settings not replicated&lt;/strong&gt; (plugin configuration missing on translated forms)&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The WPML + CF7 Translation Setup: What You Need to Know
&lt;/h2&gt;

&lt;p&gt;Before debugging CRM integration, you must verify that WPML is correctly translating your CF7 form. WPML provides an official add-on called &lt;strong&gt;WPML Multilingual for CF7&lt;/strong&gt; that handles the translation glue between the two plugins.&lt;/p&gt;

&lt;h3&gt;
  
  
  How It Should Work
&lt;/h3&gt;

&lt;p&gt;According to WPML's official documentation, the recommended workflow is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Build the form once&lt;/strong&gt; in your site's default language.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Send the form for translation&lt;/strong&gt; through WPML's translation dashboard.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Use the same shortcode&lt;/strong&gt; on translated pages. WPML serves the translated version automatically based on the visitor's language.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The critical rule: &lt;strong&gt;Do not create separate forms for each language.&lt;/strong&gt; Use one form, translated through WPML's system.&lt;/p&gt;

&lt;h3&gt;
  
  
  Common Translation Mistakes
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Mistake 1: Creating separate forms per language.&lt;/strong&gt; If you duplicate the form for each language, the API integration settings are also duplicated. Each form needs its own API configuration, and missing settings on any language's form will cause failures.&lt;/p&gt;

&lt;p&gt;A WordPress forum user reported exactly this: their form worked in German but failed in English. The email sent correctly, but the Brevo (Sendinblue) CRM integration did not. The solution was to manually re-check the CRM list selection on the translated form's settings.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mistake 2: Assuming translation is automatic for integration settings.&lt;/strong&gt; WPML translates form tags, messages, and mail templates. It does &lt;strong&gt;not&lt;/strong&gt; automatically replicate plugin integration settings. You must manually verify that your CRM integration is configured on each language version.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Pipe-Separated Value Problem
&lt;/h2&gt;

&lt;p&gt;This is the most subtle and damaging issue for multilingual CRM integrations.&lt;/p&gt;

&lt;h3&gt;
  
  
  What Pipe Syntax Does
&lt;/h3&gt;

&lt;p&gt;Contact Form 7 supports pipe-separated values in dropdowns:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[select your-country "China" "India" "San Marino"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With pipe syntax, you can display one label to the user but submit a different value:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[select your-country "China|CN" "India|IN" "San Marino|SM"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The user sees "China" but the form submits "CN".&lt;/p&gt;

&lt;h3&gt;
  
  
  How WPML Handles This
&lt;/h3&gt;

&lt;p&gt;According to WPML's official documentation, WPML Multilingual for CF7 &lt;strong&gt;translates the visitor-facing labels while keeping the submitted value canonical&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A French visitor sees "Chine" instead of "China". But the form submission, the email body, and your CRM receive the original English value "China" (or "CN" if you used pipe syntax).&lt;/p&gt;

&lt;h3&gt;
  
  
  Why This Breaks CRM Integrations
&lt;/h3&gt;

&lt;p&gt;The problem occurs when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You &lt;strong&gt;did not use pipe syntax&lt;/strong&gt; in the original form.&lt;/li&gt;
&lt;li&gt;WPML translates the label to "Chine".&lt;/li&gt;
&lt;li&gt;The submitted value becomes "Chine" instead of "China".&lt;/li&gt;
&lt;li&gt;Your CRM expects "China" (or a specific country code).&lt;/li&gt;
&lt;li&gt;The CRM rejects the value, ignores it, or stores incorrect data.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Fix
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Always use pipe syntax for dropdown values that feed into a CRM.&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Wrong&lt;/th&gt;
&lt;th&gt;Right&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[select country "China" "India"]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;`[select country "China\&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This ensures the submitted value remains stable regardless of the visitor's language. The CRM always receives the canonical value, while visitors see translated labels.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Field Mapping Problem in Multilingual Contexts
&lt;/h2&gt;

&lt;p&gt;Even when WPML works correctly, field mapping between CF7 and your CRM can fail.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Field Mapping Breaks
&lt;/h3&gt;

&lt;p&gt;A field mapping problem is not a connection problem. The API can return a successful response while the data ends up in the wrong CRM fields.&lt;/p&gt;

&lt;p&gt;Common scenarios:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your CF7 field is named {% raw %}&lt;code&gt;your-name&lt;/code&gt;, but the CRM API expects &lt;code&gt;first_name&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Your form field is named &lt;code&gt;company&lt;/code&gt;, but the CRM expects &lt;code&gt;organization&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Your dropdown submits a label, but the CRM expects an ID.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Translation Layer Analogy
&lt;/h3&gt;

&lt;p&gt;Think of field mapping as a translation layer. The form field names and the CRM field names are not automatically the same. Your integration needs to explicitly translate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;company → organization
your-email → email_address
inquiry-type → lead_source
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without this mapping, the API may ignore the value, place it somewhere unexpected, or reject the request.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Fix
&lt;/h3&gt;

&lt;p&gt;Create a mapping table before configuring the API plugin:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Contact Form 7 Field&lt;/th&gt;
&lt;th&gt;API Field&lt;/th&gt;
&lt;th&gt;CRM Field&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;your-name&lt;/td&gt;
&lt;td&gt;name&lt;/td&gt;
&lt;td&gt;Name&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;your-email&lt;/td&gt;
&lt;td&gt;email&lt;/td&gt;
&lt;td&gt;Email&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;your-phone&lt;/td&gt;
&lt;td&gt;phone&lt;/td&gt;
&lt;td&gt;Phone&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;company&lt;/td&gt;
&lt;td&gt;organization&lt;/td&gt;
&lt;td&gt;Company&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;inquiry-type&lt;/td&gt;
&lt;td&gt;lead_source&lt;/td&gt;
&lt;td&gt;Lead Source&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Verify each mapping in the plugin's JSON payload configuration. Test with a hardcoded value first, then replace with CF7 tags. For a deeper dive into JSON structure mapping, read this guide on &lt;a href="https://www.contactformtoapi.com/contact-form-7-json-mapping/" rel="noopener noreferrer"&gt;Contact Form 7 JSON mapping&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Integration Settings Not Replicated Problem
&lt;/h2&gt;

&lt;p&gt;This is specific to WPML's translation workflow.&lt;/p&gt;

&lt;h3&gt;
  
  
  What Happens
&lt;/h3&gt;

&lt;p&gt;When WPML translates a CF7 form, it creates a translated version of the form. However, &lt;strong&gt;third-party plugin settings are not automatically replicated&lt;/strong&gt; to the translated form.&lt;/p&gt;

&lt;p&gt;A WordPress user described this exactly: their Brevo integration worked in French but failed in English. The PHP debug log showed no errors related to the form itself. The email sent fine. But the CRM contact was not created.&lt;/p&gt;

&lt;p&gt;The root cause: the Brevo list selection was not enabled on the English version of the form.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Fix
&lt;/h3&gt;

&lt;p&gt;For every translated form version:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Open the translated form in CF7 editor.&lt;/li&gt;
&lt;li&gt; Navigate to your API plugin's settings tab for that form.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Manually verify&lt;/strong&gt; that all integration settings are enabled and configured.&lt;/li&gt;
&lt;li&gt; Save the form.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;WPML does not sync plugin-specific settings across translations. You must do this manually.&lt;/p&gt;

&lt;h2&gt;
  
  
  The CF7 Not Sending in Translated Language Problem
&lt;/h2&gt;

&lt;p&gt;Sometimes the problem is not the CRM integration at all. The form itself fails to submit in the translated language.&lt;/p&gt;

&lt;h3&gt;
  
  
  The REST API URL Issue
&lt;/h3&gt;

&lt;p&gt;WPML has a known issue where the REST API URL for CF7 includes the language parameter incorrectly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;/wp-json/?lang=en/contact-form-7/v1/contact-forms/11187/feedback
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This causes a 404 error, and the form never submits. For a full breakdown of data not reaching your API, see this guide on &lt;a href="https://www.contactformtoapi.com/contact-form-7-data-not-reaching-api/" rel="noopener noreferrer"&gt;Contact Form 7 data not reaching the API&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Fix
&lt;/h3&gt;

&lt;p&gt;Add this to your theme's &lt;code&gt;functions.php&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nf"&gt;add_filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s1"&gt;'wpcf7_load_js'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'__return_false'&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or switch WPML's URL format from "language name added as a parameter" to "different languages in directories".&lt;/p&gt;

&lt;p&gt;This is a WPML bug, not a plugin issue. But it prevents the form from submitting, which means no data reaches your CRM.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Debugging Checklist
&lt;/h2&gt;

&lt;p&gt;Work through this sequence for every multilingual CRM integration failure:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Step&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;th&gt;What It Tells You&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Test the form in the default language&lt;/td&gt;
&lt;td&gt;Does the CRM receive data? If yes, the problem is translation-specific.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Test the form in a translated language&lt;/td&gt;
&lt;td&gt;Does the form submit at all? If not, check the REST API URL issue.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Check the plugin's API Logs&lt;/td&gt;
&lt;td&gt;Was a request sent? What was the response code?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Inspect the JSON payload in logs&lt;/td&gt;
&lt;td&gt;Are the field values correct? Are translated values being sent?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Verify pipe syntax in dropdowns&lt;/td&gt;
&lt;td&gt;Are labels translated while values stay canonical?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;Check integration settings on translated form&lt;/td&gt;
&lt;td&gt;Are CRM settings enabled for this language version?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;Verify field mapping&lt;/td&gt;
&lt;td&gt;Do CF7 field names match API expectations?&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Beyond CRM: One Form, Multiple Destinations
&lt;/h2&gt;

&lt;p&gt;Once your multilingual CRM integration works, you might want to send the same submission to other tools: an email marketing platform, a help desk system, or an SMS notification service.&lt;/p&gt;

&lt;p&gt;A good connector plugin supports multiple API integrations from a single form submission. You can create a CRM contact, send an SMS via Twilio, create a Zendesk ticket, and subscribe them to Mailchimp, all from one CF7 submission, without Zapier. For a cost comparison, see this article on &lt;a href="https://www.contactformtoapi.com/zapier-vs-contact-form-to-api-plugin-cost-comparison/" rel="noopener noreferrer"&gt;Zapier vs a dedicated API plugin&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Use pipe syntax for all dropdown values.&lt;/strong&gt; This keeps submitted values stable across languages while visitors see translated labels.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do not create separate forms per language.&lt;/strong&gt; Use WPML's official translation workflow. Separate forms mean separate integration settings and more failure points.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Manually verify integration settings on every translated form.&lt;/strong&gt; WPML does not sync third-party plugin settings across translations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Check the REST API URL if forms do not submit in translated languages.&lt;/strong&gt; This is a known WPML bug with a simple fix.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Field mapping is not a connection problem.&lt;/strong&gt; The API can succeed while data goes to the wrong fields. Always verify the mapping table.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Test in the default language first.&lt;/strong&gt; If it works there, the problem is translation-specific. If it fails there too, the problem is in your API configuration.&lt;/p&gt;

&lt;p&gt;With correct pipe syntax, verified integration settings on every translated form, and careful field mapping, your CF7 + WPML + CRM integration will deliver accurate data in every language.&lt;/p&gt;

</description>
      <category>wordpress</category>
      <category>contactform7</category>
      <category>crm</category>
      <category>api</category>
    </item>
    <item>
      <title>CF7 to Twilio SMS Not Sending After Form Submit: A Complete Troubleshooting Guide</title>
      <dc:creator>Rahul Sharma</dc:creator>
      <pubDate>Fri, 25 Sep 2026 12:48:03 +0000</pubDate>
      <link>https://dev.to/rahul_sharma_15bd129bc69e/cf7-to-twilio-sms-not-sending-after-form-submit-a-complete-troubleshooting-guide-4ihi</link>
      <guid>https://dev.to/rahul_sharma_15bd129bc69e/cf7-to-twilio-sms-not-sending-after-form-submit-a-complete-troubleshooting-guide-4ihi</guid>
      <description>&lt;p&gt;You have configured your Contact Form 7 form to trigger an SMS notification through Twilio. You have entered your Account SID and Auth Token. And yet, no text message arrives on your phone after a form submission.&lt;/p&gt;

&lt;p&gt;This is a frustratingly common problem. The good news? The issue is almost always one of four things, and each has a clear fix. This guide walks through the exact debugging process, common error patterns, and verified solutions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding the Data Flow
&lt;/h2&gt;

&lt;p&gt;When a user submits your CF7 form with Twilio SMS notifications enabled, here is what should happen:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User submits form → Plugin captures data → POST request sent to Twilio API → SMS delivered
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When it breaks, the failure happens at one of the last two stages. Your first diagnostic tool is the &lt;strong&gt;Twilio Console logs&lt;/strong&gt;. It shows whether a request was sent at all, the exact message content, and the delivery status.&lt;/p&gt;

&lt;p&gt;If no request appears in Twilio logs, the problem is on the WordPress side. For a deeper breakdown of that specific scenario, see this guide on &lt;a href="https://www.contactformtoapi.com/contact-form-7-data-not-reaching-api/" rel="noopener noreferrer"&gt;Contact Form 7 data not reaching the API&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Failure #1: The Phone Number Format Problem
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What you see:&lt;/strong&gt; SMS History shows "sent" but no message arrives. Or the plugin throws a validation error.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it happens:&lt;/strong&gt; Twilio requires phone numbers in &lt;strong&gt;E.164 format&lt;/strong&gt;. This means a plus sign, country code, and the full number with no spaces or dashes. For example: &lt;code&gt;+14155552671&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A common mistake is entering a domestic number without the country code. The plugin may accept it, but Twilio will reject or silently fail to deliver the message.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fix:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Setting&lt;/th&gt;
&lt;th&gt;Correct Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;To (recipient)&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;+14155552671&lt;/code&gt; (country code + number)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;From (Twilio number)&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;+14155552671&lt;/code&gt; (your active Twilio number)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;How to verify:&lt;/strong&gt; Send a test SMS directly from your Twilio Console. If that works but the plugin does not, the issue is likely the number format in the plugin settings.&lt;/p&gt;

&lt;h2&gt;
  
  
  Failure #2: The Tags Not Working Problem
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What you see:&lt;/strong&gt; The SMS sends and arrives perfectly when using plain text. But when you add CF7 tags like &lt;code&gt;[your-name]&lt;/code&gt; or &lt;code&gt;[your-message]&lt;/code&gt;, the message never arrives. Or it arrives empty.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it happens:&lt;/strong&gt; This is a known issue in some CF7-to-Twilio integrations. The tags are not being replaced with actual form data before the SMS is sent. Possible causes include a plugin bug, a conflict with another form plugin, or an issue with how the tags are formatted.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fix:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option A: Check the SMS History tab.&lt;/strong&gt; Some plugins have an SMS History feature that shows the actual content sent. If the history shows the raw tags (e.g., &lt;code&gt;[your-name]&lt;/code&gt;) instead of the replaced values, the tag replacement is failing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option B: Test with a minimal payload.&lt;/strong&gt; Create a simple form with just one text field. Add that field's tag to the SMS content. Submit the form and check if the tag is replaced. If not, the issue is in the plugin.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option C: Contact the plugin developer.&lt;/strong&gt; This is a known bug in some integrations. The developer may have a pre-release version that fixes the tag replacement issue. Provide them with your CF7 version, plugin version, and screenshots of the SMS History showing the unreplaced tags.&lt;/p&gt;

&lt;p&gt;For a deeper dive into how field mapping works, read this guide on &lt;a href="https://www.contactformtoapi.com/contact-form-7-json-mapping/" rel="noopener noreferrer"&gt;Contact Form 7 JSON mapping&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Failure #3: The Twilio Account Configuration Problem
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What you see:&lt;/strong&gt; No SMS record appears in Twilio logs at all. The form submits successfully, but Twilio never receives a request.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it happens:&lt;/strong&gt; The plugin cannot authenticate with Twilio, or the Twilio number is not properly configured for SMS.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fix:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Verify your credentials.&lt;/strong&gt; Go to Twilio Console homepage and confirm your Account SID and Auth Token are correct. Copy them fresh into the plugin settings.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2: Check your Twilio number.&lt;/strong&gt; Navigate to Phone Numbers &amp;gt; Manage &amp;gt; Active Numbers. Verify that your Twilio number has SMS capabilities. Numbers that cannot send SMS will not work for this integration.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3: Check for trial account restrictions.&lt;/strong&gt; If you are using a Twilio trial account, you can only send SMS to &lt;strong&gt;verified phone numbers&lt;/strong&gt;. Add your recipient number to the verified list in Twilio Console, or upgrade your account.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 4: Check A2P 10DLC registration.&lt;/strong&gt; As of September 2023, US carriers require A2P 10DLC registration for business SMS. If your registration is incomplete or failed, carriers will block your messages.&lt;/p&gt;

&lt;h2&gt;
  
  
  Failure #4: The API Error Response Problem
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What you see:&lt;/strong&gt; A specific error code appears in the plugin settings when you enable error display, or in Twilio logs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it happens:&lt;/strong&gt; Twilio is returning an error that tells you exactly what is wrong.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Common Twilio error codes and fixes:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Error Code&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;th&gt;Fix&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;21604&lt;/td&gt;
&lt;td&gt;"To" phone number is required&lt;/td&gt;
&lt;td&gt;Add the recipient phone number in the plugin settings&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;14101&lt;/td&gt;
&lt;td&gt;Invalid "To" attribute&lt;/td&gt;
&lt;td&gt;Check number format and verify the number if using a trial account&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4XX&lt;/td&gt;
&lt;td&gt;General API error&lt;/td&gt;
&lt;td&gt;Look up the specific code in Twilio's error documentation&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;The fix:&lt;/strong&gt; Enable the "Show Error Message" option in your plugin settings. Submit the form again. Copy the exact error message and look it up in Twilio's API error documentation.&lt;/p&gt;

&lt;p&gt;For a full breakdown of timeout issues that may affect SMS delivery, refer to this article on &lt;a href="https://www.contactformtoapi.com/contact-form-7-api-timeout/" rel="noopener noreferrer"&gt;Contact Form 7 API timeout&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Debugging Checklist
&lt;/h2&gt;

&lt;p&gt;Work through this sequence every time an SMS fails to send:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Step&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;th&gt;What It Tells You&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Check Twilio Console logs&lt;/td&gt;
&lt;td&gt;Was a request sent? If not, the problem is in WordPress.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Check plugin SMS History&lt;/td&gt;
&lt;td&gt;What content was sent? Are tags replaced?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Enable error display&lt;/td&gt;
&lt;td&gt;What specific error is returned?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Test with hardcoded values&lt;/td&gt;
&lt;td&gt;Isolates tag issues from configuration issues.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Verify number format&lt;/td&gt;
&lt;td&gt;E.164 format: +[country code][number]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;Check trial account limits&lt;/td&gt;
&lt;td&gt;Are you sending to a verified number?&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Beyond SMS: One Form, Multiple Destinations
&lt;/h2&gt;

&lt;p&gt;Once your Twilio SMS integration works, you might want to send the same form submission to other tools: a CRM, an email marketing platform, or a help desk system.&lt;/p&gt;

&lt;p&gt;A good connector plugin supports multiple API integrations from a single form submission. You can send an SMS via Twilio, create a Zendesk ticket, add the contact to HubSpot, and subscribe them to Mailchimp, all from one CF7 submission, without Zapier. For a cost comparison, see this article on &lt;a href="https://www.contactformtoapi.com/zapier-vs-contact-form-to-api-plugin-cost-comparison/" rel="noopener noreferrer"&gt;Zapier vs a dedicated API plugin&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Phone numbers must be in E.164 format&lt;/strong&gt; (+14155552671). Domestic-only formats will fail.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tags not working&lt;/strong&gt; is a known bug in some integrations. Test with plain text first, then add tags one at a time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Twilio trial accounts&lt;/strong&gt; can only send to verified numbers. Upgrade or verify your recipients.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A2P 10DLC registration&lt;/strong&gt; is now required for US business SMS. Incomplete registration means blocked messages.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Twilio Console logs&lt;/strong&gt; are your best debugging tool. Check them first, every time.&lt;/p&gt;

&lt;p&gt;With the right number format, correct account configuration, and a quick check of the logs when things go wrong, your CF7-to-Twilio SMS notifications will work reliably every time.&lt;/p&gt;

</description>
      <category>wordpress</category>
      <category>contactform7</category>
      <category>twilio</category>
      <category>automation</category>
    </item>
    <item>
      <title>Debugging CF7 to Zendesk Ticket Creation Failures: A Complete Troubleshooting Guide</title>
      <dc:creator>Rahul Sharma</dc:creator>
      <pubDate>Thu, 24 Sep 2026 12:49:12 +0000</pubDate>
      <link>https://dev.to/rahul_sharma_15bd129bc69e/debugging-cf7-to-zendesk-ticket-creation-failures-a-complete-troubleshooting-guide-26ej</link>
      <guid>https://dev.to/rahul_sharma_15bd129bc69e/debugging-cf7-to-zendesk-ticket-creation-failures-a-complete-troubleshooting-guide-26ej</guid>
      <description>&lt;p&gt;Integrating Contact Form 7 (CF7) with Zendesk's Ticketing API is a powerful way to automate lead capture and support ticket creation. However, this integration frequently fails due to subtle configuration errors in authentication or payload structure. This guide walks through the exact debugging process, common error codes, and verified fixes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding the Data Flow
&lt;/h2&gt;

&lt;p&gt;Before diving into fixes, it helps to understand what happens when your CF7 form is submitted:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;CF7 captures&lt;/strong&gt; the form submission.&lt;/li&gt;
&lt;li&gt; A &lt;strong&gt;connector plugin&lt;/strong&gt; intercepts the data.&lt;/li&gt;
&lt;li&gt; The plugin sends a &lt;strong&gt;POST request&lt;/strong&gt; to Zendesk's &lt;code&gt;/api/v2/tickets&lt;/code&gt; endpoint.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Zendesk processes&lt;/strong&gt; the request and creates a ticket—or returns an error.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Most failures occur at steps 3 and 4. The plugin's &lt;strong&gt;API Logs&lt;/strong&gt; page is your primary debugging tool; it shows the exact request sent and the response received. If you're seeing empty logs, refer to our guide on &lt;a href="https://www.contactformtoapi.com/contact-form-7-data-not-reaching-api/" rel="noopener noreferrer"&gt;Contact Form 7 data not reaching the API&lt;/a&gt; for deeper troubleshooting.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Failure Point 1: 401 Unauthorized (Authentication)
&lt;/h2&gt;

&lt;p&gt;The single most frequent cause of failure is incorrect Zendesk authentication configuration.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Symptom:&lt;/strong&gt; Your API logs show a &lt;code&gt;401 Unauthorized&lt;/code&gt; response.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Cause:&lt;/strong&gt; Zendesk does not use Bearer tokens for standard API token authentication. It uses &lt;strong&gt;Basic Auth&lt;/strong&gt; with a specific username format that is easy to get wrong.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Fix (Three Critical Steps):&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Auth Type:&lt;/strong&gt; In the plugin, set Authorization type to &lt;strong&gt;Basic Auth&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Username Format:&lt;/strong&gt; Enter your Zendesk admin email with &lt;code&gt;/token&lt;/code&gt; appended. For example: &lt;code&gt;admin@yourcompany.com/token&lt;/code&gt;. The &lt;code&gt;/token&lt;/code&gt; suffix is &lt;strong&gt;mandatory&lt;/strong&gt; and is the most commonly forgotten step.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Password:&lt;/strong&gt; Paste the API Token you generated in Zendesk Admin Center (Apps and integrations &amp;gt; APIs &amp;gt; Zendesk API).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Verification:&lt;/strong&gt; After fixing this, submit a test form. You should now receive a different error code (likely 422) if other issues exist, which means authentication has been successfully resolved.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Failure Point 2: 422 Unprocessable Entity (Payload Structure)
&lt;/h2&gt;

&lt;p&gt;Once authentication works, the next barrier is the JSON payload. Zendesk's Ticket API is strict about its schema.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Symptom:&lt;/strong&gt; You receive a &lt;code&gt;422 Unprocessable Entity&lt;/code&gt; response. The error message often references missing required fields like &lt;code&gt;comment&lt;/code&gt; or &lt;code&gt;requester&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Cause:&lt;/strong&gt; You are sending a flat JSON object with CF7 field names. Zendesk requires a specific nested structure within a root &lt;code&gt;ticket&lt;/code&gt; object.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Fix:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Your request body must follow this structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"ticket"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"subject"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"[CF7 Field: your-subject]"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"comment"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"body"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"[CF7 Field: your-message]"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"requester"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"[CF7 Field: your-name]"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"[CF7 Field: your-email]"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key requirements:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;root key&lt;/strong&gt; must be &lt;code&gt;ticket&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;&lt;code&gt;comment.body&lt;/code&gt;&lt;/strong&gt; field is &lt;strong&gt;required&lt;/strong&gt; and cannot be empty.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;&lt;code&gt;requester.email&lt;/code&gt;&lt;/strong&gt; field is required to associate the ticket with a user.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Debugging Tip:&lt;/strong&gt; Start with a minimal test payload using hardcoded values (e.g., &lt;code&gt;"subject": "Test Ticket"&lt;/code&gt;). Once that succeeds, replace hardcoded values with your CF7 field placeholders one by one. For a deeper dive into JSON structure mapping, read our guide on &lt;a href="https://www.contactformtoapi.com/contact-form-7-json-mapping/" rel="noopener noreferrer"&gt;Contact Form 7 JSON mapping&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Failure Point 3: Empty Required Fields
&lt;/h2&gt;

&lt;p&gt;A subtle variant of the 422 error occurs when a CF7 form field that maps to a required Zendesk field is left empty by the user.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Symptom:&lt;/strong&gt; Tickets fail intermittently, often when users skip the "message" field.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Cause:&lt;/strong&gt; Zendesk's &lt;code&gt;comment.body&lt;/code&gt; is required. If your CF7 form allows that field to be empty, the API call will fail.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Fix (Two Options):&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Make the field required in CF7:&lt;/strong&gt; Enable the "Required" option on the relevant form field.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Set a default value:&lt;/strong&gt; If you don't want to force users to fill it out, use a small custom hook to inject a fallback value before the form is submitted.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Example snippet (add to your theme's &lt;code&gt;functions.php&lt;/code&gt; or a custom plugin):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nf"&gt;add_action&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'wpcf7_before_send_mail'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'set_default_zendesk_description'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;set_default_zendesk_description&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$contact_form&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$submission&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;WPCF7_Submission&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;get_instance&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$submission&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$submission&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get_posted_data&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'your-message'&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;$data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'your-message'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'No detailed description provided.'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="nv"&gt;$submission&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;set_posted_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Common Failure Point 4: API Timeout
&lt;/h2&gt;

&lt;p&gt;If your Zendesk instance is slow to respond or your server has strict timeout limits, the request may fail before completing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Symptom:&lt;/strong&gt; Logs show a timeout error or the request never completes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Cause:&lt;/strong&gt; Server-side timeout limits or Zendesk API rate limiting.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Fix:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Increase PHP &lt;code&gt;max_execution_time&lt;/code&gt; on your WordPress server.&lt;/li&gt;
&lt;li&gt;Check Zendesk's API rate limits (typically 400 requests per minute for most plans).&lt;/li&gt;
&lt;li&gt;Consider implementing a retry mechanism using the plugin's conditional logic features.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a full breakdown of timeout issues, refer to our article on &lt;a href="https://www.contactformtoapi.com/contact-form-7-api-timeout/" rel="noopener noreferrer"&gt;Contact Form 7 API timeout&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recommended Debugging Workflow
&lt;/h2&gt;

&lt;p&gt;Follow this sequence to isolate the problem efficiently:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Step&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;th&gt;What to Look For&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Check the plugin's &lt;strong&gt;API Logs&lt;/strong&gt; page&lt;/td&gt;
&lt;td&gt;Is there a log entry? If empty, the request was never sent—check CF7 configuration.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Inspect the &lt;strong&gt;Response Code&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;401 = Auth issue. 422 = Payload issue. 500 = Zendesk server issue.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Enable &lt;strong&gt;Debug Mode&lt;/strong&gt; in plugin settings&lt;/td&gt;
&lt;td&gt;See the exact JSON payload sent and the full response body.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Test with &lt;strong&gt;minimal payload&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;Hardcode values to isolate whether the issue is structure or field mapping.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Verify &lt;strong&gt;field mapping&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;Ensure CF7 field names match exactly what you've entered in the plugin.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Extending the Integration: Multiple APIs and CRM Sync
&lt;/h2&gt;

&lt;p&gt;Once Zendesk ticket creation works, you may want to send the same form submission to additional destinations—for example, a CRM like HubSpot or Salesforce, or a marketing tool like Mailchimp.&lt;/p&gt;

&lt;p&gt;A capable connector plugin supports multiple API integrations from a single form submission. This means you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a Zendesk ticket.&lt;/li&gt;
&lt;li&gt;Add the contact to HubSpot.&lt;/li&gt;
&lt;li&gt;Subscribe them to Mailchimp.&lt;/li&gt;
&lt;li&gt;Log the lead in Salesforce.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All from a single CF7 submission, without additional plugins or Zapier subscriptions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Basic Auth with &lt;code&gt;/token&lt;/code&gt; suffix&lt;/strong&gt; is non-negotiable for Zendesk API token authentication.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The root JSON key must be &lt;code&gt;ticket&lt;/code&gt;&lt;/strong&gt;, with &lt;code&gt;comment.body&lt;/code&gt; and &lt;code&gt;requester.email&lt;/code&gt; as required nested fields.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The plugin's logging feature&lt;/strong&gt; is your most valuable debugging asset—use it to see the raw request and response.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Start simple, then expand.&lt;/strong&gt; A working hardcoded request proves connectivity; add field mappings incrementally.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No Zapier required.&lt;/strong&gt; A dedicated connector plugin handles the integration natively, reducing cost and complexity.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once these configuration layers are correct, your CF7 to Zendesk integration will reliably create tickets without the overhead of a dedicated connector or third-party automation service.&lt;/p&gt;

</description>
      <category>wordpress</category>
      <category>contactform7</category>
      <category>zendesk</category>
      <category>api</category>
    </item>
    <item>
      <title>Why Your Contact Form Submissions Are Ruining Your CRM Data (And How to Fix Field Mapping)</title>
      <dc:creator>Rahul Sharma</dc:creator>
      <pubDate>Wed, 23 Sep 2026 11:16:05 +0000</pubDate>
      <link>https://dev.to/rahul_sharma_15bd129bc69e/why-your-contact-form-submissions-are-ruining-your-crm-data-and-how-to-fix-field-mapping-3n3o</link>
      <guid>https://dev.to/rahul_sharma_15bd129bc69e/why-your-contact-form-submissions-are-ruining-your-crm-data-and-how-to-fix-field-mapping-3n3o</guid>
      <description>&lt;p&gt;A Contact Form 7 integration can return a successful API response, create a CRM record, and still put the wrong data into the wrong fields.&lt;/p&gt;

&lt;p&gt;That is one of the more frustrating integration bugs because, technically, nothing appears to be broken.&lt;/p&gt;

&lt;p&gt;The form submits.&lt;/p&gt;

&lt;p&gt;The API responds.&lt;/p&gt;

&lt;p&gt;The CRM creates the record.&lt;/p&gt;

&lt;p&gt;Yet when someone opens that record, the data is wrong.&lt;/p&gt;

&lt;p&gt;The customer's company might appear as their job title. A phone number might end up in a custom text field. A dropdown value might be rejected or silently stored incorrectly.&lt;/p&gt;

&lt;p&gt;This is usually a &lt;strong&gt;field-mapping problem&lt;/strong&gt;, not a connection problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  The API Request Can Succeed While the Data Is Still Wrong
&lt;/h2&gt;

&lt;p&gt;When debugging a Contact Form 7 integration, developers often start with the HTTP response.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;POST /api/contacts
200 OK
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At first glance, everything looks good.&lt;/p&gt;

&lt;p&gt;But HTTP 200 only tells you that the API accepted the request. It does not necessarily tell you that the values were mapped to the fields you intended.&lt;/p&gt;

&lt;p&gt;Consider a simple Contact Form 7 form:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[text* customer-name]
[email* customer-email]
[tel customer-phone]
[text company]
[select inquiry-type "Sales" "Support" "Partnership"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The submitted data might look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"customer-name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"John Smith"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"customer-email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"john@example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"customer-phone"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"+1 555 123 4567"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"company"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Example Inc"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"inquiry-type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Sales"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But the CRM API may expect something completely different:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"John Smith"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"john@example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"phone"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"+1 555 123 4567"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"organization"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Example Inc"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"lead_source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"website"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The form field names and API field names are not automatically the same thing.&lt;/p&gt;

&lt;p&gt;That translation layer is where field mapping becomes important.&lt;/p&gt;

&lt;h2&gt;
  
  
  Think of Field Mapping as a Translation Layer
&lt;/h2&gt;

&lt;p&gt;A useful way to debug these integrations is to think about three separate layers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Contact Form 7
      ↓
Submitted Form Data
      ↓
Field Mapping / Transformation
      ↓
API Payload
      ↓
CRM
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A problem at any point can produce bad CRM data.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Form field:
company

API field:
organization

CRM field:
Company Name
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The value may be identical, but the field identifiers are not.&lt;/p&gt;

&lt;p&gt;Your integration needs to explicitly translate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;company → organization
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without that mapping, the API may ignore the value, place it somewhere unexpected, or reject the request.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start by Comparing the Form With the API
&lt;/h2&gt;

&lt;p&gt;Before changing code or debugging authentication, create a simple mapping table.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Contact Form 7&lt;/th&gt;
&lt;th&gt;API Field&lt;/th&gt;
&lt;th&gt;CRM Field&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;customer-name&lt;/td&gt;
&lt;td&gt;name&lt;/td&gt;
&lt;td&gt;Name&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;customer-email&lt;/td&gt;
&lt;td&gt;email&lt;/td&gt;
&lt;td&gt;Email&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;customer-phone&lt;/td&gt;
&lt;td&gt;phone&lt;/td&gt;
&lt;td&gt;Phone&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;company&lt;/td&gt;
&lt;td&gt;organization&lt;/td&gt;
&lt;td&gt;Company&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;inquiry-type&lt;/td&gt;
&lt;td&gt;lead_source&lt;/td&gt;
&lt;td&gt;Lead Source&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This immediately exposes mismatches.&lt;/p&gt;

&lt;p&gt;It also prevents a common mistake: assuming that the CRM's field label is the same as the API property name.&lt;/p&gt;

&lt;p&gt;It often isn't.&lt;/p&gt;

&lt;p&gt;For example, the CRM interface might display:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Company Name
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;while the API expects:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;organization
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The UI label is designed for humans.&lt;/p&gt;

&lt;p&gt;The API field is designed for machines.&lt;/p&gt;

&lt;p&gt;Your integration needs to know the latter.&lt;/p&gt;

&lt;h2&gt;
  
  
  JSON Mapping Is Where Many Integrations Go Wrong
&lt;/h2&gt;

&lt;p&gt;For APIs that accept JSON, the payload should be treated as a contract.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"[customer-name]"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"[customer-email]"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"phone"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"[customer-phone]"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"organization"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"[company]"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important part isn't just sending JSON.&lt;/p&gt;

&lt;p&gt;It's sending the &lt;strong&gt;correct JSON structure&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A payload like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"customer-name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"John Smith"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"company"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Example Inc"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;may be perfectly valid JSON but completely useless to an API expecting:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"John Smith"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"organization"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Example Inc"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Valid JSON does not automatically mean valid API data.&lt;/p&gt;

&lt;p&gt;That's an important distinction when troubleshooting form integrations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Watch Out for Data Types
&lt;/h2&gt;

&lt;p&gt;Field mapping isn't only about field names.&lt;/p&gt;

&lt;p&gt;Data types matter too.&lt;/p&gt;

&lt;p&gt;A form might provide:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Interested: Yes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;while the API expects:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"interested"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or a form might send:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Sales
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;while the CRM expects a specific option identifier:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"lead_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;123&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The value may look correct to a human but still be invalid for the API.&lt;/p&gt;

&lt;p&gt;Common examples include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Text vs numeric IDs&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;"true"&lt;/code&gt; vs &lt;code&gt;true&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;"false"&lt;/code&gt; vs &lt;code&gt;false&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Date strings vs timestamps&lt;/li&gt;
&lt;li&gt;CRM option labels vs internal option IDs&lt;/li&gt;
&lt;li&gt;Single values vs arrays&lt;/li&gt;
&lt;li&gt;Empty strings vs &lt;code&gt;null&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These differences are easy to overlook because the form itself may work perfectly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dropdowns Deserve Extra Attention
&lt;/h2&gt;

&lt;p&gt;Dropdowns are another common source of mapping problems.&lt;/p&gt;

&lt;p&gt;Imagine your Contact Form 7 field contains:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[select* department "Sales" "Support" "Billing"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your CRM might not accept those exact strings.&lt;/p&gt;

&lt;p&gt;Instead, its API could require something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"department_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So the mapping isn't simply:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;department → department
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Sales → 42
Support → 43
Billing → 44
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is why developers should check the API documentation for accepted values instead of assuming that the visible form value is what the CRM expects.&lt;/p&gt;

&lt;h2&gt;
  
  
  Don't Debug the Wrong Layer
&lt;/h2&gt;

&lt;p&gt;One of the biggest time-wasters in API integrations is debugging the connection when the connection isn't actually the problem.&lt;/p&gt;

&lt;p&gt;A useful debugging sequence is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Did the form submit?
        ↓
2. Was the webhook/API request triggered?
        ↓
3. What payload was actually sent?
        ↓
4. Did the API accept the request?
        ↓
5. What fields did the API actually process?
        ↓
6. What values appeared in the CRM?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the API returns a successful response, don't immediately assume the integration is finished.&lt;/p&gt;

&lt;p&gt;Inspect the payload.&lt;/p&gt;

&lt;p&gt;Then inspect the resulting CRM record.&lt;/p&gt;

&lt;p&gt;The difference between those two is often where the bug becomes obvious.&lt;/p&gt;

&lt;h2&gt;
  
  
  Log the Payload During Debugging
&lt;/h2&gt;

&lt;p&gt;When troubleshooting a field-mapping issue, logging is extremely useful.&lt;/p&gt;

&lt;p&gt;For example, temporarily record:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"John Smith"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"john@example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"organization"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Example Inc"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"lead_source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"website"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then compare it with the CRM record.&lt;/p&gt;

&lt;p&gt;If the payload is already wrong, the problem is somewhere between the form and the API request.&lt;/p&gt;

&lt;p&gt;If the payload is correct but the CRM record is wrong, investigate the API's field definitions, transformations, or response behavior.&lt;/p&gt;

&lt;p&gt;This distinction can save a lot of unnecessary debugging.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep the Mapping Explicit
&lt;/h2&gt;

&lt;p&gt;A maintainable integration shouldn't rely on assumptions such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;form field name == API field name
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead, make the relationship explicit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CF7: customer-name
        ↓
API: name
        ↓
CRM: Name

CF7: company
        ↓
API: organization
        ↓
CRM: Company
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This makes the integration easier to understand and much easier to troubleshoot when the form changes later.&lt;/p&gt;

&lt;p&gt;It also helps when different CRM systems use different terminology.&lt;/p&gt;

&lt;h2&gt;
  
  
  What If You Have Multiple CRM Integrations?
&lt;/h2&gt;

&lt;p&gt;This becomes even more important when one Contact Form 7 form sends data to multiple systems.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Contact Form 7
      ↓
 ┌────┴─────┐
 ↓          ↓
CRM A     CRM B
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;CRM A might expect:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"organization"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Example Inc"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;while CRM B expects:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"company_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Example Inc"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The original form field can remain:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;company
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;but each API request needs its own mapping.&lt;/p&gt;

&lt;p&gt;This is one reason API-based form automation becomes useful for more complex WordPress setups. Instead of expecting every service to understand your form's field names, you control the payload sent to each destination.&lt;/p&gt;

&lt;p&gt;For more background, the &lt;a href="https://www.contactformtoapi.com/contact-form-7-json-mapping/" rel="noopener noreferrer"&gt;Contact Form 7 JSON mapping guide&lt;/a&gt; covers this part of the integration process in more detail.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Contact Form to API Fits
&lt;/h2&gt;

&lt;p&gt;This is also where a tool such as Contact Form to API can be useful.&lt;/p&gt;

&lt;p&gt;The important benefit isn't simply connecting Contact Form 7 to an API. The more important part is being able to control how the submitted form data is structured and mapped before it reaches the destination.&lt;/p&gt;

&lt;p&gt;That matters when your CRM uses different field names, custom fields, specific values, or a payload structure that doesn't directly match your Contact Form 7 form.&lt;/p&gt;

&lt;p&gt;For broader WordPress CRM integration considerations, see the &lt;a href="https://www.contactformtoapi.com/contact-form-7-crm-integration/" rel="noopener noreferrer"&gt;Contact Form 7 CRM integration guide&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Practical Field-Mapping Checklist
&lt;/h2&gt;

&lt;p&gt;Before calling a Contact Form 7 → CRM integration complete, verify:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Does every required form field have a destination?&lt;/li&gt;
&lt;li&gt;Are the API field names correct?&lt;/li&gt;
&lt;li&gt;Are CRM field IDs different from their visible labels?&lt;/li&gt;
&lt;li&gt;Are dropdown values accepted by the CRM?&lt;/li&gt;
&lt;li&gt;Are numbers being sent as numbers where required?&lt;/li&gt;
&lt;li&gt;Are booleans being sent as booleans?&lt;/li&gt;
&lt;li&gt;Are dates in the format expected by the API?&lt;/li&gt;
&lt;li&gt;Are empty fields handled correctly?&lt;/li&gt;
&lt;li&gt;Does the JSON structure match the API documentation?&lt;/li&gt;
&lt;li&gt;Does the actual CRM record match the submitted form?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And most importantly:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Don't stop debugging when you receive HTTP 200.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A successful HTTP response means the request was accepted. It doesn't prove that the business data ended up in the right place.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Real Goal Is Correct Data, Not Just Successful Requests
&lt;/h2&gt;

&lt;p&gt;A CRM integration has two different definitions of success.&lt;/p&gt;

&lt;p&gt;The first is technical:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Request sent → API accepted it
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second is operational:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Form submitted
      ↓
Correct payload created
      ↓
API accepted it
      ↓
Correct CRM fields populated
      ↓
Sales team can use the data
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second outcome is what actually matters.&lt;/p&gt;

&lt;p&gt;If your Contact Form 7 submissions are reaching the CRM but the records contain incorrect, missing, or misplaced values, the integration isn't necessarily broken at the connection level.&lt;/p&gt;

&lt;p&gt;The mapping may be.&lt;/p&gt;

&lt;p&gt;And once you start treating field mapping as a deliberate translation layer rather than an automatic process, these problems become much easier to diagnose.&lt;/p&gt;

</description>
      <category>wordpress</category>
      <category>contactform7</category>
      <category>api</category>
      <category>webdev</category>
    </item>
    <item>
      <title>CF7 to Freshdesk Tickets Not Being Created - Four Causes and Exact Fixes</title>
      <dc:creator>Rahul Sharma</dc:creator>
      <pubDate>Tue, 22 Sep 2026 08:08:23 +0000</pubDate>
      <link>https://dev.to/rahul_sharma_15bd129bc69e/cf7-to-freshdesk-tickets-not-being-created-four-causes-and-exact-fixes-2037</link>
      <guid>https://dev.to/rahul_sharma_15bd129bc69e/cf7-to-freshdesk-tickets-not-being-created-four-causes-and-exact-fixes-2037</guid>
      <description>&lt;p&gt;A developer documented a real CF7 to Freshdesk integration in a 2017 tutorial. The comments section became a support thread multiple people following the same code reported that "it just sends the email but no activity on Freshdesk." The author's debugging advice: use Postman to test the API directly, then print the PHP array to check the values.&lt;/p&gt;

&lt;p&gt;That debugging advice is still the right starting point. Here are the four causes that produce the same symptom form submits, email arrives, no Freshdesk ticket.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cause 1: Wrong Domain Format in the API URL
&lt;/h2&gt;

&lt;p&gt;Freshdesk API calls require your full subdomain in the URL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://YOUR_SUBDOMAIN.freshdesk.com/api/v2/tickets
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Where &lt;code&gt;YOUR_SUBDOMAIN&lt;/code&gt; is the part before &lt;code&gt;.freshdesk.com&lt;/code&gt; in your Freshdesk URL. If your Freshdesk account is at &lt;code&gt;acmehelp.freshdesk.com&lt;/code&gt;, the API endpoint is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://acmehelp.freshdesk.com/api/v2/tickets
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The most common mistake is entering just the subdomain (&lt;code&gt;acmehelp&lt;/code&gt;) without the full domain, or using &lt;code&gt;freshdesk.com&lt;/code&gt; without the subdomain prefix. Both produce a URL that either does not resolve or returns a generic Freshdesk error page rather than an API response.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Test your domain format:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="s2"&gt;"https://YOUR_SUBDOMAIN.freshdesk.com/api/v2/tickets"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-u&lt;/span&gt; &lt;span class="s2"&gt;"YOUR_API_KEY:X"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you see a JSON response (even a 401), the URL format is correct. If you see an HTML page or a connection error, the domain format is wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cause 2: API Key Authentication Format Is Not Standard
&lt;/h2&gt;

&lt;p&gt;Freshdesk uses HTTP Basic authentication but with a non-standard format. The username is your API key and the password is literally the letter &lt;code&gt;X&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Authorization: Basic base64(YOUR_API_KEY:X)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is different from most APIs. The API key goes in the username position. The password is always &lt;code&gt;X&lt;/code&gt; not your actual password, not empty, literally the single character &lt;code&gt;X&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Using &lt;code&gt;wp_remote_post&lt;/code&gt; in PHP:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="s1"&gt;'headers'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s1"&gt;'Authorization'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'Basic '&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;base64_encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;FRESHDESK_API_KEY&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;':X'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="s1"&gt;'Content-Type'&lt;/span&gt;  &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'application/json'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you enter your email and password in the Basic auth fields instead of API_KEY:X, authentication will fail with a 401 even if the credentials are otherwise correct.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Find your Freshdesk API key:&lt;/strong&gt; In Freshdesk, click your profile picture at the top right, then Profile Settings. The API Key appears at the bottom right of the page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cause 3: Required Fields Missing from the Ticket Payload
&lt;/h2&gt;

&lt;p&gt;Freshdesk requires at minimum two fields for every ticket:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;subject&lt;/code&gt; — the ticket title/subject line&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;email&lt;/code&gt; — the requester's email address&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without both, Freshdesk returns a 422 Unprocessable Entity with a validation error. If your plugin or custom code maps only the message body or only the name, the ticket creation fails.&lt;/p&gt;

&lt;p&gt;A minimal valid Freshdesk ticket payload:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"subject"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Enquiry from Jane Smith"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Message content here"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"jane@example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"priority"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Freshdesk status codes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;1&lt;/code&gt; = Open&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;2&lt;/code&gt; = Pending&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;3&lt;/code&gt; = Resolved&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;4&lt;/code&gt; = Closed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Freshdesk priority codes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;1&lt;/code&gt; = Low&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;2&lt;/code&gt; = Medium&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;3&lt;/code&gt; = High&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;4&lt;/code&gt; = Urgent&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For most CF7 contact form tickets, &lt;code&gt;status: 2&lt;/code&gt; (Pending) and &lt;code&gt;priority: 1&lt;/code&gt; (Low) are appropriate defaults.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cause 4: The Hook &lt;code&gt;wpcf7_mail_sent&lt;/code&gt; vs &lt;code&gt;wpcf7_before_send_mail&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;The original tutorial code used &lt;code&gt;wpcf7_mail_sent&lt;/code&gt; as the hook:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nf"&gt;add_action&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'wpcf7_mail_sent'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'cf7_create_freshdesk_ticket'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;wpcf7_mail_sent&lt;/code&gt; fires only after CF7 has successfully sent its notification email. If CF7's mail sending fails for any reason — SMTP configuration issues, email blocked by spam filter, missing mail configuration — this hook never fires and no Freshdesk ticket is created.&lt;/p&gt;

&lt;p&gt;The more reliable hook for API integrations is &lt;code&gt;wpcf7_before_send_mail&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nf"&gt;add_action&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'wpcf7_before_send_mail'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'cf7_create_freshdesk_ticket'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This fires during the submission processing regardless of whether the email is sent successfully. For use cases where the Freshdesk ticket should always be created when someone submits the form, not only when the email delivery succeeds, use &lt;code&gt;wpcf7_before_send_mail&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Complete CF7 to Freshdesk Implementation
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nf"&gt;add_action&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'wpcf7_before_send_mail'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'cf7_create_freshdesk_ticket'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;cf7_create_freshdesk_ticket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$contact_form&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;$contact_form&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="no"&gt;YOUR_FORM_ID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nv"&gt;$submission&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;WPCF7_Submission&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;get_instance&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nv"&gt;$submission&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nv"&gt;$data&lt;/span&gt;      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$submission&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get_posted_data&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nv"&gt;$name&lt;/span&gt;      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sanitize_text_field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'your-name'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;    &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$email&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sanitize_email&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'your-email'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;        &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$message&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sanitize_textarea_field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'your-message'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$email&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nv"&gt;$api_key&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;defined&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'FRESHDESK_API_KEY'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;    &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="no"&gt;FRESHDESK_API_KEY&lt;/span&gt;    &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nv"&gt;$subdomain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;defined&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'FRESHDESK_SUBDOMAIN'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="no"&gt;FRESHDESK_SUBDOMAIN&lt;/span&gt;  &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nv"&gt;$response&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;wp_remote_post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s2"&gt;"https://&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$subdomain&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.freshdesk.com/api/v2/tickets"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="s1"&gt;'headers'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                &lt;span class="s1"&gt;'Authorization'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'Basic '&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;base64_encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$api_key&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;':X'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="s1"&gt;'Content-Type'&lt;/span&gt;  &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'application/json'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="s1"&gt;'body'&lt;/span&gt;    &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;wp_json_encode&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
                &lt;span class="s1"&gt;'subject'&lt;/span&gt;     &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'Enquiry from '&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="s1"&gt;'description'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="s1"&gt;'email'&lt;/span&gt;       &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="s1"&gt;'status'&lt;/span&gt;      &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="s1"&gt;'priority'&lt;/span&gt;    &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;]),&lt;/span&gt;
            &lt;span class="s1"&gt;'timeout'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;is_wp_error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;error_log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'[CF7-&amp;gt;Freshdesk] Error: '&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get_error_message&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nv"&gt;$status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;wp_remote_retrieve_response_code&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nb"&gt;error_log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'[CF7-&amp;gt;Freshdesk] Response: '&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$status&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;' — '&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nf"&gt;wp_remote_retrieve_body&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Store credentials in &lt;code&gt;wp-config.php&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nb"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'FRESHDESK_API_KEY'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="s1"&gt;'your-api-key-here'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nb"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'FRESHDESK_SUBDOMAIN'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'yourcompany'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  No-Code Alternative
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.contactformtoapi.com/contact-form-7-third-party-integration-guide/" rel="noopener noreferrer"&gt;Contact Form to API&lt;/a&gt; handles the Freshdesk API call from the WordPress dashboard. Configure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Endpoint:&lt;/strong&gt; &lt;code&gt;https://yoursubdomain.freshdesk.com/api/v2/tickets&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Method:&lt;/strong&gt; POST&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Authorization:&lt;/strong&gt; &lt;code&gt;Basic&lt;/code&gt; + base64 of &lt;code&gt;YOUR_API_KEY:X&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Body:&lt;/strong&gt; JSON with &lt;code&gt;subject&lt;/code&gt;, &lt;code&gt;email&lt;/code&gt;, &lt;code&gt;description&lt;/code&gt;, &lt;code&gt;status&lt;/code&gt;, &lt;code&gt;priority&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The response is logged for every submission so you see the Freshdesk ticket ID or the exact validation error if something fails.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Diagnosis
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Error&lt;/th&gt;
&lt;th&gt;Cause&lt;/th&gt;
&lt;th&gt;Fix&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Connection error / HTML response&lt;/td&gt;
&lt;td&gt;Wrong domain format in URL&lt;/td&gt;
&lt;td&gt;Use &lt;code&gt;https://SUBDOMAIN.freshdesk.com/api/v2/tickets&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;401 Unauthorized&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Wrong auth format&lt;/td&gt;
&lt;td&gt;Use &lt;code&gt;API_KEY:X&lt;/code&gt; as Basic auth, not email:password&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;422 Unprocessable Entity&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Missing &lt;code&gt;subject&lt;/code&gt; or &lt;code&gt;email&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Include both required fields in payload&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;No ticket, no error&lt;/td&gt;
&lt;td&gt;Hook &lt;code&gt;wpcf7_mail_sent&lt;/code&gt; not firing&lt;/td&gt;
&lt;td&gt;Switch to &lt;code&gt;wpcf7_before_send_mail&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ticket created but no requester&lt;/td&gt;
&lt;td&gt;Email field not mapped&lt;/td&gt;
&lt;td&gt;Confirm &lt;code&gt;email&lt;/code&gt; key is in the payload&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

</description>
      <category>wordpress</category>
      <category>freshdesk</category>
      <category>api</category>
      <category>webdev</category>
    </item>
    <item>
      <title>CF7 to Intercom Not Creating Contacts - Four Causes Explained</title>
      <dc:creator>Rahul Sharma</dc:creator>
      <pubDate>Mon, 21 Sep 2026 07:43:03 +0000</pubDate>
      <link>https://dev.to/rahul_sharma_15bd129bc69e/cf7-to-intercom-not-creating-contacts-four-causes-explained-4doc</link>
      <guid>https://dev.to/rahul_sharma_15bd129bc69e/cf7-to-intercom-not-creating-contacts-four-causes-explained-4doc</guid>
      <description>&lt;p&gt;Intercom is one of the more technically demanding integrations to get right from CF7. The platform has gone through several API authentication changes, deprecated an entire object type (Leads), and has a permission scope system that causes silent failures even with valid tokens.&lt;/p&gt;

&lt;p&gt;Here are the four causes that produce the same symptom - form submits, nothing appears in Intercom.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cause 1: App ID + API Key Authentication Is No Longer Supported
&lt;/h2&gt;

&lt;p&gt;Intercom's older API accepted Basic authentication using an App ID and API Key combination:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Authorization: Basic base64(APP_ID:API_KEY)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A GitHub issue on the intercom-php library documented this exactly: a developer was getting 401 errors using &lt;code&gt;new IntercomClient(APP_ID, API_KEY)&lt;/code&gt; even with valid credentials. The fix was switching to the Personal Access Token approach:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Authorization: Bearer YOUR_ACCESS_TOKEN
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The App ID + API Key pattern has been deprecated. Modern Intercom API calls require a Personal Access Token or an OAuth App token, both sent as Bearer tokens. If your CF7 to Intercom plugin was built several years ago and uses Basic auth with an App ID and API Key, it will return 401 on every call regardless of whether the credentials are valid.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Generate an Access Token:&lt;/strong&gt; In Intercom, go to Settings, then Integrations, then Developer Hub. Create a new app or open an existing one. Under Authentication, generate an Access Token. Use this as the Bearer token in every API call.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cause 2: Token Does Not Have the Required Permission Scopes
&lt;/h2&gt;

&lt;p&gt;Intercom's Access Tokens have granular permission scopes. An Intercom community thread confirmed this directly: "If you try to use an access token that doesn't have the right permissions to query a specific API endpoint, a &lt;code&gt;token_unauthorized&lt;/code&gt; error will be returned."&lt;/p&gt;

&lt;p&gt;For creating contacts from a CF7 form, your token needs at minimum:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;contacts:write&lt;/code&gt; — to create and update contact records&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;contacts:read&lt;/code&gt; — to search for existing contacts before creating duplicates&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your token was created with read-only scopes or limited permissions, the API call authenticates successfully but returns &lt;code&gt;token_unauthorized&lt;/code&gt; when attempting to write a contact. This looks identical to an invalid token error from the WordPress side.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Check your token's scopes:&lt;/strong&gt; In the Intercom Developer Hub, open your app, go to Authentication, and review the permissions assigned to your access token. If &lt;code&gt;contacts:write&lt;/code&gt; is not included, edit the token permissions to add it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cause 3: Intercom Removed the Leads API — Contacts Only Now
&lt;/h2&gt;

&lt;p&gt;This is the cause that breaks older integrations without any obvious error.&lt;/p&gt;

&lt;p&gt;Intercom previously had two separate object types for people: &lt;strong&gt;Leads&lt;/strong&gt; (anonymous visitors) and &lt;strong&gt;Users&lt;/strong&gt; (identified contacts). Many early CF7 to Intercom integration plugins were built against the Leads API endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;POST https://api.intercom.io/leads
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Intercom merged Leads and Users into a single &lt;strong&gt;Contacts&lt;/strong&gt; object in 2018-2019 and deprecated the Leads endpoint. The current endpoint for all contact creation is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;POST https://api.intercom.io/contacts
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A plugin that is still calling the old &lt;code&gt;/leads&lt;/code&gt; endpoint will get a 404 or a deprecated endpoint error. The contact is never created. The plugin may log nothing useful because it does not know how to handle the deprecated endpoint response.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Check your plugin:&lt;/strong&gt; If your CF7 to Intercom plugin was last updated before 2020, it is almost certainly using the old Leads API. Update the plugin or switch to a direct integration using the current Contacts endpoint.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cause 4: Creating an Archived Contact Returns an Error
&lt;/h2&gt;

&lt;p&gt;An Intercom community thread documented a specific failure when a contact's email already exists in Intercom but the contact was archived: the create endpoint returns an error saying "An archived contact with this email address already exists" rather than creating a new contact or updating the existing one.&lt;/p&gt;

&lt;p&gt;This happens when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A contact previously submitted your form and was archived in Intercom&lt;/li&gt;
&lt;li&gt;The same person submits again&lt;/li&gt;
&lt;li&gt;The plugin tries to create a new contact&lt;/li&gt;
&lt;li&gt;Intercom returns an error because the archived contact blocks creation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The correct handling is to first search for the contact by email, unarchive if found as archived, then update rather than create. Most simple CF7 to Intercom integrations do not handle this edge case.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Workaround:&lt;/strong&gt; Use Intercom's upsert-style endpoint which handles this automatically, or search before creating.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Correct CF7 to Intercom Integration
&lt;/h2&gt;

&lt;p&gt;Intercom's current API for creating a contact:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;POST https://api.intercom.io/contacts
Authorization: Bearer YOUR_ACCESS_TOKEN
Intercom-Version: 2.11
Content-Type: application/json

{
  "role": "lead",
  "email": "jane@example.com",
  "name": "Jane Smith",
  "phone": "+11234567890",
  "custom_attributes": {
    "message": "Their enquiry message here"
  }
}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;role&lt;/code&gt; field accepts &lt;code&gt;"lead"&lt;/code&gt; (anonymous, no login) or &lt;code&gt;"user"&lt;/code&gt; (identified, has logged in to your product). For CF7 contact forms, &lt;code&gt;"lead"&lt;/code&gt; is almost always correct.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Intercom-Version&lt;/code&gt; header is required. Use the current version (&lt;code&gt;2.11&lt;/code&gt; at the time of writing) to ensure predictable API behaviour.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.contactformtoapi.com/contact-form-7-third-party-integration-guide/" rel="noopener noreferrer"&gt;Contact Form to API&lt;/a&gt; handles this call from the WordPress dashboard. You set the Intercom contacts endpoint, add your Bearer token, include the &lt;code&gt;Intercom-Version&lt;/code&gt; header, and map your CF7 fields to the contact payload. Every submission logs the Intercom response, so you see whether the contact was created or what error was returned.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Diagnosis
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Error&lt;/th&gt;
&lt;th&gt;Cause&lt;/th&gt;
&lt;th&gt;Fix&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;401 token_not_found&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Using App ID + API Key instead of Bearer token&lt;/td&gt;
&lt;td&gt;Generate Access Token, use as Bearer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;401 token_unauthorized&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Token missing &lt;code&gt;contacts:write&lt;/code&gt; scope&lt;/td&gt;
&lt;td&gt;Add write permission in Developer Hub&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;404&lt;/code&gt; on the endpoint&lt;/td&gt;
&lt;td&gt;Plugin calling deprecated &lt;code&gt;/leads&lt;/code&gt; endpoint&lt;/td&gt;
&lt;td&gt;Update plugin to use &lt;code&gt;/contacts&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;"archived contact exists"&lt;/code&gt; error&lt;/td&gt;
&lt;td&gt;Email matches an archived Intercom contact&lt;/td&gt;
&lt;td&gt;Search first, unarchive, then update&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;403&lt;/code&gt; from AWS WAF&lt;/td&gt;
&lt;td&gt;Server IP blocked by Intercom's WAF&lt;/td&gt;
&lt;td&gt;Contact Intercom support with request IDs&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

</description>
      <category>wordpress</category>
      <category>intercom</category>
      <category>crm</category>
      <category>webdev</category>
    </item>
    <item>
      <title>CF7 to ConvertKit (Kit) Not Tagging Subscribers - Four Causes Explained</title>
      <dc:creator>Rahul Sharma</dc:creator>
      <pubDate>Fri, 18 Sep 2026 09:37:26 +0000</pubDate>
      <link>https://dev.to/rahul_sharma_15bd129bc69e/cf7-to-convertkit-kit-not-tagging-subscribers-four-causes-explained-2gdc</link>
      <guid>https://dev.to/rahul_sharma_15bd129bc69e/cf7-to-convertkit-kit-not-tagging-subscribers-four-causes-explained-2gdc</guid>
      <description>&lt;p&gt;ConvertKit rebranded to Kit in 2024 and migrated their API from v3 to v4. They also changed from API Key + Secret authentication to OAuth 2.0. These changes, combined with the longstanding confusion between tag names and tag IDs, explain almost every CF7 to ConvertKit/Kit integration failure.&lt;/p&gt;

&lt;p&gt;This post covers each cause with the exact technical detail needed to fix it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cause 1: API Key vs Secret Key Confusion
&lt;/h2&gt;

&lt;p&gt;A WordPress forum user reported that their plugin showed the ConvertKit connection as validated but no forms were visible in the mapping screen. After back and forth, the resolution was simple: the client had given them the API key instead of the API secret.&lt;/p&gt;

&lt;p&gt;ConvertKit's legacy v3 API used two separate credentials:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;API Key:&lt;/strong&gt; Used for some read operations&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API Secret:&lt;/strong&gt; Required for subscriber creation and tagging&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most CF7 integration plugins that use ConvertKit's v3 API require the API Secret, not the API Key. These two values are shown in the same settings page in ConvertKit under Advanced &amp;gt; API but they look different and have different lengths. Entering the API Key where the Secret is expected causes the connection to validate (it is a valid credential format) but subscriber operations fail silently.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Check:&lt;/strong&gt; In ConvertKit (now Kit), go to Settings, then Advanced, then scroll to the API section. Confirm which credential your CF7 plugin is asking for and enter the matching one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cause 2: ConvertKit Rebranded to Kit — Old API Endpoints Are Changing
&lt;/h2&gt;

&lt;p&gt;In 2024, ConvertKit officially rebranded to Kit and began migrating their API from v3 to v4. The v4 API uses OAuth 2.0 instead of API Key/Secret. Plugins that were built against the v3 API need to be updated to work with v4.&lt;/p&gt;

&lt;p&gt;What this means for CF7 integrations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Plugins using the old &lt;code&gt;api.convertkit.com/v3/&lt;/code&gt; base URL may stop working as Kit deprecates v3 endpoints&lt;/li&gt;
&lt;li&gt;The new v4 API is at &lt;code&gt;api.kit.com/v4/&lt;/code&gt; with a completely different authentication flow&lt;/li&gt;
&lt;li&gt;The tag application and subscriber creation payloads have changed between v3 and v4&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your CF7 to ConvertKit plugin was last updated before 2024, it may be running against deprecated v3 endpoints with an authentication pattern that is being phased out.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Check your plugin's last updated date.&lt;/strong&gt; If it has not been updated since 2023, check the plugin changelog or support forum for v4/Kit migration notes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cause 3: Tag Name vs Tag ID Confusion
&lt;/h2&gt;

&lt;p&gt;This is the most common cause of tags not being applied even when the subscriber is added correctly.&lt;/p&gt;

&lt;p&gt;ConvertKit's v3 API applies tags using the tag's numeric ID, not its name. The tag named "Website Enquiry" has an ID like &lt;code&gt;4567890&lt;/code&gt;. If your integration is sending the tag name instead of the tag ID, ConvertKit accepts the subscriber but ignores the tag.&lt;/p&gt;

&lt;p&gt;This is a confusing failure because some plugin UIs show tag names in a dropdown (they look up the IDs behind the scenes) while others require you to manually enter the tag ID. If your plugin asks for a "tag" and shows you a text field rather than a populated dropdown, it probably wants the numeric ID.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Find your tag IDs:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# ConvertKit v3&lt;/span&gt;
curl &lt;span class="s2"&gt;"https://api.convertkit.com/v3/tags?api_secret=YOUR_API_SECRET"&lt;/span&gt;

&lt;span class="c"&gt;# Kit v4&lt;/span&gt;
curl &lt;span class="s2"&gt;"https://api.kit.com/v4/tags"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer YOUR_ACCESS_TOKEN"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each tag object in the response has an &lt;code&gt;id&lt;/code&gt; field. That number is what goes in your tag configuration.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Apply a tag to a subscriber (v3):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;POST https://api.convertkit.com/v3/tags/{TAG_ID}/subscribe
api_secret: YOUR_SECRET

{
  "api_secret": "YOUR_SECRET",
  "email": "subscriber@example.com"
}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Tag a subscriber (v4):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;POST https://api.kit.com/v4/subscribers/{subscriber_id}/tags
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json

{
  "tag_ids": [TAG_ID_1, TAG_ID_2]
}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: in v4, tagging requires the subscriber's ID, which means you must first create the subscriber and capture their ID from the response before you can apply tags. This is a two-step flow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cause 4: ConvertKit Forms vs Tags — Different Subscription Mechanisms
&lt;/h2&gt;

&lt;p&gt;ConvertKit has two ways to subscribe someone: through a Form or through a Tag. These behave differently.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Subscribing via a Form:&lt;/strong&gt; Uses the form's specific subscribe endpoint. Triggers the form's opt-in confirmation email if double opt-in is enabled. Places the subscriber in the form's subscriber list.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Subscribing with a Tag:&lt;/strong&gt; Adds a tag to an existing or new subscriber. Does not send an opt-in confirmation unless you have an automation set up to trigger one.&lt;/p&gt;

&lt;p&gt;Many CF7 to ConvertKit integrations only support Form-based subscription. If you configure one of these integrations expecting tags to be applied, you will find subscribers are added to the form's list but no tags appear.&lt;/p&gt;

&lt;p&gt;If you need tags applied at subscription time, you need a plugin or direct API implementation that specifically supports the tag subscription endpoint, not just the form subscription endpoint.&lt;/p&gt;

&lt;h2&gt;
  
  
  Direct API Integration With Contact Form to API
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.contactformtoapi.com/contact-form-7-email-automation/" rel="noopener noreferrer"&gt;&lt;strong&gt;Contact Form to API&lt;/strong&gt;&lt;/a&gt; gives you direct control over which ConvertKit/Kit endpoint receives your data and what the payload looks like.&lt;/p&gt;

&lt;p&gt;For a two-step ConvertKit v3 flow (create subscriber then apply tag):&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1 — Subscribe:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;POST https://api.convertkit.com/v3/forms/{FORM_ID}/subscribe
Content-Type: application/json

{
  "api_key": "YOUR_API_KEY",
  "email": "[your-email]",
  "first_name": "[your-name]"
}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 2 — Apply tag&lt;/strong&gt; (use the subscriber_id from Step 1 response):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;POST https://api.convertkit.com/v3/tags/{TAG_ID}/subscribe
Content-Type: application/json

{
  "api_secret": "YOUR_SECRET",
  "email": "[your-email]"
}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Pro version's chained API call feature passes the subscriber ID from Step 1's response into Step 2's payload automatically.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Diagnosis
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symptom&lt;/th&gt;
&lt;th&gt;Most Likely Cause&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Connection validated but no forms in dropdown&lt;/td&gt;
&lt;td&gt;API Key used instead of API Secret&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Subscribers added but no tags applied&lt;/td&gt;
&lt;td&gt;Tag name sent instead of Tag ID&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Integration stopped working after Kit rebrand&lt;/td&gt;
&lt;td&gt;Plugin using deprecated v3 endpoints&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Double opt-in confirmation sent when using tag subscription&lt;/td&gt;
&lt;td&gt;Wrong endpoint — using form subscribe instead of tag subscribe&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tags applied but automations not triggering&lt;/td&gt;
&lt;td&gt;Tag ID correct but automation trigger not set up in Kit&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

</description>
      <category>wordpress</category>
      <category>convertkit</category>
      <category>emailmarketing</category>
      <category>webdev</category>
    </item>
    <item>
      <title>CF7 to MailerLite Not Adding Subscribers to the Right Group - Four Causes</title>
      <dc:creator>Rahul Sharma</dc:creator>
      <pubDate>Thu, 17 Sep 2026 10:12:04 +0000</pubDate>
      <link>https://dev.to/rahul_sharma_15bd129bc69e/cf7-to-mailerlite-not-adding-subscribers-to-the-right-group-four-causes-5c5n</link>
      <guid>https://dev.to/rahul_sharma_15bd129bc69e/cf7-to-mailerlite-not-adding-subscribers-to-the-right-group-four-causes-5c5n</guid>
      <description>&lt;p&gt;Multiple WordPress support threads document the same frustrating pattern with CF7 to MailerLite integrations. Subscribers either do not appear at all, or they land in the general subscribers list instead of the specific group selected in the plugin settings. No error is shown on the form. The submission appears to succeed.&lt;/p&gt;

&lt;p&gt;Four distinct causes produce this identical symptom. Here is each one with exactly what to check.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cause 1: Double Opt-In Is Enabled on the Group
&lt;/h2&gt;

&lt;p&gt;This was the resolution in two separate forum threads. One was closed with just this note: "The issue was solved through email. Double opt-in option was on."&lt;/p&gt;

&lt;p&gt;When double opt-in is enabled on a MailerLite group, subscribers added via API are placed in a pending state until they confirm their email. They do not appear in the group as active subscribers. From the WordPress side, the integration looks like it did nothing — the person is not in the group.&lt;/p&gt;

&lt;p&gt;The person was added. They are pending. They just do not appear as active subscribers until they click the confirmation email.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Check this first:&lt;/strong&gt; In your MailerLite account, go to Subscribers, then Groups. Open the group your CF7 integration is adding to. Click Settings. Look for the double opt-in setting. If it is enabled and you want subscribers added immediately without a confirmation step, disable it.&lt;/p&gt;

&lt;p&gt;Alternatively, if you need double opt-in for GDPR compliance, understand that this is working correctly — the subscriber will appear in the group after they confirm. Set up MailerLite to send the confirmation email correctly and check the Unconfirmed tab in the group to see pending subscribers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cause 2: Classic API Key vs New API Key
&lt;/h2&gt;

&lt;p&gt;MailerLite migrated their API in 2022-2023 from a "Classic" version to a "New" version. These are not interchangeable. Classic API keys (generated in the old MailerLite dashboard) do not work with New API endpoints, and vice versa.&lt;/p&gt;

&lt;p&gt;A forum user reported that data was getting through to MailerLite but the subscriber was not being added to the group. The plugin was using the MailerLite Classic API SDK while their MailerLite account was on the New platform.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to tell which you have:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If your MailerLite account URL is &lt;code&gt;app.mailerlite.com&lt;/code&gt; — you are on the New platform. You need a New API key.&lt;/li&gt;
&lt;li&gt;If your account URL is &lt;code&gt;app.mailerlite.com/classic&lt;/code&gt; or you signed up before 2022 and have not migrated — you may still be on Classic.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Generate the correct API key:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;New MailerLite: go to Integrations, then API, then create a token&lt;/li&gt;
&lt;li&gt;Classic MailerLite: go to Integrations, then Developer API&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the plugin you are using was last updated before 2023, it is likely using the Classic API SDK and will not work correctly with a New API key.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cause 3: CleanTalk or Spam Plugin Conflicting With the Submission Hook
&lt;/h2&gt;

&lt;p&gt;One forum thread documented a specific CleanTalk interaction. The site owner was using Contact Form 7 Connector for MailerLite sign-ups. With CleanTalk enabled, every submission returned "There was an error trying to send your message" and no subscriber was added. Disabling CleanTalk fixed it immediately.&lt;/p&gt;

&lt;p&gt;The CleanTalk dashboard showed all events as "approved" — no spam detected. But something in CleanTalk's processing was interfering with the CF7 hook execution before the MailerLite integration could fire.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you are using CleanTalk:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Temporarily disable CleanTalk and test the form&lt;/li&gt;
&lt;li&gt;If subscribers are added correctly without CleanTalk, the conflict is confirmed&lt;/li&gt;
&lt;li&gt;In CleanTalk settings, look for a "Forms to Protect" whitelist and add your CF7 form&lt;/li&gt;
&lt;li&gt;Also check "Protect Logged-in Users" — disable it if you are testing while logged in&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The same conflict can occur with other aggressive spam protection plugins (Cerber Security, WP Cerber) that intercept form submissions before CF7's hooks complete.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cause 4: Plugin Not Updated for MailerLite's API Migration
&lt;/h2&gt;

&lt;p&gt;A forum user trying the CF7 Connector MailerLite add-on reported subscribers were not being added to the correct group. A community member confirmed: "Looks like the plugin wasn't updated to be compatible with the latest version of MailerLite." The user switched to AFI (Advanced Form Integration) and it worked immediately with the same API key and group settings.&lt;/p&gt;

&lt;p&gt;This is the structural problem with dedicated integration plugins that depend on a specific email platform's API: when the platform migrates their API, the plugin must be updated to match. If the plugin author is slow to update or has abandoned the plugin, users are left with an integration that authenticates successfully but fails silently on group assignment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Check:&lt;/strong&gt; Look at the plugin's last updated date in WordPress admin and compare it to MailerLite's API migration announcement (2022-2023). If the plugin predates the migration and has not been updated since, it is running against a deprecated API.&lt;/p&gt;

&lt;h2&gt;
  
  
  Calling MailerLite's New API Directly
&lt;/h2&gt;

&lt;p&gt;The MailerLite New API endpoint for adding a subscriber to a group:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;POST https://connect.mailerlite.com/api/subscribers
Authorization: Bearer YOUR_NEW_API_TOKEN
Content-Type: application/json
Accept: application/json

{
  "email": "jane@example.com",
  "fields": {
    "name": "Jane Smith",
    "last_name": ""
  },
  "groups": ["GROUP_ID_HERE"],
  "status": "active"
}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Get your group IDs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="s2"&gt;"https://connect.mailerlite.com/api/groups"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer YOUR_TOKEN"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Accept: application/json"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;id&lt;/code&gt; field in each group object is what goes in the &lt;code&gt;groups&lt;/code&gt; array.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.contactformtoapi.com/contact-form-7-email-automation/" rel="noopener noreferrer"&gt;Contact Form to API&lt;/a&gt; calls this endpoint directly from the WordPress dashboard. You configure the MailerLite New API endpoint, add your token as a Bearer header, and map your CF7 fields to the subscriber payload. The group ID goes directly in the &lt;code&gt;groups&lt;/code&gt; array in your JSON body — no plugin middleware that might be running against the old Classic API.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Diagnosis
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symptom&lt;/th&gt;
&lt;th&gt;Most Likely Cause&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Subscriber appears in Unconfirmed tab&lt;/td&gt;
&lt;td&gt;Double opt-in enabled on the group&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Subscriber in all subscribers but not in group&lt;/td&gt;
&lt;td&gt;Double opt-in enabled OR group ID wrong&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;No subscriber created, no error&lt;/td&gt;
&lt;td&gt;CleanTalk or spam plugin conflict&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Subscriber not added, error in debug log&lt;/td&gt;
&lt;td&gt;Classic API key with New platform (or vice versa)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Was working, stopped after MailerLite update&lt;/td&gt;
&lt;td&gt;Plugin not updated for API migration&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

</description>
      <category>wordpress</category>
      <category>mailerlite</category>
      <category>emailmarketing</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Stop Paying Zapier to Connect Your CF7 Form to a CRM</title>
      <dc:creator>Rahul Sharma</dc:creator>
      <pubDate>Wed, 16 Sep 2026 09:53:54 +0000</pubDate>
      <link>https://dev.to/rahul_sharma_15bd129bc69e/stop-paying-zapier-to-connect-your-cf7-form-to-a-crm-10a9</link>
      <guid>https://dev.to/rahul_sharma_15bd129bc69e/stop-paying-zapier-to-connect-your-cf7-form-to-a-crm-10a9</guid>
      <description>&lt;p&gt;Zapier is the default answer when someone asks how to connect Contact Form 7 to a CRM. It shows up in every search result. It is easy to set up. It works.&lt;/p&gt;

&lt;p&gt;It is also significantly more expensive than the alternative and for a simple CF7-to-CRM connection, the alternative does exactly the same job without the per-task pricing.&lt;/p&gt;

&lt;p&gt;This post breaks down the cost comparison, explains where Zapier adds genuine value versus where it is overkill, and shows you how to replace it with a direct API integration for the common CF7 use case.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Zapier Cost Model for CF7 Integrations
&lt;/h2&gt;

&lt;p&gt;Zapier charges per task. One task = one action in one Zap triggered once. If your CF7 form submission triggers two actions (create a CRM contact and add to a Mailchimp list), that is two tasks per submission.&lt;/p&gt;

&lt;p&gt;At 500 form submissions per month going to two destinations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;500 submissions × 2 actions = 1,000 tasks/month
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Zapier's Starter plan: $19.99/month for 750 tasks. You are already over the limit.&lt;br&gt;
Zapier's Professional plan: $49.99/month for 2,000 tasks.&lt;/p&gt;

&lt;p&gt;At 1,000 submissions/month to two destinations (2,000 tasks):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Professional plan: $49.99/month = $599.88/year
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a setup that could be replaced by a one-time plugin licence.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the Direct Alternative Costs
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.contactformtoapi.com/zapier-vs-contact-form-to-api-plugin-cost-comparison/" rel="noopener noreferrer"&gt;Contact Form to API&lt;/a&gt; handles CF7-to-API connections directly from WordPress. The free plan covers up to 5 API connections per form. The Pro licence is a one-time payment.&lt;/p&gt;

&lt;p&gt;At 1,000 submissions/month to two destinations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Contact Form to API: one-time licence cost
Zapier Professional: $49.99/month recurring
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The plugin pays for itself in the first month or two.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Zapier Is Worth Paying For
&lt;/h2&gt;

&lt;p&gt;Before replacing Zapier entirely, be honest about what you are using it for. Zapier earns its cost in specific situations:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Complex conditional routing:&lt;/strong&gt; If different form responses should go to different CRMs or different pipeline stages based on what the user selected, Zapier's visual workflow builder handles branching logic well. A direct plugin handles fixed destinations - all submissions go to the same endpoints. Conditional routing based on field values requires the Pro version's conditional logic features or a workflow platform.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Non-API destinations:&lt;/strong&gt; Zapier connects to 5,000+ apps, many of which do not expose a REST API. If you need CF7 submissions to update a Google Calendar event, create a Notion page through Notion's proprietary sync, or trigger a specific action in a tool without a proper REST API, Zapier is the correct tool.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Multi-app workflows with delays:&lt;/strong&gt; If your workflow needs to wait 24 hours then send a follow-up email, check a condition, then update a CRM field - Zapier's scheduler handles time-based workflow logic. A direct plugin does not.&lt;/p&gt;

&lt;p&gt;For everything else a form that sends data to a CRM and optionally an email list a direct plugin removes the per-task cost entirely.&lt;/p&gt;

&lt;h2&gt;
  
  
  The GDPR Consideration
&lt;/h2&gt;

&lt;p&gt;When a CF7 submission passes through Zapier, the data (name, email, enquiry content) is processed on Zapier's servers before reaching your CRM. For sites serving EU users under GDPR:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Zapier must be listed as a data processor in your privacy notice&lt;/li&gt;
&lt;li&gt;A Data Processing Agreement (DPA) must be in place with Zapier&lt;/li&gt;
&lt;li&gt;Zapier's data handling practices become part of your compliance posture&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A self-hosted WordPress plugin processes submissions entirely within your server. No third-party server receives the data in transit. For legal firms, healthcare providers, or any operator with privacy-conscious clients, this is a structural advantage that the monthly cost comparison does not capture.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Three-Point Failure Model vs One-Point
&lt;/h2&gt;

&lt;p&gt;A Zapier-based CF7 integration has three potential failure points:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;CF7 webhook delivery from WordPress to Zapier&lt;/li&gt;
&lt;li&gt;Zapier's internal processing and task execution&lt;/li&gt;
&lt;li&gt;Zapier's delivery to the destination API&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If any of the three fails, the lead is lost. Zapier's task history log will show the failure — but only if you are watching it.&lt;/p&gt;

&lt;p&gt;A direct plugin integration has one potential failure point: the WordPress server's outbound HTTP call to the destination API. If it fails, it fails at one place, with one log entry, on your own server.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Setup: CF7 to HubSpot Directly
&lt;/h2&gt;

&lt;p&gt;Here is what the direct integration looks like for the most common use case — CF7 to HubSpot — using Contact Form to API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Endpoint:   https://api.hubapi.com/crm/v3/objects/contacts
Method:     POST
Headers:    Authorization: Bearer YOUR_PRIVATE_APP_TOKEN
            Content-Type: application/json

Body:
{
  "properties": {
    "email":       "[your-email]",
    "firstname":   "[your-name]",
    "phone":       "[your-phone]",
    "hs_lead_status": "NEW",
    "lifecyclestage": "lead"
  }
}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;CF7 field names in brackets are replaced with submitted values before the request fires. No Zapier account. No webhook. No task counter. Just a direct POST from your WordPress server to HubSpot's API.&lt;/p&gt;

&lt;p&gt;Add a second connection for Mailchimp and both fire simultaneously on every submission. Still no Zapier.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to Keep Zapier
&lt;/h2&gt;

&lt;p&gt;Keep Zapier if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You need conditional routing based on form field values (send enterprise leads to one CRM, SMB leads to another)&lt;/li&gt;
&lt;li&gt;You need to connect to tools that have no REST API&lt;/li&gt;
&lt;li&gt;You need time-delayed workflows (follow up 3 days after submission)&lt;/li&gt;
&lt;li&gt;You are already paying for Zapier for other non-CF7 automations and have spare tasks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Replace Zapier if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You are using it only to relay CF7 submissions to one or two API destinations&lt;/li&gt;
&lt;li&gt;The per-task cost is scaling with your form volume&lt;/li&gt;
&lt;li&gt;You want data to stay within your own WordPress server for GDPR reasons&lt;/li&gt;
&lt;li&gt;You want fewer external dependencies in your lead capture stack&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>wordpress</category>
      <category>api</category>
      <category>automation</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
