The Legacy Unsubscribe API endpoints are sunset from November 1, 2026. After that date, calls made to these endpoints no longer function, so every flow still using them — your own code, Zapier, Make, n8n — has to point at the v2 multichannel unsubscribe endpoints to keep working without disruption. This article maps each legacy route to its replacement, lists the response changes that can break your existing code, and covers the new contact-level and bulk routes.
Why this is changing
The unsubscribe feature was originally developed when email was the only channel available on lemlist. With several channels now available, the unsubscribe system was reworked to handle them.
That rework also introduced a way to unsubscribe at the Contact level, ensuring no future communication is sent from any channel — including any channel added to the platform later.
Before you start
Calls to the legacy endpoints stop working from November 1, 2026.
The legacy routes only accept emails and domains. LinkedIn URLs and phone numbers can only be unsubscribed through v2.
You cannot re-subscribe a variable whose source is
leadorabuse. These sources are protected and return409.The
limitparameter on the list route accepts a maximum of 100.One bulk unsubscribe request accepts up to 10,000 values.
You need:
A lemlist API key — see Find and use the lemlist API.
A list of every script, integration, and automation that calls an
/unsubscribesroute today.
Key concepts
Variable: a contact value that you can unsubscribe. Four types exist: email, domain (starts with @), LinkedIn URL, phone number.
Contact: a person identified by a
contactId(prefixcon_). Unsubscribing a contact sets thedoNotContactflag, which blocks all channels. The GET Contact route shows this flag in the boolean fieldunsubscribed.Source: the origin of an unsubscription. Possible values:
api,bounced,lead,user,abuse.Idempotence: unsubscribing a variable that is already unsubscribed returns the existing record with code
200.
Phase 1: Swap each legacy call for its v2 replacement
These five endpoints are sunset and act as direct replacements for one another. Replace the route, keep the same intent.
POST /unsubscribes/{email}→POST /v2/unsubscribes/variables/{value}(Unsubscribe Variable)GET /unsubscribes/{email}→GET /v2/unsubscribes/variables/{value}(Get Unsubscribed Variable)GET /unsubscribes→GET /v2/unsubscribes/variables(List Unsubscribed Variables)DELETE /unsubscribes/{email}→DELETE /v2/unsubscribes/variables/{value}(Re-subscribe Variable)GET /unsubs/export→GET /v2/unsubscribes/exports/variables(Export Unsubscribed Variables)
✅ Verify: a call to the v2 route returns 200 with the record, and the same call to the legacy route is no longer used anywhere in your flow.
Phase 2: Update your code for the response changes
These changes can break existing client code. Check each point against your current integration.
POST variable: the
emailfield is removed. Readvalueinstead. The response also addsvariableandsource.GET variable: the response no longer includes
createdAt. A missing value returns404with"Variable not found". An empty value returns400instead of500.DELETE variable: the response is the plain string
"Variable subscribed", not a JSON object. A missing value returns400instead of404. A protected source returns409.GET list: the format does not change. Note the
limitparameter now accepts a maximum of 100.CSV export: the
_idcolumn is added in the first position. Columns become_id, value, source, createdAt.
A future update will change the routes that return a plain string, for example "Variable not found" or "Variable subscribed". These routes will return JSON. This change standardizes the API. Do not depend on the exact string in your code.
✅ Verify: nothing in your code reads email from a POST response, depends on the exact text of the DELETE response, or maps export columns by position.
Phase 3: Update your webhooks
Since March 30, 2026, a Contact unsubscription no longer emits emailsUnsubscribed.
Subscribe to entityUnsubscribed (whole contact) or variableUnsubscribed (single variable) instead.
Phase 4: Use what v2 adds (optional)
You can now unsubscribe in bulk:
POST /v2/unsubscribes/variables→ Bulk Unsubscribe Variables
You also have access to new endpoints that manage unsubscribes at Contact level rather than by specific channel:
GET /v2/unsubscribes/contacts/{contactId}→ Get Contact Subscription StatusPOST /v2/unsubscribes/contacts/{contactId}→ Unsubscribe ContactDELETE /v2/unsubscribes/contacts/{contactId}→ Re-subscribe ContactGET /v2/unsubscribes/exports/contacts→ Export Unsubscribed Contacts
Example
A form on your website unsubscribes people, and your script reads the email back from the response to log it.
Before: POST /unsubscribes/{email}, then read email from the response.
After: POST /v2/unsubscribes/variables/{value}, then read value. You also get variable and source back. If that value is already unsubscribed, you get the existing record with 200, so you don't need to check first.
If you want that person blocked on every channel and not just on one email address, call POST /v2/unsubscribes/contacts/{contactId} instead. This sets doNotContact on the contact.
Troubleshooting
Issue: 404 with "Variable not found" on a GET that used to succeed.
Root cause: the value is not unsubscribed, and v2 returns a 404 where your code expected the legacy response.
Fix: treat 404 as "this value is not unsubscribed" rather than as an error, and remove any read of createdAt from that response.
Issue: 409 when re-subscribing a variable.
Root cause: the variable was unsubscribed by a protected source — lead or abuse.
Fix: read the source field before attempting to re-subscribe, skip protected sources, and handle 409 without retrying.
Issue: your DELETE call fails when handling the response.
Root cause: the response is currently the plain string "Variable subscribed" rather than a JSON object, and it will become JSON in a future update.
Fix: write the response handling so it accepts both a plain string and a JSON object, and never branch on the exact text. Rely on the status code instead, and expect 400 rather than 404 when the value does not exist.
Issue: the email is missing from the response after an unsubscribe.
Root cause: the email field was removed from the POST variable response.
Fix: read value instead.
If your case is different
If you manage unsubscribes inside lemlist rather than through the API, see Use the Unsubscribes section.
If your unsubscribes flow to a CRM, see Sync unsubscribes between lemlist and your CRM.
If you need to create or find an API key first, see Find and use the lemlist API.
This change takes some work to put in place on your end, so reach out to support or your assigned Account Manager if you need extra help.
