WP Webhooks / Blog / Integrations

Adding WooCommerce Customers to MailerLite With the Official Plugin or the API

WooCommerce to MailerLite: what the official plugin covers, the API upsert that never removes groups, consent at checkout, and the 120-a-minute limit.

8 min 2026-10-20
#mailerlite#woocommerce#api

TL;DR: For most stores the official MailerLite plugin is the right answer. Go to the API when MailerLite is one destination among several, or when the rules about who lands in which group are yours.

  • POST https://connect.mailerlite.com/api/subscribers is an upsert: 201 when it creates, 200 when it updates. Fields and groups you leave out are never removed.
  • PUT /api/subscribers/:id is not the same call. It removes the subscriber from every group you do not list.
  • Consent is your job. A checkbox registered with WooCommerce's additional checkout fields API is stored on the order, and the code that reads it decides whether anything is sent at all.
  • The limit is 120 requests a minute per account, with a Retry-After header on the 429.

/ Official plugin

Is there an official MailerLite plugin for WooCommerce?

Yes, and it is good. MailerLite – WooCommerce integration has 30,000+ active installs.¹ It adds a subscribe checkbox to checkout with a choice of position and label, a double opt-in switch, order data forwarded to MailerLite, product import, order-related custom fields and segments, sales tracking for campaign ROI, automations triggered by recent purchases, and abandoned cart emails.

That list covers what most shops want. If yours is one of them, install it and stop reading. Abandoned carts in particular are not something you should rebuild yourself.

The API is for the cases the plugin was not built around. The same customer also has to reach a CRM, a Slack channel or an n8n workflow, and you want one place where every delivery is logged. Group membership depends on rules that are yours: which product was bought, whether it was a renewal, which shipping country. Or the event is not a checkout at all, such as a membership activation or a course enrolment.

/ Authentication

How do you authenticate to the MailerLite API?

With an API key sent as a Bearer token. In MailerLite, open Integrations, choose MailerLite API and click Generate new token. MailerLite shows the key once and stores it hashed, so copy it straight into wherever your site keeps secrets.

Two details from the getting-started page matter in production. Every request sends Content-Type: application/json and Accept: application/json to the base URL https://connect.mailerlite.com/api. And the key is bound to the user who created it: remove that person from the account and the key stops authenticating, and every request answers 401 Unauthenticated. Create it from an account owner who is not about to leave, and name it after the site.

Requests use the latest API version unless you pin one. Send X-Version with the date you implemented the integration and a later change to the API cannot alter what your requests do.

/ Upsert

Which endpoint adds a WooCommerce customer without creating duplicates?

POST /api/subscribers. The subscribers reference calls it create/upsert: if the email exists the subscriber is updated, and it is a non-destructive operation, so omitting fields or groups does not remove them. Only email is required. The response code tells you which case happened: 201 Created for a new subscriber, 200 OK for an existing one.

JSON — body for POST /api/subscribers

{
  "email": "[email protected]",
  "fields": {
    "name": "Ada",
    "last_name": "Lovelace"
  },
  "groups": ["4243829086487936"]
}

Three rules decide whether that body works:

  • groups holds group ids, not names, and the groups must already exist. Read the ids from GET /api/groups once and keep them in configuration.
  • Every key in fields must be a default or custom field. name and last_name exist on every account. Anything else, such as last_order_total, has to be created first with POST /api/fields, which takes a name and a type of text, number or date.
  • Do not switch to PUT for updates. PUT /api/subscribers/:id looks like the update half of the API, but the same reference says the subscriber "will be removed from unlisted groups". A PUT that sends only the customer group silently takes the person out of every newsletter group they joined from a form.
FIG 01 — Consent decides whether an event exists at all; the upsert only adds fields and groups

/ Consent

How do you record newsletter consent at WooCommerce checkout?

WooCommerce has no marketing checkbox of its own, and the MailerLite API accepts any address you send it. Whether the customer agreed is a fact only your checkout knows. Add the checkbox with the additional checkout fields API, which stores the answer on the order. Then fire your own action only when the box was ticked:

