Accounts
An account (also called a mailbox or sender account) is a connected email inbox used for warmup and/or campaign sending, for example a Gmail, Outlook, Zoho, Namecheap, or custom SMTP/IMAP mailbox. Every account belongs to a project and carries its own warmup status, ramp schedule, health score, and sending limits.
All endpoints below require X-Api-Key. Only connecting mailboxes (POST /accounts and POST /accounts/bulk) requires X-Project-Id; GET /accounts uses it when sent. Every /accounts/{id}/... endpoint finds the project from the account id in the URL, and answers 403 forbidden for an account in a workspace you do not belong to and 400 for an id that is not a valid UUID. See Authentication.
#The account object
Responses never include raw credentials: SMTP/IMAP passwords and OAuth tokens are encrypted at rest and stripped from the API response entirely. The object carries every stored setting of the mailbox, so it has more fields than the abridged example below (for example lastCampaignSendAt, warmupEnabled, warmupStartedAt, warmupActiveDays, campaignSendingPausedAt, slowRampEnabled, managedBy, dkimSelector and trackingDomainVerified). A typical account looks like this:
{
"id": "3a6f9e2e-4b7a-4e9a-9b1d-6e3a2f8c1a10",
"projectId": "8f14e45f-ceea-4c6a-8c8d-6b1a5b5c9c1a",
"kind": "real",
"email": "sales@yourdomain.com",
"displayName": "Alex Carter",
"provider": "custom",
"authMethod": "password",
"smtpHost": "smtp.yourdomain.com",
"smtpPort": 587,
"smtpUser": "sales@yourdomain.com",
"imapHost": "imap.yourdomain.com",
"imapPort": 993,
"imapUser": "sales@yourdomain.com",
"timezone": "UTC",
"status": "aging",
"createdAt": "2026-06-20T09:12:00.000Z",
"activatedAt": null,
"lastHealthScore": null,
"lastSendAt": null,
"consecutiveFailures": 0,
"needsReconnect": false,
"notes": null,
"dnsLastCheckedAt": null,
"dnsOverallStatus": null,
"senderFirstName": null,
"senderLastName": null,
"fromName": null,
"replyToAddress": null,
"dailyCampaignLimit": 30,
"minWaitMinutes": 10,
"trackingDomain": null,
"warmupEnabled": true,
"warmupDailyLimit": null,
"warmupStartedAt": "2026-06-20T09:12:00.000Z"
}status is one of aging, active, paused, flagged, dead. Newly connected accounts start as aging while warmup ramps up sending volume.
#List accounts
GET /accountsReturns the accounts for a single project when X-Project-Id is set. If you omit X-Project-Id, this endpoint falls back to returning every account across all projects in your active workspace (the one named in X-Workspace-Id if you belong to it, otherwise your own workspace): useful for a workspace-wide overview. Mailboxes whose hosted subscription has been cancelled are left out.
Add ?view=summary for a lighter list with only id, email, provider, status, todayQuota, lastHealthScore, needsReconnect, campaignSendingPausedAt, managedBy, warmupStartedAt and createdAt.
curl https://app.warmerly.com/api/v1/accounts \
-H "X-Api-Key: wmv_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "X-Project-Id: 8f14e45f-ceea-4c6a-8c8d-6b1a5b5c9c1a"{
"accounts": [
{
"id": "3a6f9e2e-4b7a-4e9a-9b1d-6e3a2f8c1a10",
"email": "sales@yourdomain.com",
"provider": "custom",
"status": "aging",
"todayQuota": 4,
"sentToday": 2,
"campaignSendBlocked": false
}
]
}The default view returns the full account object plus baseQuota and todayQuota (today's warmup target), sentToday, receivedToday and todayPlan (today's warmup numbers) and, when X-Project-Id is set, campaignSendBlocked (true when the campaign engine will never send a campaign from that mailbox). The example above shows only some of those fields.
#Connect an account
POST /accountsConnects a mailbox using manual SMTP/IMAP credentials. Requires X-Project-Id and a plan that includes the email channel, see the errors below. Fields you send that are not in the table are ignored.
| Field | Type | Required | Description |
|---|---|---|---|
email | string | Yes | The mailbox's email address. |
displayName | string | No | Friendly name shown in the dashboard. |
provider | string | Yes | One of gmail, outlook, zoho, namecheap, custom. |
smtp.host | string | Yes | SMTP server hostname. |
smtp.port | integer | Yes | SMTP server port. |
smtp.user | string | Yes | SMTP username. |
smtp.pass | string | Yes | SMTP password or app password. Encrypted at rest, never returned. |
imap.host | string | Yes | IMAP server hostname. |
imap.port | integer | Yes | IMAP server port. |
imap.user | string | Yes | IMAP username. |
imap.pass | string | Yes | IMAP password or app password. Encrypted at rest, never returned. |
timezone | string | No | IANA timezone for scheduling sends. Defaults to UTC. |
curl -X POST https://app.warmerly.com/api/v1/accounts \
-H "X-Api-Key: wmv_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "X-Project-Id: 8f14e45f-ceea-4c6a-8c8d-6b1a5b5c9c1a" \
-H "Content-Type: application/json" \
-d '{
"email": "sales@yourdomain.com",
"displayName": "Alex Carter",
"provider": "custom",
"smtp": { "host": "smtp.yourdomain.com", "port": 587, "user": "sales@yourdomain.com", "pass": "app-password" },
"imap": { "host": "imap.yourdomain.com", "port": 993, "user": "sales@yourdomain.com", "pass": "app-password" },
"timezone": "Europe/London"
}'Returns 201 with the created account:
{
"account": {
"id": "3a6f9e2e-4b7a-4e9a-9b1d-6e3a2f8c1a10",
"projectId": "8f14e45f-ceea-4c6a-8c8d-6b1a5b5c9c1a",
"kind": "real",
"email": "sales@yourdomain.com",
"displayName": "Alex Carter",
"provider": "custom",
"authMethod": "password",
"smtpHost": "smtp.yourdomain.com",
"smtpPort": 587,
"smtpUser": "sales@yourdomain.com",
"imapHost": "imap.yourdomain.com",
"imapPort": 993,
"imapUser": "sales@yourdomain.com",
"timezone": "Europe/London",
"status": "aging",
"warmupEnabled": true,
"warmupStartedAt": "2026-06-20T09:12:00.000Z"
}
}The response is the full account object (abridged above). On creation, Warmerly starts warmup (warmupStartedAt is set) and kicks off a DNS pre-flight check (SPF/DKIM/DMARC/MX) in the background; check dnsOverallStatus on a subsequent GET to see the result. Connecting an address that is already in the same project returns 409 conflict. SMTP or IMAP hosts that point at private or internal addresses are refused with 400 bad_request.
#Get an account
GET /accounts/{id}curl https://app.warmerly.com/api/v1/accounts/3a6f9e2e-4b7a-4e9a-9b1d-6e3a2f8c1a10 \
-H "X-Api-Key: wmv_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"{
"account": {
"id": "3a6f9e2e-4b7a-4e9a-9b1d-6e3a2f8c1a10",
"email": "sales@yourdomain.com",
"provider": "custom",
"status": "aging",
"lastHealthScore": 87,
"todayQuota": 4,
"spamPlacementScore": null
}
}Returns the full account object (abridged above) plus trackingCnameTarget, sandboxSendingBlock (a sentence, only for the free sandbox mailbox), sendingFlag, todayQuota (today's warmup target), capacityExplain (why the warmup quota is what it is), spamPlacementScore and workspaceCapOverride. Returns 404 if the account doesn't exist.
#Update an account
PATCH /accounts/{id}Updates settings on an existing account. Only send the fields you want to change. A few of the most commonly used fields:
| Field | Type | Description |
|---|---|---|
displayName | string | Friendly name shown in the dashboard. |
timezone | string | IANA timezone for scheduling sends. |
notes | string | Freeform notes shown in the dashboard. |
dailyCampaignLimit | integer (0-1000) | Max campaign emails sent per day from this account. |
minWaitMinutes | integer (0-1440) | Minimum wait between campaign emails from this account. |
slowRampEnabled | boolean | Turns the slower campaign volume ramp on or off. |
dailyInboxPlacementTestLimit | integer (0-100) | Daily limit on inbox placement tests for this account. |
warmupDailyLimit | integer (1-500) or null | Per-mailbox ceiling on warmup emails per day. null removes it. |
senderFirstName / senderLastName | string or null | Overrides the sender identity used in campaign merge fields. |
fromName | string (max 80) or null | The name recipients see in the From header, for example your company. Empty or null falls back to first and last name. Does not change {{senderFirstName}}. |
signatureHtml | string or null | Signature for outgoing campaign mail. |
replyToAddress | valid email, "" or null | Reply-to address for outgoing campaign mail. "" clears it. |
trackingDomain | string or null | A custom tracking hostname. It must be a bare hostname, and changing it resets its verification until the next DNS check. |
dkimSelector | string or null | The DKIM selector to check first in DNS checks. |
smtpUser / imapUser | valid email or null | Login identity override, for accounts connected with OAuth only (400 otherwise). |
projectId | string (UUID) | Moves the mailbox to another project, including one in another workspace. Needs owner or admin on both sides. |
These are the only fields PATCH accepts. Any other field in the body is ignored without an error, so check the returned account to confirm a change landed. On the free sandbox mailbox (managedBy: "warmerly_sandbox") dailyCampaignLimit, minWaitMinutes, slowRampEnabled and dailyInboxPlacementTestLimit are refused with 400.
curl -X PATCH https://app.warmerly.com/api/v1/accounts/3a6f9e2e-4b7a-4e9a-9b1d-6e3a2f8c1a10 \
-H "X-Api-Key: wmv_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{ "dailyCampaignLimit": 45, "notes": "Ramping faster for Q3 push" }'{
"account": {
"id": "3a6f9e2e-4b7a-4e9a-9b1d-6e3a2f8c1a10",
"dailyCampaignLimit": 45,
"notes": "Ramping faster for Q3 push"
}
}The response is the full account object (abridged above) with trackingCnameTarget added.
#Disconnect an account
DELETE /accounts/{id}Permanently disconnects and removes the account, including its warmup history. For a Warmerly-hosted mailbox it also suspends the mail account on Warmerly's mail server. An optional JSON body can carry reason and note (strings), which are recorded for the audit log.
curl -X DELETE https://app.warmerly.com/api/v1/accounts/3a6f9e2e-4b7a-4e9a-9b1d-6e3a2f8c1a10 \
-H "X-Api-Key: wmv_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"{ "ok": true }Returns 404 if the account doesn't exist.
#Connect several accounts at once
POST /accounts/bulkRequires X-Project-Id and a plan that includes the email channel (403 channel_not_included otherwise). Takes { "accounts": [...] }, where each item has email, provider (gmail | outlook | zoho | namecheap | custom), smtp and imap objects, and optional displayName and timezone (default UTC), the same fields as POST /accounts. SMTP or IMAP hosts that point at private or internal addresses refuse the whole batch with 400 bad_request.
Capacity is all-or-nothing: if the batch would breach the plan's mailbox limit the whole request is refused with 402 plan_capacity rather than importing the first few. A billing-locked workspace is refused with 402 billing_locked. Past that gate each account is inserted independently, so one bad row does not lose the others:
{
"results": [
{ "index": 0, "email": "a@yourdomain.com", "ok": true, "id": "3a6f9e2e-4b7a-4e9a-9b1d-6e3a2f8c1a10" },
{ "index": 1, "email": "b@yourdomain.com", "ok": false, "error": "duplicate key value violates unique constraint" }
]
}A failed row carries the database's error text in error, so treat it as debugging context, not something to parse. Each connected mailbox starts with status: "aging" and warmup enabled (warmupStartedAt is set). Unlike POST /accounts, the bulk route does not start the DNS pre-flight check itself.
#Check settings before you connect
POST /accounts/detect
POST /accounts/test-connectiondetect takes { "email": "you@yourdomain.com" } (3 to 320 characters) and returns { "detection": { … } }: Warmerly's best guess at the provider, from the domain's live MX records, with the SMTP/IMAP hosts and ports the dashboard's connect wizard would prefill. A domain it cannot place comes back as an unsupported kind with a human-readable note rather than an error.
test-connection takes full smtp and imap objects (host, port from 1 to 65535, user, pass, all required) and reports whether each side authenticated, without saving anything. Use it to surface a credential problem before creating an account that would immediately pause. Hosts that point at private or internal addresses are refused with 400 bad_request. On a failure, message is a plain-language reason; on success it is omitted.
{ "smtp": { "ok": true }, "imap": { "ok": false, "message": "Invalid credentials" } }#Domain health (records + blocklists in one call)
GET /accounts/{id}/domain-health
POST /accounts/{id}/domain-healthThe single call behind the domain-health card in the dashboard, and the one to reach for first: it returns the record checks and the blocklist checks for the sending domain and its sending IP together, with per-record advisories rather than a bare pass/fail. GET reads the latest stored results; it does not run a new check. Any of dns, domainBlocklist and ipBlocklist is null when there is no stored result for it yet.
{
"domain": "yourdomain.com",
"providerManaged": false,
"dns": {
"spfStatus": "pass",
"dkimStatus": "none",
"dmarcStatus": "pass",
"mxStatus": "pass",
"findings": [{ "record": "dkim", "severity": "warn", "title": "No DKIM record found" }],
"checkedAt": "2026-09-12T08:14:00.000Z"
},
"domainBlocklist": { "subject": "yourdomain.com", "status": "clean", "listings": [], "zonesQueried": ["dbl.spamhaus.org"], "zonesErrored": [], "checkedAt": "2026-09-12T08:14:00.000Z" },
"ipBlocklist": { "subject": "203.0.113.10", "via": "smtp.yourprovider.com", "status": "clean", "listings": [], "zonesQueried": [], "zonesErrored": [], "checkedAt": "2026-09-12T08:14:00.000Z" },
"ipSkippedReason": null
}| Field | Description |
|---|---|
providerManaged | true for gmail.com, outlook.com and the like: the records belong to the provider, so a DKIM reading of them is unreliable and nothing here is your responsibility to fix. |
dns.findings | Advisories beyond presence, SPF's all qualifier and its 10-lookup budget, DKIM key length and test mode, DMARC policy/pct/rua. |
domainBlocklist / ipBlocklist | Listings on public blocklists, with the zones actually queried and any that errored, so a partial answer is visible as partial. |
ipSkippedReason | Why there is no IP section (a provider-shared host, an unresolvable SMTP host). A hole with no reason reads as something silently broken. |
POST re-runs the DNS check and returns the same payload. It is rate-limited internally: a blocklist re-check inside the minimum interval (6 hours) reuses the stored result rather than re-querying third-party blocklist zones, so holding down a refresh button cannot multiply Warmerly's query volume across them.
The two endpoints below remain, and are the narrower views of the same data.
#DNS and domain checks
GET /accounts/{id}/dns
POST /accounts/{id}/dnsGET returns the last 10 DNS checks for the account, newest first, plus latest as a convenience (the first item of history, or null). POST re-runs the check now and returns { "result": { … } }, or 400 with the error text if the check could not run.
{
"latest": {
"id": "b1e7c2a4-0c3e-4c0a-9a6f-2b7d8e5f1a33",
"accountId": "3a6f9e2e-4b7a-4e9a-9b1d-6e3a2f8c1a10",
"domain": "yourdomain.com",
"checkedAt": "2026-09-11T08:14:00.000Z",
"spfStatus": "pass",
"spfRecord": "v=spf1 include:_spf.google.com ~all",
"dkimStatus": "none",
"dkimSelector": null,
"dkimRecord": null,
"dmarcStatus": "pass",
"dmarcRecord": "v=DMARC1; p=none; rua=mailto:dmarc@yourdomain.com",
"mxStatus": "pass",
"mxRecords": ["aspmx.l.google.com"],
"findings": [],
"overallStatus": "warn"
},
"history": [ { "id": "b1e7c2a4-0c3e-4c0a-9a6f-2b7d8e5f1a33", "…": "same shape as latest" } ]
}Each record status (SPF, DKIM, DMARC and MX) is pass, none, fail or error; overallStatus is pass, warn or fail. mxStatus is null on older checks. Two things to know before you treat a result as a verdict:
errormeans DNS did not answer (timeout or resolver problem), not that the record is wrong. Re-check rather than re-publishing records.dkimStatus: "none"can mean "present but under a selector Warmerly could not guess", the check tries a list of common selector names and cannot discover an arbitrary one. SetdkimSelectoron the account (see Update an account) and re-check.
SPF, DKIM, DMARC and MX are checked here, and if the account has a tracking domain its CNAME is re-verified on the same run. Everything each record does, and the order to publish them in, is in the DNS records checklist.
#Placement tests
GET /accounts/{id}/placement
POST /accounts/{id}/placementGET lists this account's 10 most recent placement tests, newest first, with a summary:
{
"tests": [
{
"id": "6d2f0b1a-9c4e-4f77-bb31-2a9e7c4d8e55",
"accountId": "3a6f9e2e-4b7a-4e9a-9b1d-6e3a2f8c1a10",
"startedAt": "2026-09-10T09:00:00.000Z",
"completedAt": "2026-09-10T09:01:04.000Z",
"status": "done",
"score": 82,
"details": { }
}
],
"summary": {
"latestScore": 82,
"latestStatus": "done",
"latestStartedAt": "2026-09-10T09:00:00.000Z",
"latestDegraded": false,
"trendDelta": 6
}
}status is pending, running, done or failed. trendDelta is the score change against the previous comparable test, or null when there is nothing fair to compare with. latestDegraded is true when the latest test was measured against Warmerly's own warmup mailboxes rather than real seed inboxes. Its score is not a placement result and is not comparable with a clean one. Tests recorded before this flag existed also read as degraded.
POST sends live email and spends quota. It dispatches probe messages from this mailbox to seed addresses and debits one of your monthly placement tests (counted per user, as in Usage & limits). Out of allowance returns 402 with error.code quota_exhausted and details carrying used, limit, upgradeUrl and, when credits can cover it, a topUp offer. The charge is taken before the run and handed back if the run fails, which returns 400 bad_request. The response is { "test": { … } }. The call waits at least 30 seconds for delivery before responding, so expect it to take that long or more.
#Blocklist status
GET /accounts/{id}/blocklist
POST /accounts/{id}/blocklistWhether the account's sending domain appears on public DNS blocklists. GET returns the last 10 checks; POST runs one now, and returns a recent result with cached: true rather than re-querying the zones if one was taken moments ago.
{ "domain": "yourdomain.com", "applicable": true, "latest": null, "history": [] }applicable: false means the domain belongs to a free consumer provider (gmail.com and friends), which is never checked. A shared provider's reputation is not yours to read.
#Activity and warmup history
GET /accounts/{id}/stats
GET /accounts/{id}/events
GET /accounts/{id}/log
GET /accounts/{id}/warmup-jobsstats is today-and-7-day counters for one mailbox. "Today" is the UTC day:
{ "sentToday": 24, "pendingToday": 6, "inboxToday": 22, "spamToday": 2, "openRate": 0.415, "replyRate": 0.123, "todayPlan": null, "firstWarmupSend": null }openRate and replyRate here are warmup-network rates over 7 days, returned as fractions between 0 and 1 (not percentages), not campaign performance. The two are different metrics with similar names, explained in How warmup works. Either can be null when there is nothing to divide by. todayPlan is the mailbox's warmup plan for its local day and firstWarmupSend describes the first warmup email during the first 7 days after warmup starts (null afterwards).
events returns up to 200 lifecycle events, newest first, as { "events": [...] } with { id, accountId, type, payload, createdAt } each. type is one of smtp_fail, imap_fail, flagged, auto_paused, auto_resumed, manual_pause, aged_in, marked_dead, oauth_refresh_fail, oauth_connected and oauth_reconnected.
log pages through the individual warmup messages this mailbox sent, newest first, as { "jobs": [...], "nextCursor": "..." }: ?limit= (1-100, default 50) and ?cursor= (pass the previous response's nextCursor, a timestamp). nextCursor is null only when a page comes back empty, so keep paging until jobs is empty.
warmup-jobs returns the 100 most recent warmup messages this mailbox sent or received, newest first by scheduled time, as { "jobs": [...], "dailySummary": [...] }, with no paging.
#Pause, resume and warmup
POST /accounts/{id}/pause
POST /accounts/{id}/resume
POST /accounts/{id}/warmup/toggle
POST /accounts/{id}/send-test
POST /accounts/{id}/oauth/reconnectpause sets the mailbox's status to paused and resume sets it back to active; both return { "ok": true }. resume also clears a campaign-sending pause. If the mailbox is flagged as needing a reconnect, resume first tests the stored login and answers 409 with code reconnect_required when it fails. Resuming a dead or flagged mailbox can return 402 plan_capacity when the workspace is at its mailbox limit.
warmup/toggle takes { "enabled": true | false } (required) and is the supported way to start or stop warmup for one mailbox; it returns { "account": { … } }. Enabling it for the first time also stamps the warmup start date the ramp is measured from.
The free mailbox every new account is given (managedBy: "warmerly_sandbox") keeps warming for as long as you have it: pause, and warmup/toggle with { "enabled": false }, answer 409 with code sandbox_warmup_locked for it. Delete it (DELETE /accounts/{id}) if you no longer want it.
send-test takes { "to": "you@example.com" } (a valid email) and sends one real message through this mailbox, with a fixed subject and body, the fastest way to prove SMTP works end to end. It returns { "ok": true }. A failed send returns 500 with { "error": { "message": ... } } where message is smtp_auth_failed, smtp_timeout, smtp_connection_failed or send_failed (this response has no error.code).
oauth/reconnect is for mailboxes connected with Google or Microsoft sign-in. It returns { "auth_url": "..." }, a consent URL to open in a browser; completing it reconnects the mailbox (for example a Microsoft 365 mailbox that authenticates but fails to send, see Troubleshooting). It returns 400 for a mailbox that was not connected with OAuth.
#Channel account limits
GET /accounts/limitsNo X-Project-Id; the OneMail part follows your active workspace (X-Workspace-Id). Reports connected-vs-included counts for the per-account channels (LinkedIn and WhatsApp, counted for your user) with an overage price in USD, plus the OneMail hosted-mailbox add-on: its current quantity, per-mailbox price in minor units, the tier discount, and the full price ladder.
{
"limits": {
"linkedin": { "used": 1, "included": 0, "overageUsd": 19 },
"whatsapp": { "used": 0, "included": 2, "planIncluded": 2, "slots": 0, "overageUsd": 6 },
"onemail": { "used": 4, "included": null, "unitAmountMinor": 199, "currency": "usd", "billableQuantity": 4, "recurringAmountMinor": 796, "tier": "growth", "discountPercent": 33 }
}
}whatsapp.included is the whole ceiling: planIncluded from the plan plus slots bought on top. linkedin.overageUsd and whatsapp.overageUsd are the USD price of one more slot, the same figure the slot checkout uses; they are always in USD, whatever currency your plan bills in. The onemail object has more fields than shown: packSlots, packSlotsFree, minimumQuantity, tierPrices and upgrade.
included: null on onemail is not a missing value: hosted mailboxes have no cap at all, they are billed per unit and never consume a plan mailbox slot, so never render that one as a progress bar. For monthly allowances and plan capacity see Usage & limits.
#OAuth-connected accounts
Outlook.com and Microsoft 365 accounts can also be connected via OAuth instead of raw SMTP/IMAP credentials. That is a browser sign-in flow built for the dashboard's Add mailbox → Microsoft wizard, and it is not part of this reference. Gmail and Google Workspace connect with SMTP/IMAP and a Google app password (smtp.gmail.com:465, imap.gmail.com:993); mailboxes connected with Google OAuth before 2026-09-15 keep working. Once connected (by either method), the resulting account is fully manageable through this API.
#Errors
Attempting to connect an account on a plan without the email channel returns 403:
{
"error": {
"code": "channel_not_included",
"message": "Your plan does not include email features. Upgrade at /pricing.",
"details": { "upgradeUrl": "/pricing" }
}
}An invalid request body (e.g. malformed smtp/imap object) returns 400:
{ "error": { "code": "bad_request", "message": "invalid_body", "details": { /* zod field errors */ } } }Connecting beyond your plan's mailbox limit returns 402 with error.code plan_capacity, and a billing-locked workspace returns 402 billing_locked. A missing account on GET, PATCH, or DELETE returns 404:
{ "error": { "code": "not_found", "message": "not_found", "details": null } }Each part of this reference has its own page (15)
- The account object
- List accounts
- Connect an account
- Get an account
- Update an account
- Disconnect an account
- Connect several accounts at once
- Check settings before you connect
- Domain health (records + blocklists in one call)
- DNS and domain checks
- Placement tests
- Blocklist status
- Activity and warmup history
- Pause, resume and warmup
- OAuth-connected accounts