Returning a 410 from an audience webhook will disable it
Prior to this change, 410 responses from audience webhooks were treated like any other error—we retried three times for the given change, and kept trying for other changes to the audience. Now a webhook that returns 410 will be disabled with no retries, and for all future changes to the audience. The Webhook entry on the Webhooks page in your Audience settings will indicate that it’s been disabled.
410 means a resource is gone and its absence is likely to be permanent. Properly interpreting this response means less load on our servers and the servers that are hosting the webhook. Additionally, this allows webhook implementers to disable calls to their webhook without needing to make an API call to explicitly do so.
createListMemberNote / create_list_member_note
updateListMemberNote / update_list_member_note
previewSegment / preview_segment
updateInterestCategoryInterest / update_interest_category_interest
updateListMemberTags / update_list_member_tags
Fixing a PHP client library include and exclude fields bug
The Marketing API’s PHP client library was not handling the
exclude_fields query parameters correctly. We’ve fixed a bug in the client generation that will process the arrays as CSV strings. This change will affect version 3.0.35 of the PHP client library.
A user reported unexpected behavior when passing in an array of strings, and we discovered that the Swagger Codegen utility was not parsing the
collectionFormat for query parameters as expected.
Better error on invalid request to ecommerce/stores/.../orders
lines parameter is required on this endpoint, but previously we’d return a generic 404 error message. Now we’ll return a 400 error with information about why the request failed.
A user reported being confused about the error message; we should be more informative about validation errors.
Handling boolean query parameters
We now handle boolean query parameters in a more explicit way. For query parameters that are defined as a boolean type in our documentation, the case-insensitive strings
1 will be handled as a
true value, and the case-insensitive strings
0 will be handled as the
false value. Other values will be defaulted to
false, if provided.
We didn’t have a clear statement on what the accepted values for boolean query parameters were.
Addition of Customer Journey API trigger endpoint
We added an endpoint similar to the Add Subscriber to Workflow Email endpoint for the Customer Journey Builder. This is usable and dependent on the API 3.0 Starting Point/Wait.
This Classic Automation trigger and endpoint is valuable to our customers, but we can’t use the endpoint because it is located in the Automations section of the API. This new endpoint provides similar functionality, but it’s usable in the Customer Journey Builder, which provides new features and functionality not available in Classic Automations.
Transactional search infrastructure improvements
We upgraded the ElasticSearch cluster that backs our activity search feature, which will result in significant stability improvements.
We were running an old version of ElasticSearch on old hardware that was struggling to keep up with our load. By migrating to new hardware and bumping several major ElasticSearch versions, we will cut the number of failed search requests in half.
Mobile SDK for iOS adds Swift Package Support
We published a Mailchimp Mobile SDK Swift package for use in Xcode.
In Xcode 11 or newer, Swift Package Manager provides a native way to add package dependencies to Xcode. Compared to a third-party manager such as Cocoapods, Swift Package Manager is an even easier way to install the Mobile SDK. Making
MailchimpSDK available as a Swift package allows us to reduce duplicate code and promote maintainability.
Changes when using multiple authorization methods
We made a small change to authorization that will affect a handful of users.
The Marketing API supports authorization using an Authorization header, using either a Bearer Token or Basic Auth, but we also have legacy support for authorizing GET requests by including the API key in the query parameters. For cases where both an Authorization header and an API key query parameter were sent for a GET request, we defaulted to using the query parameter value.
We switched the default, so that if both methods are used, we use the value in the Authorization header. For the small number of requests that use both methods with conflicting values, we’ll return an HTTP 401 with the message:
The API key included in the query parameters is not consistent with the Authorization header. Please provide authorization using a single method.
If you’re affected by this change, we recommend removing the
?apikey= query parameter from your requests, and sending only an Authorization header following the example in our Quick Start guide.
The Authorization header is our preferred method for authorizing API requests. It simplifies our systems if we can assume that any time the Authorization header is present, it’s the authorization method we’ll be using.
Deprecating the Link Application endpoint
We removed the largely unused Link Application endpoint due to security concerns.
We previously supported a POST
/authorized-apps endpoint that let you post the client credentials for an app, and receive a new API token associated with that app.
This would register an app to the users’ account in a way that isn’t transparent to the user, so to improve security, we removed this feature.
The endpoint was accessed by only a handful of accounts over the last few months, so most API users will not be impacted.
Require PHP 7 in Marketing and Transactional SDKs
We updated the version of Guzzle used by the Marketing and Transactional PHP SDK to 7.2. This version of Guzzle requires PHP 7, so users of SDK versions after January 25, 2021, will need to use PHP 7.
We want to stay up to date on the libraries we use, even though that may mean dropping some legacy support. We came to this decision with lots of input from users on our Github projects; thank you for the contributions and feedback!
Updated Swagger and API reference to match endpoint requirements
The following verbs and endpoints:
Had a body parameter that wasn’t marked as required in our Swagger file, but was required for the API endpoint to work. These parameters are now marked as required.
This changed the method signature for the following methods in our SDKs:
The parameters were incorrectly labeled. This caused confusion with some of our sample code, and was also factually incorrect.
Improved HTTP status for unhandled methods
We adjusted several endpoints to return a
405 Method Not Allowed when processing unhandled methods instead of a
404 Not Found.
Our API endpoints were not consistent when responding to methods that aren’t supported by a given endpoint. By providing a
405 Method Not Allowed, with an additional
Allow header specifying the methods that are valid for the endpoint, it should be easier to discover and fix erroneous API calls.
Performance improvement for Email Activity Reports
We improved performance on the List Email Activity endpoint.
We realized we were fetching bounce activity from an inefficient source. With a more efficient method to fetch this information, this endpoint is now running an order of magnitude faster—the average request time has gone from 6 seconds to 200 milliseconds.
This change also makes this endpoint more consistent with bounce activity displayed in the web application. Previously, if an email server returned multiple bounces for a single recipient in a given campaign, this endpoint would include the latest one, whereas the web application would show the first one. As of this change, this endpoint will respond with the first bounce.
Fixed behavior for customers added via E-commerce endpoints
We fixed a mistake in how the e-commerce API handled customers who did not opt-in to receiving marketing emails (e.g., when adding an order via the API).
When we added a customer via some e-commerce API calls, we would first incorrectly add them as a “subscribed” contact (even though they had not opted in) and then immediately mark them as a “transactional” contact. The act of first marking them as “subscribed” caused us to incorrectly give these contacts an opt-in timestamp and also trigger them into any signup-related activities such as classic automations or customer journeys.
Incorrectly returning messages for all conversations
We fixed a bug in List Conversations Messages that resulted in returning messages for all conversations.
A bug was inadvertently introduced on November 24 that caused the List Conversations Messages endpoint to return messages for all conversations, instead of filtering to only messages for the provided conversation ID. The issue was fixed December 2.
Improved performance of List Member Activity
We improved performance on the List Member Activity endpoint.
We noticed the List Member Activity endpoint was running more queries than it needed to. We made some adjustments, and this endpoint is now processing 25% faster.
Fixing the query parameter documentation for List Templates
We fixed the query parameter documentation for List Templates.
The creation date filters on querying a list of templates were documented incorrectly, and we were missing some sorting options.
Improving the _links
In API responses, we return links to related endpoints. Some of the
schema fields pointed to outdated JSON Schema files. We changed these to reference the equivalent Swagger definition.
Transactional database infrastructure improvements
We upgraded the underlying hardware of our database service resulting in significant performance improvements.
We were observing performance and occasional stability issues relating to our older database hardware. By doubling processor, memory, and network card speeds as well as tripling disk I/O speeds with newer NVMe solid-state drives, our database service is processing tasks in comfort. In turn, our web application service is processing tasks faster as well.
Better handling of rss_opts for POST Campaigns
We fixed a bug in the POST Campaigns endpoint regarding invalid request body parameters for non-rss campaigns.
We were receiving requests that were attempting to create non-
rss type campaigns with an
rss_opts field. These requests were throwing exceptions and returning
500 status codes to users. We now return a
400 status code if
rss_opts are provided for non-
rss type campaigns.
Sunsetting the Mailchimp API Playground
We shut down the Mailchimp API Playground.
Updated list automations query parameters
We fixed a mistake in the query parameters for filtering a list of automations.
The query parameter filters were incorrectly documented as
since_send_time. The correct parameters are
Deprecating the Update Automation endpoint
We removed the unused Update Automation endpoint.
This endpoint was limited in which automations workflow types could be updated, and no successful calls had been made to this endpoint in many months. We opted to deprecate it until we can provide a more useful method of updating automations.
Since we don’t see any usage of this endpoint, we don’t expect any action to be needed.
Internal infrastructure improvements
We rewrote large parts of the API internals. There should be little to no external impact on API behavior, besides slight performance fluctuations.
The internals of the API had accumulated a fair bit of kludge over the past 5-10 years, so we rewrote a good portion of them and have identified several discrepancies in behavior across endpoints. During the rewrite, we learned about and ironed out many of the discrepancies that were causing friction internally—and in the process, we identified further changes that we’ll implement in the future to make behaviors across the APIs more consistent.
Assorted spec and documentation fixes
We made a variety of fixes to our Swagger spec to improve the documentation.
There were endpoints included in the documentation that have no function except to organize the path hierarchy. For example:
/reporting. We removed them since they’re not useful on their own. Additionally, there were some
body parameters included incorrectly, for properties that are read-only and can’t be passed in as a parameter
Ensuring codegen references latest Swagger spec
We use a Swagger spec to produce API client libraries from the codegen repo. Doing this required tweaking the Swagger spec that’s automatically produced by our internal API definitions, so there was some drift between the spec in the codegen repo and the one we produce automatically. We backported the changes, so our automatically-produced spec matched the one in the codegen repo. Now that this work is done, we can rely on the automatically produced spec for client libraries.
Deprecated fields in the Growth History endpoint
We’ve stopped calculating the (deprecated)
imports fields for the Growth History endpoint, and API responses will have a value of zero for these fields.
The data in these fields can be accessed in a more understandable way in other fields, and returning the data in these fields was slow and added infrastructure load when these endpoints were requested.
New client libraries for Marketing and Transactional APIs
We have released API client libraries for the Marketing and Transactional APIs, supporting PHP, Node.js, Ruby, and Python.
We wanted to make it easier for developers to integrate their applications with both of our APIs in the language of their choice. The new libraries are generated from publicly available API specs and published on the respective package managers for each supported language.
Preventing multiple confirmation emails on PATCH or PUT to Lists/Member endpoint
It was possible to force multiple confirmation emails to be sent to a member when using identical PATCH or PUT requests to the Members resource. We’ve corrected this behavior by preventing the duplicate confirmation emails from being sent.
Before this change, multiple confirmation emails would be sent to a member’s inbox, which could potentially be used for abuse.
Stricter rules for URL matching in OAuth 2
The security team has implemented stricter rules around redirect URL matching in our OAuth 2 implementation. We now only support exact matching on the redirect URI to adhere to the OAuth 2 spec.
Before this change, our redirect URL matching didn’t conform to the OAuth 2 spec. Strictly adhering to the spec results in more predictable behavior and fewer surprises.
Obfuscated emails on the Unsubscribe page
We changed the behavior of the unsubscribe merge tag to obfuscate the email address of the person who clicked the link. Instead of showing the entire address, the
md_email parameter now displays the address as something like x****@x***.*** .
Previously, if a customer clicked an unsubscribe link, their email address was displayed on the Unsubscribe page in full. By obfuscating the email address, this change provides better security.
Improved error messaging on malformed requests to the Members endpoint
Previously, if an object was passed as the value of the email field in a POST to the Lists/members endpoint, the server would return a 500 error. Now we return a 400 error with a clear error message.
We saw multiple occurrences of these errors in our logs. Ideally, badly formed requests shouldn’t return 500 errors, and we should give more information to callers when errors do occur.
API Swagger spec now OAS 2-compliant
We’ve updated our Swagger file to make it OAS 2-compliant. Our API Reference documentation is generated from our Swagger file. Before this change, we used a number of non-standard field names to control formatting in those docs. We cleaned those fields up and added testing to prevent drift in the future.
We’d heard from developers that an OAS 2-compliant Swagger would greatly improve the developer experience for the Marketing API. This update makes it possible, for example, to directly use our Swagger file in Postman to more easily make requests to our API endpoints, in addition to better integration with many other OAS-friendly tools.
Minor improvement to parameter handling in the Events endpoint
Previously, null-valued entries in the
properties object passed to the Events endpoint would cause a server error, returning a 500 to the client. With this change, we treat null property values as empty strings.
This change gives clients a little more flexibility with how they format the
properties parameter, and it cleans up our server logs.