Import subscribers from CSV or API

Updated May 22, 2026

Three ways to add subscribers

Yaplet supports bulk CSV uploads, a REST API, and manual single-contact entry. The three paths treat an address you already have on your list differently: a CSV import skips it and leaves it exactly as it was, the manual form refuses it with "Subscriber already exists", and only the bulk-upsert API updates it. None of them ever create a duplicate.

Option 1 — Upload a CSV file

Go to Marketing → Newsletter → Subscribers and click Add subscriber. That opens the import page with Import from CSV/TXT selected as the default tab. There is no template file to download — the page shows two inline CSV examples (Template Example 1 and Template Example 2) you can copy and edit.

  1. Prepare your file with at least an email column. The email column header is detected automatically (case-insensitive). A name column is also auto-detected from headers containing name, firstname, or lastname — if both firstname and lastname are present, they are concatenated into a single name.
  2. Add any custom field tags as additional columns. Only custom field columns require an exact tag match — unknown columns are ignored.
  3. Upload the file. The import button updates to show the parsed row count — that count is the only validation feedback before submitting.
  4. Toggle Send verification email on if you want each imported contact to confirm their subscription before receiving campaigns. Leave it off to import them as Verified immediately (after a background email-format check).
  5. Click Import subscribers. Imports time out at two minutes — split files larger than a few thousand rows.

Any row whose email already exists in your list is skipped, not updated: the contact keeps its current name, custom-field values, group memberships and state, and the import reports it as a duplicate. Re-uploading a CSV is therefore not a way to bulk-edit contacts you already have, and it will not add them to the groups you picked on the upload screen — use the bulk-upsert API for that.

Yaplet screens addresses as it imports, for free. Any row that's invalid in format, on a disposable or temporary domain, or a system/role address (like no-reply@, postmaster@, or abuse@) is dropped before it's inserted. You get a List cleaned summary with a per-reason breakdown — for example "Skipped 42 addresses that can't be delivered to: 30 invalid, 5 disposable, 7 system/no-reply." Duplicates are reported separately, in their own notice telling you how many rows were already on your list. The same gate runs on the bulk-upsert API, which returns the skipped counts in its response.

Yaplet also keeps a record of addresses that have permanently bounced anywhere on the platform — mailboxes that no longer exist. If your file contains one, the subscriber is still added, but arrives already marked Bounced and is never emailed: the mail provider would refuse the message anyway, and the attempt would only cost you sending reputation. It works the other way round too — when an address permanently bounces anywhere on Yaplet, it's marked Bounced on every list holding it, so a subscriber can show as Bounced without you ever having emailed them. Only permanent bounces work this way. Unsubscribes and spam complaints are decisions about one specific sender and never travel between accounts, and nothing is revealed to you about any other Yaplet account, or to them about yours.

What Yaplet can't check is whether a real mailbox actually exists behind a valid-looking address. Importing an unconfirmed, purchased, or stale list causes bounces and spam complaints — and high rates will automatically pause your sending (see Monitor your email deliverability). If a large share of a list turns out unusable, Yaplet flags it and suggests verifying it first with a service like ZeroBounce, Kickbox, or MillionVerifier. Only import lists you own and have permission to email.

As part of that same background check, Yaplet also looks up the domain of every newly added address: if the domain has no mail server at all, the contact is set to Removed before it can hard-bounce. After a file import, you get one notification in the dashboard per import telling you undeliverable addresses were removed; addresses added through the API or a workflow are removed without a notification. Subscribers already on your list are not re-checked.

Option 2 — Bulk upsert via API

Send an authenticated POST request to the bulk-upsert endpoint. Authenticate with your organisation's API key in the Y-API-Key header. Send at most 20,000 contacts in a single request — split anything larger into several calls.

POST https://yaplet.com/api/newsletter/contacts/bulk-upsert
Y-API-Key: your-api-key
Content-Type: application/json

{
  "contacts": [
    {
      "email": "[email protected]",
      "name": "Jane Smith",
      "state": "VERIFIED",
      "fields": { "plan": "pro", "country": "US" },
      "group_add": ["group-uuid-here"],
      "group_remove": ["other-group-uuid"]
    }
  ]
}

Fields on each contact object:

Field Type Required Notes
email string Yes Used as the unique key with your org ID. Existing contacts are updated.
name string No For new contacts only, defaults to the part of the email before the @ if omitted. Existing contacts keep their current name when no name is sent.
state string No Accepted values: VERIFIED, UNVERIFIED, REMOVED. Any other value is silently dropped. VERIFIED never applies directly: for a new contact, or one in REMOVED, it is saved as NEW and goes through the usual background address check before the contact becomes Verified. On any other existing contact, VERIFIED is not applied. Contacts that bounced or complained keep their state whatever you send; for unsubscribed ones, see below.
verification_id UUID No The verification email variant to send. It must be one of your own workspace's verification email variants — otherwise the whole request fails with 400 Unknown verification_id. New contacts land in NEW first; the background check then transitions them to Unverified (with this email sent) or Verified based on the verification toggle and email-format validity.
fields object No Key-value object keyed by your custom field tags. Types are validated against the field definition.
group_add UUID[] No Array of group IDs to add the contact to.
group_remove UUID[] No Array of group IDs to remove the contact from.
created_at ISO string No Override the contact's creation timestamp (useful when migrating from another platform).

A successful response returns { "success": true, "results": [...] } with the upserted contact records. Errors:

  • 401 — missing or invalid Y-API-Key.
  • 400 — contact limit exceeded for your plan.
  • 400 — contacts is missing, empty, or not an array.
  • 400 — more than 20,000 contacts in one request.
  • 400 — Unknown verification_id: a verification_id is not one of your workspace's verification email variants. Nothing is saved.

Invalid state values and unknown custom-field tags do not raise an error — they are silently filtered out before the upsert. To detect drops, compare results.length in the response against the size of the contacts array you sent.

Existing contacts are matched on (email, org_id): name, fields, and group memberships are updated; the existing state is preserved unless you explicitly send a new state value.

A “no” stays a “no”. Contacts that bounced or complained keep their state whatever you send — their name, fields and groups still update. A contact that unsubscribed stays out of your campaigns as well. If you send it with a verification_id, Yaplet emails the person a new verification email — at most one every 30 days per address; a request inside those 30 days changes nothing. After that email the contact waits as Unverified, gets no campaigns, and becomes Verified only if the person confirms. Without a verification_id it stays Unsubscribed. The same applies to an address you deleted earlier and now send again. Each contact in the response carries the state it actually ended up in.

Option 3 — Add a subscriber manually

For a single contact, click Add subscriber on the Subscribers page to open the import page, then switch to the Add Single Subscriber tab. Fill in the email address and the name — both are required — plus any custom field values and the groups to add them to. Click Add subscriber.

Subscriber states after import

Every imported row first lands in New. A background job then checks the email format and transitions the contact based on the Send verification email toggle you chose at import time:

State Meaning
New Transient state right after import. The background check picks the row up within seconds and moves it to one of the states below. One exception — if you are on the free plan and imported with Send verification email switched on, each confirmation email costs one credit; with an empty credit balance the contacts stay in New until you top up, then move on automatically.
Verified Receives campaigns. Set when verification was off at import and the email format is valid, or after a subscriber clicks the opt-in confirmation link.
Unverified Verification was on at import and the email format is valid. A confirmation email is sent; the contact will not receive campaigns until they click the link.
Unsubscribed Opted out. Reimporting will not re-activate them.
Bounced Hard bounce recorded by the email provider — or an address already known to be permanently undeliverable, even if you never emailed it. Reimporting will not re-activate them.
Complained The recipient marked a message as spam (reported via SES or Hyvor webhooks). Reimporting will not re-activate them.
Removed Manually removed from the list, or auto-removed because the background check rejected the email format as invalid, or because the address's domain has no mail server.

Unsubscribed, Bounced and Complained are a “no” that your workspace cannot undo: no CSV import, API call, subscriber edit, Verify subscribers action or AI assistant connected to your workspace can switch the contact back. Deleting the contact and adding it again does not help either — Yaplet remembers, per workspace, which addresses said no, and the re-added contact comes back with its old state. Only the person can return after unsubscribing, by confirming their subscription themselves; after a bounce or a complaint, not even that. See Unsubscribes and double opt-in.

Once subscribers are in your list, each one carries an Engagement score, shown as a column on the Subscribers table (the subscriber editor calls it Engagement score) — it updates automatically as they read your emails (a real open adds 10 points and a link click 50, while every email sent first takes 10% off, so the score fades when someone stops reading), and higher-scoring subscribers are sent first in each campaign.

What's next

With subscribers in your list, organize them into dynamic segments or static groups to target specific audiences in your campaigns.

Did this article answer your question?