PHP — checkout checkbox and an opt-in action

add_action( 'woocommerce_init', function () {
    woocommerce_register_additional_checkout_field( array(
        'id'       => 'my-shop/newsletter',
        'label'    => 'Email me news and offers',
        'location' => 'order',
        'type'     => 'checkbox',
    ) );
} );

add_action( 'woocommerce_order_status_processing', function ( $order_id, $order ) {
    // Order-location fields are saved under the _wc_other/ prefix; a ticked box is "1".
    if ( '1' === $order->get_meta( '_wc_other/my-shop/newsletter' ) ) {
        do_action( 'my_shop_newsletter_optin', $order );
    }
}, 10, 2 );

Three things to know about that code. The field API renders in the Checkout block only, not the old [woocommerce_checkout] shortcode. WooCommerce's docs recommend reading values through their CheckoutFields helper and document the _wc_other/ meta key as the direct route, with a ticked checkbox stored as "1". And woocommerce_order_status_processing fires again if an order goes back to processing after being on hold. That is harmless here, because the upsert is idempotent: the same email lands on the same subscriber.

Gating the event, rather than sending everyone and filtering later, means a customer who did not tick the box never reaches MailerLite at all. No log, no queue entry, no subscriber record to clean up.

/ Unsubscribed

What happens when a customer who unsubscribed orders again?

They stay unsubscribed. The upsert updates their fields and groups but does not change the status back to active. The endpoint does take a resubscribe flag, documented as "set to true to resubscribe previously unsubscribed subscribers", and that is the point where a careless integration does damage.

Ticking a box at checkout is fresh consent, so setting resubscribe for an order with the box ticked is defensible. Setting it on every order is not: a customer who unsubscribed in March and bought again in October without ticking anything would be back on the list. The PUT endpoint is stricter still. For an unsubscribed, bounced or junk subscriber, the reference says reactivation is only possible through the app, a form or a landing page.

/ Rate limits

What are the MailerLite API rate limits?

A global limit of 120 requests per minute. Past it you get 429 Too Many Attempts with X-RateLimit-Remaining: 0 and a Retry-After header in seconds. Imports have a separate limit of 5 requests per minute, and that includes batch requests made up entirely of subscriber upserts.

Checked against real store volume, with one upsert per opted-in order:

  • A Black Friday hour of 600 orders is 600 ÷ 60 = 10 requests a minute, a twelfth of the limit.
  • Backfilling 20,000 existing customers one by one is 20,000 ÷ 120 = 167 minutes at the very best. Use the import endpoint instead.

So the live integration will not hit the limit. A backfill sharing the same key with it will, and the live orders arriving during the backfill are the ones that get the 429s.

ConcernHand-rolled wp_remote_postWebhook Actions
Abandoned carts, product sync, campaign ROINot this. Use the official pluginNot this either. It delivers events; it has no MailerLite connector and no cart tracking
Which eventsOne add_action per event, written by youAny WordPress action as a trigger, including your own my_shop_newsletter_optin
Where the call runsInside the status change unless you build a queueQueued in its own table, delivered in the background
The API keyA constant in wp-config.phpA Bearer credential in the Credentials Vault, redacted in every log
email, name, last_nameBuilt in your arrayField mapping from args.0.billing into email, fields.name and fields.last_name
Group idsWritten in your arrayA short pre-dispatch snippet; field mapping moves values and cannot invent one
A 429 or 5xxLost unless you wrote retry logicRetried with exponential backoff, five attempts by default. Retry-After is not read
A 422 from an unknown fieldInvisibleMarked permanently failed with MailerLite's errors object in the delivery log, replayable after the fix

The group rules are a few lines of PHP. Field mapping has already produced email and the two name fields, and passed the order's line items through as items; the snippet turns products into group ids:

PHP — pre-dispatch snippet that sets the groups

// $payload arrives field-mapped: email, fields.name, fields.last_name, items.
$groups     = [ '4243829086487936' ];               // everyone who opted in
$by_product = [ 412 => '31985378335392975' ];       // product id => group id

