Three ways to add subscribers
Yaplet supports bulk CSV uploads, a REST API, and manual single-contact entry. All three paths use the same deduplication logic: if an email address already exists, Yaplet updates that record rather than creating a duplicate.
Option 1 — Upload a CSV file
Go to 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.
- Prepare your file with at least an
emailcolumn. The email column header is detected automatically (case-insensitive). A name column is also auto-detected from headers containingname,firstname, orlastname— if bothfirstnameandlastnameare present, they are concatenated into a single name. - Add any custom field tags as additional columns. Only custom field columns require an exact tag match — unknown columns are ignored.
- Upload the file. The import button updates to show the parsed row count — that count is the only validation feedback before submitting.
- 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).
- Click Import. Imports time out at two minutes — split files larger than a few thousand rows.
Any row whose email already exists in your list is merged: name and custom-field values are updated, group memberships are added, and the subscriber's existing state is preserved. An existing Unsubscribed contact will not be re-activated by a reimport.
Option 2 — Bulk upsert via API
Send an authenticated POST request to /api/newsletter/contacts/bulk-upsert. Authenticate with your workspace API key in the Y-API-Key header.
POST /api/newsletter/contacts/bulk-upsert
Y-API-Key: your-workspace-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 is only honored when promoting an existing REMOVED contact back; for brand-new contacts, omit this field and let the background check decide. |
verification_id |
UUID | No | The verification email variant to send. 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. This is the only condition that produces a 400.
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.
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, an optional name, any custom field values, and the groups to add them to. Click Save.
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. |
| 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. 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. |
What's next
With subscribers in your list, organize them into dynamic segments or static groups to target specific audiences in your campaigns.