Mailboxes
Connect mailboxes without handling passwords, buy domains and mailboxes, warm them up, and manage them.
A mailbox is the email counterpart of a sender: the address a campaign's email steps send from, and where replies land. There are two ways to get one:
- Connect a mailbox someone already has, through a hosted connect link or in the app.
- Buy domains and mailboxes through Swarmhit, over the API or on a hosted link. Bought mailboxes arrive connected, with no sign-in, and warm up before campaigns use them.
Mailboxes take no seat: a seat covers one LinkedIn sender, and a workspace on a paid plan connects as many mailboxes as it needs. A workspace inside an organization draws its plan from the organization. The email channel has to be enabled for the workspace: until it is, reads still answer, but creating a hosted link and pausing, resuming, removing, re-checking or testing a mailbox return 403. Credentials are never returned by any endpoint.
With an organization key, set X-Swarmhit-Workspace to choose the workspace a mailbox lands in or an order is placed for (see Organization).
Hosted connect links
POST /email-accounts/hosted-link is how the API connects a mailbox without ever handling its password. It works like the LinkedIn hosted link: you mint a one-time URL, send the person to it, and they connect on a page Swarmhit serves in your organization's name and logo. providers says what the page offers; the person picks one when there are several.
providers value | What the page offers |
|---|---|
google | Sign in with Google (Gmail and Google Workspace). |
google_app_password | A Google address and an app password. |
microsoft | Sign in with Microsoft (Outlook.com, Hotmail and Microsoft 365). |
imap | Any other mailbox: its address, password, and IMAP and SMTP servers. The page fills in the servers it can find for the address. |
buy_mailboxes | Buying new domains and mailboxes on the page. Needs purchase, see below. |
curl -X POST https://app.swarmhit.com/api/v1/email-accounts/hosted-link \
-H "Authorization: Bearer swh_live_..." \
-H "X-Swarmhit-Workspace: wSp042" \
-H "Content-Type: application/json" \
-d '{
"providers": ["google", "microsoft", "imap"],
"redirectUrl": "https://yourapp.com/settings/email/done",
"externalId": "your-user-42"
}'{
"data": {
"id": "hLk789",
"status": "pending",
"channel": "email",
"provider": null,
"providers": ["google", "microsoft", "imap"],
"workspaceId": "wSp042",
"accountId": null,
"orderId": null,
"purchase": null,
"externalId": "your-user-42",
"redirectUrl": "https://yourapp.com/settings/email/done",
"url": "https://app.swarmhit.com/connect/Qm9Kx...",
"expiresAt": "2026-10-08T10:30:00.000Z"
}
}provider is the one-value form of providers; send one or the other, not both. The rest works as on LinkedIn links: url is returned once, here; the link expires after 30 minutes by default (expiresIn, in seconds, between 300 and 604800); and redirectUrl may be left out when your organization has a default return URL (400 with code: invalid-redirect-url when there is neither).
The link is checked when you create it, so problems surface here rather than at the end of the person's visit:
400withcode: no-planwhen the workspace has no paid plan,code: invalid-providerfor an unknown or missing provider.403when the email channel is not enabled for the workspace.409withcode: provider-unavailablewhen a provider the link names is not available yet.
Buying on the page
A link offering buy_mailboxes lets the person buy new domains and mailboxes themselves. They search for domains, choose Google Workspace or Microsoft 365 for each, and name the mailboxes. The page shows no prices: you pay.
purchase.maxMailboxes(1 to 100) caps how many mailboxes the person can buy through the link.purchaseis required withbuy_mailboxesand refused without it (400,code: invalid-purchase).purchase.contactsets the registrant the domains are registered to, with the same fields as an order'scontact. Set it and the page does not ask the person for it.- Domains bought on the page are registered for one year, and their mailboxes warm up with the
standardstrategy. - The order is charged to the card on file of the workspace that pays: the organization, for a workspace inside one. It is placed on behalf of the API key's creator, who needs billing rights there.
These are checked when the link is created: 403 with code: buying-off when buying mailboxes is not enabled for the workspace, 403 with code: not-allowed when the key's creator has no billing rights, and 409 with code: no-payment-method when there is no card on file.
Once the person buys, the link is done: its status becomes ordered and orderId names the order. Follow the order like any other (below); mailbox_order.completed and each new mailbox's account.connected carry the link's hostedLinkId and externalId.
Reconnecting through a link
Pass accountId and the link repairs that mailbox instead of adding one: it keeps its id, its campaigns and its settings. A reconnect link offers only the mailbox's own provider, so providers can be left out (any other value is a 400 with code: invalid-provider). A mailbox that signs in with Google or Microsoft must sign in again as the same address; a password mailbox keeps its address and servers and takes the new password.
Bought mailboxes never need reconnecting, and a link for one is refused with 409 and code: managed-mailbox. An accountId that is not a mailbox of the workspace returns 404.
Knowing how it went
- The redirect. The person comes back to
redirectUrlwith?hosted_link_id=…&status=connected|ordered|failed|expired|cancelled&account_id=…&order_id=…&external_id=….account_idis the mailbox id;order_idis set after a purchase. - Webhooks.
account.connected(withdata.channel: "email") andaccount.connection_failedcarryhostedLinkIdandexternalId. - Polling.
GET /email-accounts/hosted-link/{id}returns the link'sstatus(pending,connected,ordered,failedorexpired), theaccountIdororderIdit produced, and anerrorwhen it failed.
A failed attempt, such as a wrong password, fires account.connection_failed and leaves the link open so the person can try again, a limited number of times. Only cancelling on the page (the link becomes failed with error.code: cancelled) or expiry ends it without a mailbox.
Connecting in the app
Mailboxes can also be connected in the app, under Accounts → Email: Google (sign-in or an app password), Outlook and Microsoft 365 (sign-in), or any other provider over IMAP/SMTP. They then show up in the API like any other.
Managing mailboxes
GET /email-accounts lists the workspace's mailboxes, newest first, and GET /email-accounts/{id} returns one. Each carries:
status:pendingwhile it connects,active,errorwhen its sign-in broke (reconnect it through a link),suspended, ordisconnectedonce it is removed.provider(google,microsoftorimap),authType(oauthfor a mailbox signed in with its provider,passwordotherwise) andconnectedVia(app,hosted_link, ormanagedfor a bought mailbox).- The pause state, daily
limitsand today'susage, the tracking settingstrackOpensandtrackClicks, and lifetimecounters(sent,bounced,complained,opened,clicked). Tracking is set in the app, in the mailbox settings. dnsHealth: the sending domain's SPF, DKIM and DMARC records, eachok,missing,invalid,weakorunknown, re-read daily.managedandwarmupon a bought mailbox (bothnullon a mailbox you connected).
curl https://app.swarmhit.com/api/v1/email-accounts \
-H "Authorization: Bearer swh_live_..."POST /email-accounts/{id}/pauseand.../resumework like the sender pair: campaigns stop emailing from a paused mailbox, its leads stay assigned, and both emitaccount.paused/account.resumedwithchannel: "email".DELETE /email-accounts/{id}removes the mailbox and its threads, takes it out of every campaign pool and moves the leads it was emailing to the remaining mailboxes. Connecting the same address again within the restore window (15 days by default) brings back its campaigns, leads and settings, under a new id withrestoredFromset. A bought mailbox is never removed this way (409,code: managed-mailbox): cancel it instead.POST /email-accounts/{id}/check-dnsre-reads the domain's records now, after you change DNS. See Email deliverability for what each record does.POST /email-accounts/{id}/deliverability-testsends one email to our test inbox; the mailbox'sdeliverabilityTestthen reports where it landed and what the receiving server saw.GET /email-accounts/{id}/statsreports emails sent, replies and bounces over 7 to 90 days (days, default 30), plus opens and clicks for tracked emails, with the per-campaign split.
A lead whose address bounced hard or reported spam carries emailStatus (bounced / complained) and stops at any email step it reaches from then on; see Email deliverability.
Buying domains and mailboxes
Swarmhit registers the domains, creates Google Workspace or Microsoft 365 mailboxes on them with their DNS records, and connects them to the workspace: nobody signs in, and they never need reconnecting. Buying needs the managed mailboxes feature on the workspace, and the API key's creator needs billing rights in the workspace that pays. Reading orders, domains and billing never needs the feature.
1. Find domains
GET /domains/search takes a keyword (a word, or one exact domain) and optional tlds (comma separated, e.g. .com,.org) and years:
curl "https://app.swarmhit.com/api/v1/domains/search?keyword=getacme&tlds=.com,.io" \
-H "Authorization: Bearer swh_live_..."Each result says whether it is available, whether Google Workspace and Microsoft 365 can host it (platforms), and the registrar's first-year price (priceCents). offered: false means it cannot be bought here: an ending we do not sell, or a first year above our price cap. The quote has the prices you actually pay. A key may search 15 times a minute (429, code: rate-limited).
2. Get a quote
POST /mailbox-orders/quote prices an order and charges nothing:
curl -X POST https://app.swarmhit.com/api/v1/mailbox-orders/quote \
-H "Authorization: Bearer swh_live_..." \
-H "Content-Type: application/json" \
-d '{
"domains": [{
"name": "getacme.com",
"platform": "google",
"years": 1,
"redirectUrl": "https://acme.com",
"mailboxes": [
{ "username": "jane", "firstName": "Jane", "lastName": "Doe" },
{ "username": "jane.doe", "firstName": "Jane", "lastName": "Doe" }
]
}],
"contact": {
"firstName": "Jane", "lastName": "Doe", "email": "jane@acme.com", "phone": "+14155550142",
"addressLine1": "1 Market St", "city": "San Francisco", "state": "CA", "country": "US", "postalCode": "94105"
},
"warmup": { "enabled": true, "strategy": "standard" }
}'- An order holds 1 to 20 domains, and each domain 1 to 5 mailboxes. A new domain needs its
platform(googleormicrosoft) and aredirectUrl: your ownhttps://website, where visitors of the domain are sent.yearsis 1 to 10 (default 1). Each mailbox needs ausername(the part before @),firstNameandlastName, and may take apictureUrl(https://). contactis the registrant of the new domains. It is required when the order registers a domain, and never returned by the API.warmupis on by default with thestandardstrategy; see Warmup.- To add mailboxes to a domain you already bought, send
{ "name": "getacme.com", "existing": true, "mailboxes": [...] }: no domain is charged, and they are usually ready within minutes.GET /managed-domainssays how many each domain can still take.
The quote returns a quoteId valid for 30 minutes, the lines charged, dueNowCents (the domains and the first month, charged when you buy) and monthlyCents (charged every month after, while the mailboxes run). Domains that can no longer be registered are listed in unavailable, and addresses already taken on a domain you own in unavailableMailboxes: remove or rename them and quote again. A workspace may quote 6 times a minute (429, code: rate-limited).
Validation errors are a 400 with code: invalid-order and details.errors ([{ path, message }]). For existing domains: 404 with code: domain-not-owned, and 409 with code: domain-full (details.slotsLeft) or domain-admin-cancelled. 403 with code: feature-disabled when buying is not enabled for the workspace, or not-allowed without billing rights. 503 with code: quote-unavailable when prices cannot be read right now: retry.
3. Buy
POST /mailbox-orders with the quoteId charges dueNowCents to the card on file of the paying workspace (the organization, for a workspace inside one) and starts the order:
curl -X POST https://app.swarmhit.com/api/v1/mailbox-orders \
-H "Authorization: Bearer swh_live_..." \
-H "Idempotency-Key: 6c1e0f1a-buy-getacme" \
-H "Content-Type: application/json" \
-d '{ "quoteId": "qTe901" }'Buying the same quote twice returns the same order without a second charge. Order fields are optional here; when sent, they must be exactly what was quoted (409, code: quote-mismatch).
| Status | code | What to do |
|---|---|---|
402 | no-payment-method, payment-failed | Add or fix the card in Billing, then buy again. |
409 | quote-expired, price-changed, domain-unavailable, mailbox-unavailable | Quote again. |
409 | payment-pending | The charge is still being confirmed: do not buy again. The order shows up in GET /mailbox-orders within minutes if it went through. |
409 | purchase-in-progress | Another call is buying this quote right now. |
503 | temporarily-unavailable | Retry later. |
Following an order
GET /mailbox-orders/{id} returns the order with every domain and mailbox; GET /mailbox-orders lists the workspace's orders, newest first (optional status).
An order moves paid → placing → placed → provisioning → authorizing → connecting → completed, usually within a few hours. needs_attention means it is delayed and our team has been alerted: they resume it, or cancel it. cancelled means it was stopped and refunded. delayed: true flags an order that is held up, including one still running while a mailbox is stuck in setup. Treat a status you do not recognise as in progress.
Each mailbox has a step (ordered, provisioning, authorizing, connecting, connected, failed or refused) and, once connected, its accountId. A domain that could not be registered is refused (with refusedReason) and is refunded, along with its mailboxes.
You do not have to poll: mailbox_order.completed fires when the order is done and mailbox_order.failed when it needs attention or is cancelled. Each mailbox emits account.connected as it connects (data.channel: "email", and connectedVia: "managed" on the mailbox). See Webhooks.
Warmup
A new mailbox on a new domain has no sending reputation. Warmup builds one: the mailbox exchanges a growing number of emails a day with a warmup network that opens them, replies to them and rescues them from spam. Warmup is for bought mailboxes; it is on by default for every order, and its endpoints return 409 with code: not-managed for a mailbox you connected yourself.
The hold
Campaigns do not send from a warming mailbox until it is ready. The mailbox's warmup object says why it is held:
holdReason: "warming"while warmup starts and for the first 14 days after it does (untilholdUntil).holdReason: "health"after that, for as long as its warmup health iswarningorcritical.
When the hold lifts, warmup.ready fires and campaigns that include the mailbox start assigning leads to it right away. To send before warmup is done, POST /email-accounts/{id}/warmup/hold-override with { "on": true }; { "on": false } holds it again. A paused or stopped warmup never holds a mailbox.
Health
GET /email-accounts/{id}/warmup returns the warmup status (pending while it starts, active, paused, cancelled, past_due or error), the warmup day, the current and target daily volume, and its health (excellent, good, warning, critical, or unknown until there is enough data), with healthScore and inboxRate. GET .../warmup/stats returns the daily series (days, 1 to 365, default 30).
If health turns critical after the hold, Swarmhit pauses the mailbox for campaigns (pausedReason: "warmup_health") while warmup carries on, and resumes it on its own once health is back to good or excellent. warmup.health_changed and warmup.status_changed report each change.
Strategy
A strategy sets the daily volume (start, increase per day, target) and the share of warmup emails the network replies to, rescues from promotions and rescues from spam. Pick a preset, or send your own values:
| Preset | Start | Increase per day | Target |
|---|---|---|---|
conservative | 5 | 2 | 30 |
standard (default) | 10 | 3 | 40 |
aggressive | 15 | 5 | 60 |
curl -X PATCH https://app.swarmhit.com/api/v1/email-accounts/eMa123/warmup \
-H "Authorization: Bearer swh_live_..." \
-H "Content-Type: application/json" \
-d '{ "strategy": { "preset": "standard", "targetVolume": 35 } }'PATCH /email-accounts/{id}/warmup takes a preset name or an object: a preset fills the fields you leave out, and without one every field is required. startingVolume and targetVolume are 1 to 500 and dailyIncrease 1 to 50; the target can be at most limits.maxTarget (in every warmup endpoint's response), what the mailbox's daily email limit leaves for warmup. The starting volume only applies on the first day and cannot change after it (409, code: starting-volume-locked). Invalid values are a 400 with code: invalid-strategy and details.errors. A strategy changed before warmup starts is applied as soon as it does.
Pausing, stopping and restarting
.../warmup/pauseand.../warmup/resumepause and resume a running warmup. A warmup paused because a payment failed resumes only once it is paid (409,code: warmup-billing-paused)..../warmup/stopends warmup for good; campaigns may use the mailbox right away..../warmup/startstarts warmup again on a bought mailbox without one, once a month at most (429,code: warmup-restart-limit). A mailbox that already finished its hold is not held again.
Starting and stopping warmup need billing rights.
Managed domains
GET /managed-domains lists the domains the workspace bought. Each holds up to 5 mailboxes, and each entry says how many run on it (live), how many are on their way (pending), how many more it can take (slotsLeft), and whether a mailbox can be added (canAdd, with a reason when not: full, admin-cancelled, not-active or removed). adminEmail is the domain's admin mailbox, and takenEmails the addresses a new mailbox cannot reuse.
Domains renew every year. The renewal is charged to the card about 30 days before the domain expires; a domain with no running mailbox is not renewed and lapses. A renewal that cannot be charged fires mailbox_billing.payment_failed (with a payUrl); a domain that lapses unpaid takes its mailboxes with it.
Cancelling a bought mailbox
POST /email-accounts/{id}/cancel-managed cancels a bought mailbox: it keeps working until its renewal date (cancelAt), then it is removed and no longer billed. Its warmup stops at once. Cancelling needs billing rights (403, code: not-allowed), and a mailbox you connected yourself returns 409 with code: not-managed.
Each domain has one admin mailbox (managed.isAdmin on the mailbox, adminEmail on the domain). Once it is cancelled, no mailbox can ever be added to that domain again, so while other mailboxes still run there, cancelling it needs { "confirmAdmin": true } (409, code: admin-mailbox otherwise).
Billing
Bought mailboxes and domains are billed apart from the plan, to the card of the workspace that pays (the organization, for a workspace inside one), including purchases made on hosted links. Each purchase is charged when it is bought (the domains and the first month), then monthly from that date; each domain renews yearly.
GET /mailbox-billing returns the monthly total and next charge date, the card charged, each purchase with its status, a payUrl when a payment failed and the last receipt, and each domain's renewal. It needs billing rights.
When a monthly payment fails, mailbox_billing.payment_failed fires with a payUrl. A day later the purchase's warmup pauses, and after 14 days unpaid its mailboxes are cancelled. mailbox_billing.payment_recovered fires once it is paid.
Reference
Mailbox hosted link
A one-time page where a person connects a mailbox, or buys new ones, without you handling a password.
List mailboxes
Status, pause state, daily limits, DNS health and counters for every mailbox.
Search domains
Domains to buy for sending, with availability and which platforms can host them.
Price an order
What an order of domains and mailboxes costs now and every month, as a quote to buy.
Buy domains and mailboxes
Charge the card for a quote and start the order.
Get a mailbox's warmup
Status, health, daily volume and the hold that keeps a warming mailbox out of campaigns.
List bought domains
Each domain's free slots and why a mailbox cannot be added.
Mailbox billing
What you pay for bought mailboxes and domains, and what is due.