foreach ( $payload['items'] ?? [] as $item ) {
    if ( isset( $by_product[ $item['product_id'] ] ) ) {
        $groups[] = $by_product[ $item['product_id'] ];
    }
}

$payload['groups'] = array_values( array_unique( $groups ) );
unset( $payload['items'] );                         // MailerLite does not need them
return $payload;
try_it

Seeing it run beats reading about it. The live preview boots a throwaway WordPress with Webhook Actions already installed and demo deliveries sitting in the log — no signup, nothing left on your machine afterwards.

/ Failures

Which MailerLite errors should be retried?

Only 429 and 5xx. A 429 clears by itself. With retries 60 and then a further 120 seconds apart, the second retry lands 60 + 120 = 180 seconds after the first attempt, past even the 119-second Retry-After in MailerLite's own example, without the header ever being read. A 5xx is on MailerLite's side and is usually brief.

Everything in the 4xx range is a request that will fail the same way next time. A 401 means the key was revoked or its user was removed. A 422 carries an errors object naming the field, most often an invalid email or a fields key that does not exist on the account. A 403 means the action is denied for that account or token. Retrying those burns requests from the same 120-a-minute budget the healthy orders need. Log them where someone will look, which is the whole subject of why webhooks fail silently.

/ Exposure

What does MailerLite not protect you from?

Your own consent logic. MailerLite's terms put it directly: when you collect subscribers through your own API key, you are responsible for preventing abuse. A checkout that adds everyone is a checkout that sends campaigns to people who never asked for them, and spam complaints count against the account's sending reputation.

The bill. MailerLite plans are priced by subscriber count. Every guest checkout you push in moves you toward the next tier, whether or not that person ever opens an email. Opt-in gating keeps the list and the invoice the same size as your actual audience.

A key that dies with a person. Because the key is bound to its creator, an offboarding in the marketing team can stop the integration with no change on your side. The symptom is a run of 401s, which is why a 401 should alert rather than retry.

If the same store also feeds Mailchimp or Klaviyo, the Mailchimp and Klaviyo articles cover their APIs, which handle status and tags quite differently.

/Footnotes
¹ MailerLite – WooCommerce integration on WordPress.org, read 2026-10-22: version 3.1.28, 30,000+ active installations. Feature list from the plugin description.
² Endpoint behaviour, status codes and rate limits from the MailerLite API documentation, read 2026-10-22.
FAQ

Things engineers always ask.

Don't see yours? Open an issue on GitHub or check the full reference in the API docs.

Is there an official MailerLite plugin for WooCommerce? +
Yes. MailerLite - WooCommerce integration has 30,000+ active installs. It adds a subscribe checkbox at checkout with a double opt-in switch, forwards order data, imports products, tracks sales for campaign ROI and sends abandoned cart emails. Use the API when the group rules are your own or MailerLite is one of several destinations.
How do I add a subscriber with the MailerLite API without creating duplicates? +
Send POST https://connect.mailerlite.com/api/subscribers with a Bearer API key. It is an upsert: 201 Created for a new email, 200 OK for an existing one. It is non-destructive, so fields and groups you leave out are not removed from the subscriber.
Why did a MailerLite subscriber disappear from their groups after an update? +
Because the update was a PUT to /api/subscribers/:id. Unlike the POST upsert, PUT removes the subscriber from every group not listed in the request. Use the POST upsert to add groups, or POST /api/subscribers/{subscriber_id}/groups/{group_id} to assign one group.
Can the MailerLite API resubscribe someone who unsubscribed? +
Only if you ask. The upsert leaves an unsubscribed subscriber unsubscribed unless you send resubscribe set to true. Send it only when the customer gave fresh consent, such as ticking a newsletter box at checkout, never for every new order.
What is the MailerLite API rate limit? +
A global limit of 120 requests per minute, answered with 429 and a Retry-After header when exceeded. Imports, including batch requests made entirely of subscriber upserts, have a separate limit of 5 requests per minute.
Ready

Your next automation is
one sentence away.

$ wp plugin install flowsystems-webhook-actions --activate