Cordial: Telltide Seed Address Guide
Place Telltide seeds in Cordial audiences and orchestrations.
Cordial is a cross-channel messaging platform that uses a contact-centric model where the subscribeStatus field controls email deliverability. Lists in Cordial are boolean contact attributes; a contact is "on" a list by having that attribute set to true. Automations are triggered by events, list additions (with Date Tracking enabled), or API calls. The most important constraint for seed management: Cordial has AI-powered Frequency Optimization that dynamically caps the number of weekly emails per contact based on engagement history, and a seed with minimal engagement history may be suppressed by the cap after 12 weeks of account data accumulates.
Quick reference
| Send type | Where to add seeds | Complexity |
|---|---|---|
| Scheduled (Broadcast) | Create seed contact with subscribeStatus = subscribed; target via Audience Builder condition | Low |
| Ongoing (Automation) | Create seed contact; trigger via event, list attribute change, or API trigger | Medium |
1. Scheduled / one-off sends (Broadcasts)
Cordial Broadcasts are one-time email sends. The audience is built with the Audience Builder using contact attributes, list memberships, events, and purchase history. Seeds must be contacts with subscribeStatus = subscribed.
Where to add seed addresses
The simplest approach: set a custom boolean attribute internal_test_user = true on seed contacts. In the Broadcast Audience Builder, add this as an OR condition: internal_test_user is true alongside the main audience rules.
Non-technical path
For CRM managers without API access. All of these options live inside the Cordial UI.
- Add a Contact directly. Navigate to Contacts > Contacts, click + New Contact, enter the seed email address, set
channels.email.subscribeStatustosubscribed, add the custom attributeinternal_test_user: true, assign the contact to any relevant Lists, and save. - CSV import via Contact Import. Build a CSV with columns for email,
subscribeStatus,internal_test_user, and any list keys. Navigate to Contacts > Contact Imports, upload the CSV, and map columns to attributes. - Sign-up form. If your account uses a Cordial-hosted sign-up form or JavaScript Listener form, submit the seed email through the same form your real subscribers use. This guarantees the seed runs through the exact welcome path.
- Manual Audience or List add. Navigate to Contacts > Lists, open the trigger List, and use Add Contacts to attach the seed. For Audiences, save the seed as a Contact first, then verify the Audience preview shows the seed when the OR clause is in place.
Technical path
For email-dev and ops. Cordial's REST API base URL depends on your account region: https://api.cordial.io/v2/ for accounts on admin.cordial.io, or https://api.usw2.cordial.io/v2/ for accounts on usw2.admin.cordial.io. Authentication is HTTP Basic: pass the encoded API key (generated under Settings > API Keys) as the username and leave the password blank.
Upsert a seed contact
POST https://api.cordial.io/v2/contacts
Content-Type: application/json
Authorization: Basic {{base64_encoded_api_key}}
{
"channels": {
"email": {
"address": "seed@example.com",
"subscribeStatus": "subscribed"
}
},
"first_name": "Seed",
"last_name": "Monitor",
"internal_test_user": true
}
subscribeStatus values: "subscribed" (receives marketing emails), "unsubscribed" (excluded from all sends), "none" (excluded from sends; the default if omitted).
Custom attribute requirement: Contact attributes must be created in the account before they can be populated. Navigate to Contacts > Attributes to create internal_test_user (boolean type) if it does not already exist.
Upsert behavior: If a contact matching the identifier already exists, the record is updated. Otherwise a new contact is created.
forceSubscribe: true: Add this field to re-subscribe a contact that was previously unsubscribed:
POST https://api.cordial.io/v2/contacts
Authorization: Basic {{base64_encoded_api_key}}
{
"channels": {
"email": {
"address": "seed@example.com",
"subscribeStatus": "subscribed"
}
},
"forceSubscribe": true
}
Add the seed to a List via API
Lists are stored as a key/value map on the contact. Set the list key to true to add, false to remove:
POST https://api.cordial.io/v2/contacts
Authorization: Basic {{base64_encoded_api_key}}
{
"channels": {"email": {"address": "seed@example.com", "subscribeStatus": "subscribed"}},
"lists": {
"newsletter": true,
"vip": true
}
}
Push a behavioral event for the seed
Cordial Events are recorded via POST /v2/contactactivities. The action name lives in the a field, the contact identifier in email (or cID), and event data in properties:
POST https://api.cordial.io/v2/contactactivities
Authorization: Basic {{base64_encoded_api_key}}
{
"a": "browse",
"email": "seed@example.com",
"ats": "2026-05-01 09:30:00",
"properties": {
"category": "Electronics",
"title": "Widget Pro",
"url": "https://yourstore.com/products/widget",
"price": 49.99
}
}
Profile attributes required
Seeds need:
- Email address
channels.email.subscribeStatus = "subscribed"(contacts withunsubscribedornonestatus are excluded from broadcast audience counts and sends)- Values for any custom attributes referenced in the message template
Ensuring seeds receive the same version as real recipients
Dynamic Audience Builder rules: Audiences are evaluated in real time. If the broadcast uses rules based on purchase history, engagement, or other behavioral data, the seed must satisfy those conditions OR be included via the internal_test_user = true OR condition.
A/B split in Broadcasts: Cordial supports retargeting broadcasts (resend to contacts who did or did not open or click). For initial A/B variant testing, the seed is assigned to one branch. Use multiple seed contacts to monitor all variants.
Gotchas
Frequency Optimization may suppress seeds. Cordial's AI-powered Frequency Optimization caps weekly email sends per contact based on engagement data. After 12 weeks of data accumulates in the account, seeds with low engagement scores may have their weekly cap reduced and be excluded from sends. The cap can be turned off during specific periods. Monitor whether seeds are showing as "Skipped" in Message Reports due to the frequency cap.
forceSubscribe: true is required to re-subscribe. A contact that was previously unsubscribed (via an unsubscribe link, spam complaint, or manual update) has subscribeStatus = unsubscribed. Updating their status to subscribed without forceSubscribe: true may not re-enable delivery. Always include forceSubscribe: true when reactivating seed accounts.
2. Ongoing / automated journeys (Automations)
Cordial Automations are triggered messaging sequences. Three sending methods are available: Event Triggered, Recurring, and API Triggered.
Automation trigger types
| Trigger type | How it fires | Seed approach |
|---|---|---|
| Event Triggered, event | Fires when a contact triggers a defined event (e.g., cart, purchase) | Track the event via /v2/contactactivities or a connected store |
| Event Triggered, added to list | Fires when a contact is added to a list (requires Date Tracking on the list) | Add seed to the trigger list via API or UI |
| Event Triggered, attribute change | Fires when a contact attribute value changes | Update the trigger attribute on the seed contact |
| Recurring | Runs on a schedule; checks conditions on each run | Seed must qualify at the scheduled check time |
| API Triggered | Fired via POST /v2/automationtemplates/{key}/send | Call the API trigger endpoint with seed contact data |
Always-on flow coverage
Always-on Automations only deliver to seeds when the seed satisfies the same Audience and entry conditions as a real contact. Bake seed coverage into the automation primitives directly:
- Audience entry condition. Open the Automation, inspect the Audience attached to the entry step, and add an OR clause
internal_test_user is trueso seed contacts qualify regardless of behavioral history. For dynamic Audiences referenced inside Recurring Automations, add the same OR clause to the Audience definition under Audiences > [name] > Edit Rules. - List trigger. When the trigger is "added to list," confirm the target List has Date Tracking enabled before the seed is ever attached. Add the seed via
POST /v2/contactswithlists: {"<list_key>": true}so the List Date is captured fresh. - Event trigger. When the trigger is an Event, push the same event name and required
propertieskeys viaPOST /v2/contactactivitiesfor the seed. If the Automation filters on event property values (for exampleproperties.totalValue >= 50), the seed event payload must satisfy those filters. - Attribute change trigger. Update the watched attribute on the seed (
birth_date,last_purchase_date, etc.) so the change event fires. Re-entry is gated by the Automation's re-entry rule, not the API. - Frequency Optimization bypass. For monitoring-critical Automations, mark the message type as transactional or essential so Cordial's frequency cap does not silently skip the seed.
Creating trap profiles per journey type
Welcome / onboarding (Added to list trigger)
- Trigger: Contact is added to a specific list (list must have "Date Tracking" enabled)
- Seed requirements: Contact with
subscribeStatus = subscribed - How to enable Date Tracking on a list: Navigate to the list settings in Cordial and enable "Date Tracking." This records the timestamp when a contact is added, which is used to fire the trigger.
- How to trigger: Add the seed contact to the trigger list via the API:
POST https://api.cordial.io/v2/contacts
Content-Type: application/json
Authorization: Basic {{base64_encoded_api_key}}
{
"channels": {
"email": {
"address": "seed@example.com",
"subscribeStatus": "subscribed"
}
},
"lists": {
"welcome-trigger-list": true
}
}
Where welcome-trigger-list is the key name of your trigger list. The list key must already exist in the account.
Abandoned cart (Cart event trigger)
- Trigger:
cartevent recorded for the contact, containing items array - Seed requirements: Contact with
subscribeStatus = subscribed - How to trigger via the contact activities API:
POST https://api.cordial.io/v2/contactactivities
Content-Type: application/json
Authorization: Basic {{base64_encoded_api_key}}
{
"a": "cart",
"email": "seed@example.com",
"ats": "2026-05-01 09:30:00",
"properties": {
"cartId": "CART-TEST-001",
"totalValue": 95.00,
"currency": "USD",
"items": [
{
"productId": "SKU-123",
"name": "Widget Pro",
"price": 95.00,
"quantity": 1,
"imageUrl": "https://yourstore.com/img/widget.jpg",
"productUrl": "https://yourstore.com/products/widget"
}
]
}
}
The exact event name and required properties depend on how your Cordial account's abandoned cart event type is configured.
Browse abandonment (Browse event trigger)
- Trigger: Browse event recorded when the contact views a product or category
- Seed requirements: Contact with
subscribeStatus = subscribed - How to trigger:
POST https://api.cordial.io/v2/contactactivities
Authorization: Basic {{base64_encoded_api_key}}
{
"a": "browse",
"email": "seed@example.com",
"ats": "2026-05-01 09:30:00",
"properties": {
"productId": "SKU-123",
"title": "Widget Pro",
"category": "Electronics",
"url": "https://yourstore.com/products/widget",
"imageUrl": "https://yourstore.com/img/widget.jpg",
"price": 49.99
}
}
Winback / re-engagement (Recurring trigger)
- Trigger: Recurring automation running daily or weekly; conditions filter contacts with
last_purchase_dateolder than the lapse threshold - Seed requirements: Contact with
last_purchase_dateattribute set to a date older than the threshold
Set the attribute:
POST https://api.cordial.io/v2/contacts
Authorization: Basic {{base64_encoded_api_key}}
{
"channels": {"email": {"address": "seed@example.com", "subscribeStatus": "subscribed"}},
"last_purchase_date": "2026-01-15"
}
The attribute key must match what is configured in the automation's condition rules.
Post-purchase (Purchase event trigger)
- Trigger:
purchaseevent recorded for the contact - Seed requirements: Contact with
subscribeStatus = subscribed - How to trigger:
POST https://api.cordial.io/v2/contactactivities
Authorization: Basic {{base64_encoded_api_key}}
{
"a": "purchase",
"email": "seed@example.com",
"ats": "2026-05-01 09:30:00",
"properties": {
"orderId": "TEST-ORD-001",
"orderTotal": 149.99,
"currency": "USD",
"items": [
{
"productId": "SKU-123",
"name": "Widget Pro",
"quantity": 1,
"price": 149.99
}
]
}
}
Birthday / anniversary (Attribute change trigger)
- Trigger: Contact attribute value changes on
birth_date(or equivalent date attribute) - Seed requirements: Contact with
birth_dateattribute; trigger fires when the attribute is first set or updated - Alternative: Recurring trigger that checks
anniversary_of(birth_date) = today
Set birthday attribute:
POST https://api.cordial.io/v2/contacts
Authorization: Basic {{base64_encoded_api_key}}
{
"channels": {"email": {"address": "seed@example.com", "subscribeStatus": "subscribed"}},
"birth_date": "1990-04-15"
}
The attribute change trigger fires when this value is written. For anniversary-based recurring triggers: set the date to today's month and day so the recurring check matches.
API Triggered automations
For automations that use the API Triggered method, the request body uses a to envelope containing a contact object plus optional extVars for template personalization, and an identifyBy field that names the lookup identifier:
POST https://api.cordial.io/v2/automationtemplates/{automation_key}/send
Content-Type: application/json
Authorization: Basic {{base64_encoded_api_key}}
{
"identifyBy": "channels.email.address",
"to": {
"contact": {
"channels": {
"email": {
"address": "seed@example.com",
"subscribeStatus": "subscribed"
}
}
},
"extVars": {
"orderID": "TEST-ORD-001",
"orderTotal": 149.99
}
}
}
Replace {automation_key} with the automation template key visible in the Cordial automation settings. Values inside extVars are accessible in the template as {$extVars.orderID}. Use this method for any automation where simulating the natural trigger event is impractical.
How to reset seeds for repeated testing
Event-triggered automations: Track the trigger event again via /v2/contactactivities. Cordial typically allows re-entry unless the automation has a re-entry restriction configured.
List-triggered automations: Remove the seed from the trigger list (lists: {"welcome-trigger-list": false}), wait for processing, then re-add the seed to the list.
Recurring automations: The automation re-evaluates on its next scheduled run. Update the seed's qualifying attributes between cycles as needed.
API Triggered automations: Call the API trigger endpoint again.
3. Platform-specific considerations
API options
Base URLs by region:
https://api.cordial.io/v2/for accounts onadmin.cordial.iohttps://api.usw2.cordial.io/v2/for accounts onusw2.admin.cordial.io
Create or update contact (upsert):
POST https://api.cordial.io/v2/contacts
Authorization: Basic {{base64_encoded_api_key}}
Batch upsert contacts:
POST https://api.cordial.io/v2/contactimports
Record a contact activity (event):
POST https://api.cordial.io/v2/contactactivities
Trigger an API-driven automation:
POST https://api.cordial.io/v2/automationtemplates/{key}/send
API key location: Settings > API Keys > Generate Key. The IP address used to call the API must be whitelisted at key creation time. Pass the encoded key as the username in HTTP Basic Auth, with an empty password.
Rate limits
Cordial does not publish specific rate limits publicly. Implement exponential backoff on 429 responses. For large bulk operations, use the contactimports batch endpoint or the Asynchronous API. Cordial also exposes per-account throttling settings inside the platform that govern outbound batch send rate.
Channel coverage
Cordial supports email, SMS, mobile push, in-app, and a generic REST channel for direct mail or call-center integrations. Seed monitoring is email-only; SMS and push seeds require channel-specific identifiers (channels.sms.address, channels.push.tokens) and cannot be served by Telltide's email seed pipeline.
Duplicate contact handling
Contacts are matched by an ordered identifier priority list: cID (Cordial-assigned internal ID) first, then configured secondary identifiers (email, custom ID). If a match is found on any identifier, the existing contact is updated. If no match, a new contact is created.
The identifiersPriority parameter on the upsert request lets you control the lookup order explicitly.
Platform-specific terminology
| Cordial term | What it means |
|---|---|
| Contact | A person record in Cordial (equivalent to a Subscriber or Profile in other platforms). |
subscribeStatus | The email marketing opt-in state: subscribed, unsubscribed, none. |
| Broadcast | A one-time email send (equivalent to a Campaign or Blast in other platforms). |
| Automation | A triggered or recurring messaging sequence. |
| List | A boolean contact attribute; a contact is "on" a list by having the list attribute set to true. |
| Date Tracking | A list setting that records the timestamp when a contact is added. Required for "added to list" automation triggers. |
| Contact activity (Event) | A behavioral signal tracked for a contact (e.g., cart, purchase, browse), recorded via /v2/contactactivities. |
| Audience Builder | The drag-and-drop rule builder used to define broadcast audiences from contact attributes, lists, events, and orders. |
| Supplements | Auxiliary data collections (product catalog, store locations, coupon codes) referenced in templates and audience rules. |
| Frequency Optimization | Cordial's AI-driven per-contact weekly email cap. Requires 12 weeks of send history for accurate modeling. |
| Unsubscribe Risk AI | Cordial's feature that scores each contact on 4-week unsubscribe likelihood. |
forceSubscribe | API parameter that overrides a previously set unsubscribe flag to re-enable a contact's email delivery. |
cID | Cordial's system-assigned internal contact identifier. The highest-priority deduplication key. |
Known limitations and workarounds
Frequency Optimization silently suppresses sends. After 12 weeks of account data, seeds with low engagement may be skipped by the frequency cap. Monitor the "Skipped" count in Message Reports. Turn off Frequency Optimization during critical monitoring periods or configure transactional or essential message types to bypass the cap.
List Date Tracking must be enabled before the trigger can fire. If you add a seed to a list and then enable Date Tracking, the seed's previous addition event is not captured. Enable Date Tracking on lists before adding seeds.
Custom attributes must be created before population. Attempting to set an attribute that does not exist in the account's attribute schema fails silently or returns an error. Always verify attribute existence before creating seed contacts with custom fields.
forceSubscribe: true is required to re-subscribe previously unsubscribed contacts. Standard attribute updates without this flag may not override the unsubscribed state. Include it on all seed re-activation calls.
API key IP allowlist. Cordial API keys are bound to the IP addresses whitelisted at key creation. Calls from any other origin return an auth error even with valid credentials. Plan ingress IPs ahead of seed automation.
Start monitoring your Cordial sends
Place a Telltide seed in your Cordial audience, and we will tell you when an expected email did not land.
Start free