Seed lists
A deliverability vendor's monitored mailboxes that receive your broadcasts, and keeping them current.
The SeedListSync object 15 fields
New addresses that will be sent to.
False for a dry run: nothing was written.
Addresses held because they are contacts in this workspace — in the request, or already on the list and found to be contacts now. Never sent to.
Entries that are not valid email addresses — ignored.
Addresses in the request that were retired by hand in the app, or after a hard bounce. They stay retired until restored there.
sendable_after is less than half of sendable_before. Applying it needs allow_large_change=true. A full rotation — every address swapped for a new one — does not shrink the list and is not a large change.
Addresses already on the list whose provider the request stated differently. Their provider is updated; nothing else changes.
Retired or held addresses that became active again.
Up to 10 addresses of each kind.
Active + paused seeds after it.
Active + paused seeds before the update.
The recorded update. Null for a dry run.
The SeedList object 15 fields
Addresses per status.
due_soon is within 5 days of rotates_at (or the last half of a shorter rotation period); grace is between rotates_at and stale_at.
never_synced, no_rotation, fresh, due_soon, grace, stalePre-selected for new broadcasts from an attached sender.
Last successful update, by any channel. Null until the first one.
refreshed_at + rotation_days.
How long the list stays valid after an update. Null: the list never rotates or goes stale.
Extra days past rotates_at before the list goes stale.
Sending identities attached to the list.
rotates_at + rotation_grace_days. From then on, seed copies are skipped until the list is updated.
Who supplies and monitors the mailboxes, e.g. Warmy.
The SeedAddress object 9 fields
Mailbox provider inferred from the domain: gmail, outlook, yahoo, aol, icloud, proton or other.
active, paused, retired, conflictcontact (held), removed_by_sync, retired_by_user (retired by hand) or hard_bounce (a broadcast copy hard-bounced) — a sync never brings either of the last two back — or null.
List seed lists
Every seed list in the workspace, with its address counts and where it stands against its rotation policy.
A page of SeedList objects, under data.
Seed lists, by name. Not paginated.
The request failed validation, or a referenced record was rejected.
The tenant slug, or the record the path names, does not exist.
curl -X GET "https://api.radarsend.com/t/acme/api/seed-lists" \ -H "X-API-Key: $RADARSEND_API_KEY"
const res = await fetch('https://api.radarsend.com/t/acme/api/seed-lists', {
method: 'GET',
headers: { 'X-API-Key': process.env.RADARSEND_API_KEY },
});
const data = await res.json();{
"data": [
{
"id": "9c21895d-57f0-4a15-a1df-4dc6835d4f80",
"name": "Acme onboarding",
"vendor_label": "string",
"vendor_dashboard_url": "https://example.com",
"include_by_default": true,
"rotation_days": 0
}
],
"next_cursor": "eyJpZCI6IjljMjE4OTVkIn0",
"has_more": true
}List the addresses on a seed list
Offset-paged, ordered by address.
The seed list id, from GET /api/seed-lists.
Substring match on the address.
A page of SeedAddress objects, under data.
One page of addresses.
The request failed validation, or a referenced record was rejected.
The tenant slug, or the record the path names, does not exist.
curl -X GET "https://api.radarsend.com/t/acme/api/seed-lists/9c21895d-57f0-4a15-a1df-4dc6835d4f80/seeds" \ -H "X-API-Key: $RADARSEND_API_KEY"
const res = await fetch('https://api.radarsend.com/t/acme/api/seed-lists/9c21895d-57f0-4a15-a1df-4dc6835d4f80/seeds', {
method: 'GET',
headers: { 'X-API-Key': process.env.RADARSEND_API_KEY },
});
const data = await res.json();{
"data": [
{
"id": "9c21895d-57f0-4a15-a1df-4dc6835d4f80",
"email": "jamie@example.com",
"provider": "string",
"status": "active",
"status_reason": "string",
"retired_at": "2026-01-15T09:30:00.000Z"
}
],
"next_cursor": "eyJpZCI6IjljMjE4OTVkIn0",
"has_more": true,
"total": 0
}Replace the addresses on a seed list
Send the whole current list. Addresses not in it are retired (kept, with their history, never deleted); retired addresses that come back are reactivated, unless they were retired by hand. The natural fit for a vendor's monthly rotation.
An address that is also a contact in this workspace is held (conflict) and never sent to as a seed, and every update re-checks the seeds already on the list. An address retired by hand in the app stays retired. An update that would leave fewer than half the active and paused seeds is refused with 409 LARGE_CHANGE (the would-be result is in error.details) unless allow_large_change=true — protection against an empty or truncated file; a full rotation, every address swapped for a new one, is not a large change. Retried requests are safe: the same update applied twice leaves the addresses unchanged the second time. It still counts as an update — it restarts the rotation clock and appears in the list's history.
The seed list id, from GET /api/seed-lists.
Report what would change without writing anything.
Apply an update that would leave fewer than half the sendable seeds. Without it, such an update is refused with 409 LARGE_CHANGE.
Optional. Kept only when it is a known label; otherwise inferred from the domain.
The SeedListSync object.
What an update did — or, with dry_run=true, would do.
The request failed validation, or a referenced record was rejected.
The tenant slug, or the record the path names, does not exist.
curl -X PUT "https://api.radarsend.com/t/acme/api/seed-lists/9c21895d-57f0-4a15-a1df-4dc6835d4f80/seeds" \
-H "X-API-Key: $RADARSEND_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"seeds": [
{
"email": "jamie@example.com",
"provider": "string"
}
]
}'const res = await fetch('https://api.radarsend.com/t/acme/api/seed-lists/9c21895d-57f0-4a15-a1df-4dc6835d4f80/seeds', {
method: 'PUT',
headers: {
'X-API-Key': process.env.RADARSEND_API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"seeds": [
{
"email": "jamie@example.com",
"provider": "string"
}
]
}),
});
const data = await res.json();{
"applied": true,
"sync_id": "9c21895d-57f0-4a15-a1df-4dc6835d4f80",
"added": 0,
"reactivated": 0,
"retired": 0,
"unchanged": 0
}Add or remove addresses on a seed list
Send only what changed, such as a vendor's changed-seeds export. remove retires addresses; everything not named is left as it is. An address in both add and remove is kept.
An address that is also a contact in this workspace is held (conflict) and never sent to as a seed, and every update re-checks the seeds already on the list. An address retired by hand in the app stays retired. An update that would leave fewer than half the active and paused seeds is refused with 409 LARGE_CHANGE (the would-be result is in error.details) unless allow_large_change=true — protection against an empty or truncated file; a full rotation, every address swapped for a new one, is not a large change. Retried requests are safe: the same update applied twice leaves the addresses unchanged the second time. It still counts as an update — it restarts the rotation clock and appears in the list's history.
The seed list id, from GET /api/seed-lists.
Report what would change without writing anything.
Apply an update that would leave fewer than half the sendable seeds. Without it, such an update is refused with 409 LARGE_CHANGE.
Optional. Kept only when it is a known label; otherwise inferred from the domain.
The SeedListSync object.
What an update did — or, with dry_run=true, would do.
The request failed validation, or a referenced record was rejected.
The tenant slug, or the record the path names, does not exist.
curl -X POST "https://api.radarsend.com/t/acme/api/seed-lists/9c21895d-57f0-4a15-a1df-4dc6835d4f80/seeds/changes" \
-H "X-API-Key: $RADARSEND_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"add": [
{
"email": "jamie@example.com",
"provider": "string"
}
],
"remove": [
"string"
]
}'const res = await fetch('https://api.radarsend.com/t/acme/api/seed-lists/9c21895d-57f0-4a15-a1df-4dc6835d4f80/seeds/changes', {
method: 'POST',
headers: {
'X-API-Key': process.env.RADARSEND_API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"add": [
{
"email": "jamie@example.com",
"provider": "string"
}
],
"remove": [
"string"
]
}),
});
const data = await res.json();{
"applied": true,
"sync_id": "9c21895d-57f0-4a15-a1df-4dc6835d4f80",
"added": 0,
"reactivated": 0,
"retired": 0,
"unchanged": 0
}