Two ways to subscribe a user
There are two supported paths to subscribe a user to an ESP campaign or mailing list programmatically:
-
Variant 1 — Direct server-side or client-side API call. Universal — works for any back-end logic backed by your own opt-in forms and for client-side code that issues HTTP requests directly to the ESP API. Use this when you operate your own subscription UI and do not want to rely on the Piano ESP opt-in widget.
-
Variant 2 — Client-side notification from the page (using the SDK helper). Useful when you want to notify ESP about a new subscriber from a web page without using the built-in opt-in widget.
The remainder of this article documents Variant 1 in detail. Variant 2 is covered in the ESP SDK documentation alongside the handleUserDataPromise helper.
What the API supports
-
Subscribing a known email to one or more mailing lists.
-
Updating up to 16 user merge-field values per call.
-
Bulk deletion of user data via the GDPR endpoint.
-
Listing campaigns and mailing lists, and querying a single user's subscription status.
The API does not support bulk subscription in a single call — each subscribe request handles one email at a time. Larger workloads must iterate over the dataset and call the endpoint per record. The API also does not expose campaign engagement metrics (open rates, click counts); those remain inside the ESP dashboard.
Subscribing a user to a mailing list
Call the securesub endpoint with POST:
POST https://api-esp.piano.io/tracker/securesub?api_key=<api_key>
Set Content-Type: application/json and pass:
{
"email": "<reader_email>",
"mlids": [ idX, idY, ... ]
}
mlids is the list of mailing list IDs the user should be added to. The same endpoint also accepts application/x-www-form-urlencoded, in which case mlids is a comma-separated string.
The base URL changes by environment and region:
|
Environment |
Base URL |
|---|---|
|
Production (US) |
|
|
Production (EU) |
|
|
Production (Asia-Pacific) |
|
|
Sandbox |
|
The API key authenticates the call. The key must match the environment and Site whose mailing lists you are addressing.
Example: adding a user from the EU sandbox
curl --request POST \
'https://sandbox-api-esp.piano.io/tracker/securesub?api_key=<api_key>' \
--header 'Content-Type: application/json' \
--data-raw '{"email":"reader@example.com","mlids":["<mailing_list_id>"]}'
Adding a user to several lists at registration
To subscribe a new user to multiple mailing lists at the moment they register, hook the registrationSuccess event (fired only on a completed registration or login with Identity Management) and call the subscribe endpoint with the captured email and the desired mlids array. If users are not being added to all the lists you expect, confirm that each mailing list has Show in manage subscriptions page enabled — lists with this setting disabled are not included.
Note that anonymous subscribers (users who sign up through a newsletter form without registering) are added via direct API calls; registrationSuccess does not fire for them.
Updating user merge-field data
Use the user merge-field (umf) endpoint to set or refresh custom user data such as preferences or attributes. One call can change up to 16 different merge fields across up to 16 different users.
POST https://api-esp.piano.io/userdata/umfval/pub/<pub_id>/set?api_key=<api_key> Content-Type: application/json
Body:
[
{ "user": "<email or user_id>", "umf": "<merge_field_id or name>", "value": "<value>" }
]
The endpoint accepts users by email or user ID and merge fields by ID or name interchangeably. Whichever identifier you pass is the one returned in the response. The user must already exist in at least one mailing list, and the merge field must already be configured for the site; otherwise the call returns an error.
For larger user-data refreshes, the CSV importer in the mailing list view is faster than calling the API repeatedly. Format the CSV as comma-separated values without surrounding quotes; the first column header must be exactly email, and any additional columns must use header names that match ESP merge-field IDs. Keep each file under 4 MB and split larger datasets.
Keeping a list in sync with another system
A common pattern is to keep an ESP mailing list aligned with subscription state held in another Piano product (Management + Billing) or in a customer's own system:
-
Subscribe a user to the relevant mailing list when access is granted.
-
Unsubscribe them when access is revoked, ends, or is refunded.
Implement this by listening to the relevant Management + Billing/Piano webhooks (access_revoked, subscription_ended, payment refunded, subscription renewed, and so on) and translating each event into a securesub POST or DELETE. Process subscribes and unsubscribes through the same service so the two stay consistent. A nightly reconciliation job that compares current access state in Piano against ESP list membership is a useful safety net for catching missed events.
Bulk operations
Bulk uploads through the API are not supported — each subscribe request is per email. For large initial loads (for example, importing tens of thousands of users), iterate over the dataset and call securesub per record from a script. For bulk user-data refreshes the CSV importer is the supported path.
To bulk-delete users in compliance with GDPR, use:
DELETE https://api-esp.piano.io/userdata/gdpr/data/email/<email>/<site_id>?api_key=<api_key>
Deleting a mailing list does not remove its users from the audience; users persist in the audience until they are deleted through the GDPR endpoint.
Resubscribing users
The way a user was previously removed determines how (and whether) they can be re-added.
Users who unsubscribed themselves via the unsubscribe link
If a user clicked the unsubscribe link in an ESP email, they unsubscribed from the campaign and from every mailing list attached to that campaign. They cannot be resubscribed silently from the dashboard or by re-adding them via API — calling securesub for that email will keep them on status 0 (inactive). Direct them to the re-subscription flow (for example, an opt-in form or a custom preferences page) so they can re-opt in themselves.
If your account needs the opt-in form to resubscribe deactivated users without an extra confirmation step, enable Allow deactivated user resubscription via Opt-in form without any additional confirmations in the User Deactivation Procedure configuration.
Users who were unsubscribed via API
When you have unsubscribed a user via API, they cannot be resubscribed through the dashboard. Use the subscribe endpoint to re-add them. Before doing so, query the subscription status endpoint to confirm the user's current state:
GET https://api-esp.piano.io/tracker/securesub/email/<email>/ml/<mailing_list_id>?api_key=<api_key>
If the response indicates the user is currently inactive (HTTP 404 with subscription status "0"), calling the subscribe endpoint will not always restore them silently if they were taken out via the unsubscribe link. If you need to clear a status on the user record, contact Piano Support.
Bulk resubscription
For larger resubscribe jobs (for example, thousands of users who were inadvertently removed), build a script that iterates over the user list and calls securesub per email. The same per-email constraint applies — there is no bulk endpoint.
Users unsubscribed because of a hard bounce
If a domain or IP was blocked and large numbers of users were unsubscribed because their emails hard-bounced (statuses -2, -3, -9), they cannot be resubscribed via API alone:
-
Confirm with the email provider that your sending domain or IP is no longer blocked.
-
Open a Piano Support ticket. Provide a CSV containing the affected users in the format
,,and the date range during which the hard bounces occurred. -
Piano Support clears the bounce statuses for the specified period.
-
After the statuses are cleared, verify delivery by checking that the affected users are receiving newsletters again. You can request an export of current bounce statuses to confirm.
Troubleshooting
|
Symptom |
Likely cause |
What to check |
|---|---|---|
|
User is added but immediately appears with status |
The email previously unsubscribed from the campaign via the unsubscribe link |
Direct the user through a re-subscription flow; an API subscribe will not restore them silently. |
|
Counts in the API output do not match the Mine users UI |
Webhook-driven sync between source system and ESP is dropping events |
Verify the upstream webhook chain (for example, Management + Billing |
|
|
A mailing list ID does not exist on the site whose key you are using |
Verify |
|
|
Wrong UID type |
ESP operations require ESP-specific user IDs, not Composer IDs. Use the email address where possible. |
|
Subscribe call works but the user is not on every expected list |
A list has Show in manage subscriptions page disabled |
Enable the setting on each list the user should land on. |