A developer posted on the WordPress forums with a very specific and frustrating bug. Their CF7 form connected to Campaign Monitor worked perfectly when the newsletter checkbox was ticked. The moment someone left it unticked, the integration threw a 400 error:
{
"Code": 400,
"Message": "Failed to deserialize your request.\r\nPlease check the documentation and try again.\r\nFields in error: subscriber"
}
The plugin team fixed it in their next update. But the underlying reason this happens is worth understanding because the same bug will hit any CF7-to-Campaign Monitor integration that maps a checkbox to the "Authorized to send" field.
Why an Unchecked Checkbox Breaks the API Call
The CF7 form had a newsletter opt-in checkbox:
[checkbox add-to-nl use_label_element "accept newsletter"]
This was mapped to Campaign Monitor's Authorized to send field, which controls whether Campaign Monitor can send marketing emails to the subscriber.
When the checkbox is ticked, CF7 sends the value "accept newsletter" for the add-to-nl field. The integration plugin translates this to true and Campaign Monitor accepts it.
When the checkbox is left unticked, CF7 sends nothing for add-to-nl. There is no value because the user did not select anything. The integration plugin then either sends null, an empty string, or skips the field entirely.
Campaign Monitor's Authorized to send field expects a boolean: true or false. It cannot accept null, empty string, or a missing value. When it receives anything other than a proper boolean, it cannot parse the request and returns the deserialization error.
This is not a CF7 bug and it is not a Campaign Monitor bug. It is a gap in how the integration plugin handled the empty checkbox case. A ticked checkbox means true. An unticked checkbox means false. The plugin needed to explicitly convert the empty value to false before sending it to Campaign Monitor.
The Fix: Always Send a Boolean, Never Send Empty
The correct behaviour for any integration mapping a CF7 checkbox to a Campaign Monitor boolean field is to evaluate the checkbox state and send true or false explicitly.
If you are writing a custom integration, here is how to handle it:
add_action('wpcf7_before_send_mail', 'cf7_to_campaign_monitor');
function cf7_to_campaign_monitor($contact_form) {
if ((int) $contact_form->id() !== YOUR_FORM_ID) return;
$submission = WPCF7_Submission::get_instance();
if (!$submission) return;
$data = $submission->get_posted_data();
// Checkbox returns an array of selected values when ticked,
// or an empty array when unticked
$newsletter_checked = !empty($data['add-to-nl']);
$api_key = defined('CM_API_KEY') ? CM_API_KEY : '';
$list_id = defined('CM_LIST_ID') ? CM_LIST_ID : '';
$response = wp_remote_post(
"https://api.createsend.com/api/v3.3/subscribers/{$list_id}.json",
[
'headers' => [
'Authorization' => 'Basic ' . base64_encode($api_key . ':x'),
'Content-Type' => 'application/json',
],
'body' => wp_json_encode([
'EmailAddress' => sanitize_email($data['your-email'] ?? ''),
'Name' => sanitize_text_field($data['your-name'] ?? ''),
'ConsentToTrack' => $newsletter_checked ? 'yes' : 'no',
'CustomFields' => [
[
'Key' => 'Activity',
'Value' => sanitize_text_field($data['activity'] ?? ''),
],
],
'Resubscribe' => true,
]),
'timeout' => 15,
]
);
if (is_wp_error($response)) {
error_log('[CF7->CM] Error: ' . $response->get_error_message());
}
}
The key line is:
'ConsentToTrack' => $newsletter_checked ? 'yes' : 'no',
Whether the checkbox is ticked or not, Campaign Monitor always receives a valid value. Empty is never sent.
Note that Campaign Monitor's field name for this is ConsentToTrack in the API, not Authorized to send which is the label shown in the Campaign Monitor UI.
The Same Problem Affects Any Boolean Field
The deserialization error on an unchecked checkbox is not specific to Authorized to send. It will happen on any Campaign Monitor field that expects a boolean or a specific set of allowed values when the integration sends an empty or null value instead.
Common situations where this occurs:
- A checkbox mapped to any Campaign Monitor custom field with a predefined set of options
- An acceptance field mapped to consent or tracking fields
- A dropdown that was left at the default empty option
In all these cases the fix is the same: evaluate the empty state explicitly and send the correct fallback value rather than sending nothing.
If You Are Using an Integration Plugin
If you are using Bit Integrations or any similar CF7-to-Campaign Monitor plugin and you are seeing this error, the first thing to do is update the plugin to the latest version. The Bit Integrations team confirmed they fixed this in an update released shortly after the forum thread.
If updating does not fix it, check your field mapping screen and look at how the checkbox field is mapped. Some plugins let you set a fallback value for when a checkbox is unchecked. Setting that fallback to false or no depending on what Campaign Monitor expects for that field will resolve the error.
If your plugin does not support fallback values for empty fields, that is a capability gap and switching to a more flexible integration tool is the right move. With Contact Form to API, you can set the Authorized to send field as a fixed value of no in the field mapping instead of mapping it to the CF7 checkbox directly. Campaign Monitor then always receives a valid boolean regardless of whether the visitor ticks the checkbox or not, which eliminates the deserialization error entirely.
Quick Summary
| Scenario | What is sent to Campaign Monitor | Result |
|---|---|---|
| Checkbox ticked |
true or "yes"
|
Success |
| Checkbox unticked, no fallback |
null or empty string |
400 deserialization error |
| Checkbox unticked, fallback set |
false or "no"
|
Success |
The fix is always in the fallback. Campaign Monitor needs a boolean. Empty is not a boolean. Always send one or the other.
Top comments (0)