Set up branded lookalike domains and mailboxes; start warmup.
Changed onDomain purchase + DNS + mailbox setup + warmup run BEFORE the response, not in the background — a large request can take a while to answer. Returns 202 for every call that sets up, finished or not: a provisioning field names the state when work is still owed, and a 202 without it means the call finished (200 is returned only for a quoteOnly: true preview, which sets up nothing); poll GET /infrastructure-status or re-call this endpoint to progress a provisioning outcome. In demo/free plans this runs entirely against test mode — no real domain purchase or mailbox setup occurs.
domains covers ordinals 0..domains-1; each ordinal fills to its own mailbox count via inboxesEach (uniform) or distribution (per-ordinal). This is the infrastructure you want to HAVE, not an amount to add — a repeat call at the same domains sets up nothing new once every ordinal is satisfied, so reaching ordinal 1 needs domains: 2, not a second domains: 1 call; raising inboxesEach/distribution tops existing domains up to the new per-domain count. Mailbox addresses are DETERMINISTIC — derived from persona + ordinal + slot — so keep persona unchanged across resumes and retries.
Retry contract: repeating a call NEVER buys a second time, whatever you do with the Idempotency-Key — resend the same one, send a different one, or send none at all. The key governs response replay only (a replay of a completed keyed call returns that call's recorded result without re-running it); it has no bearing on what is purchased. This is a change from earlier behavior, in which a NEW key opened a second purchase — retrying with a fresh key bought a second lookalike domain and a duplicate set of billable mailboxes.
registerDomains (real domain purchases on the platform's own account — the customer's bill is unchanged, mailbox-count-based only): omitting it leaves any previously-given consent UNCHANGED; true opts in (registrant required only when none is already on file — see Registrant); an explicit false revokes it. There is no default. A buy-bearing call that omits it (or sends false) is refused before any spend: 400 registrar_optin_missing once this account has consented before ("registerDomains was not set on this request" — set it only after the account owner has approved the quoted purchase), or 503 registrar_unarmed if domain registration is not enabled for the platform at all. A test-mode account needs neither registerDomains nor registrant: they apply only to a real domain purchase.
If fewer available, not-already-owned lookalike domains exist than the call still has to BUY, it fails with 400 naming how many were found — never a silent partial setup or a repeat purchase of one domain. A call that needs to buy nothing (a pure retry) does not need any candidate to be available and cannot fail this way.
A big order in a paying, monthly-billed account's first billing month can be asked up to two questions, each only when the quoteOnly: true preview shows it: billing.domainEnding (a call naming more than 10 mailboxes: its new domains end in .co; send dotComDomains: true to keep .com for the one-time fee it shows per domain, added to the next bill) and billing.prepay (an order making more than 4 new domains in your first billing month: month 2 is paid up front with the order; send prepaySecondMonth: true to accept it, otherwise the call is refused 400 prepay_required before anything is bought). Ask the account owner before sending either. On an order whose preview shows neither, both fields do nothing.
A domain's DNS setup may still be completing when this call returns — the domain is recorded either way and is never lost. There is no autonomous background retry: completing it is the caller's job. Repeat the same call to converge onto that domain and finish its DNS setup. There is no per-domain DNS field to poll: GET /infrastructure-status reports a domain count, not per-domain detail, but its nextSteps names the account's own next action.
Request
- Base URL: https://api.coldrig.dev
- URL: https://api.coldrig.dev/setup-infrastructure
- Auth: HTTP bearer
Headers
Optional, and strongly recommended on every mutating call. Resend the SAME key on retry: the first call runs, a replay with the same key returns the recorded result without re-executing — no duplicate campaign, no duplicate send, no second release of mailboxes. Honored on POST /campaigns, /setup-infrastructure, /remove-mailboxes and /threads/{id}/reply.
Only a FINISHED outcome replays. A call that returned while still owing work — a 202 that is still setup, or a /remove-mailboxes response whose failedCount is above zero because the provider refused a mailbox — is not recorded, so resending its key RE-RUNS the request and finishes the job instead of handing back the partial. That is what makes "retry with the same key" a true instruction rather than a guaranteed no-op; the response body always says which case you are in.
It is a REPLAY key, never a request discriminator: on /setup-infrastructure, changing it or omitting it does not cause anything extra to be set up. On /remove-mailboxes it is the only thing that makes a retry safe, because count is relative and releasing mailboxes cannot be undone through this API: the first call under a key records the exact mailboxes it resolved, so a same-key retry finishes that set and can never release one outside it, whatever count the retry carries.
The mechanism differs by transport — REST takes this as the Idempotency-Key header (this parameter); the MCP tools take the equivalent value as an idempotencyKey argument field instead, since MCP tool calls have no separate header channel.
Request body
Example request
{
"primaryDomain": "acme.com"
}Response
Accepted: returned by every call that sets up, finished or not. Returns { jobId, billing } where jobId is a correlation id only, not a trackable job handle — there is no job store and no endpoint that accepts it, so do not poll for it or treat its presence as meaningful. billing (MailboxBilling) is the billing projection for the real post-setup mailbox count. A quoteOnly:true request instead returns 200 with { quoteOnly: true, billing } and sets up nothing.
A provisioning field is present only when the call returned OWING work, and names which state: "pending" (the last domain's DNS registration is still completing — pendingDomain names it) or "capacity_pending" (setup is paused while Coldrig support checks recent purchases on this account; nothing failed and nothing was charged; once support finishes, repeating your last call with the SAME idempotency key completes it) or "payment_pending" (a large order: it would bring the account more than 20 mailboxes past what its last confirmed payment covered, so nothing was bought; a person with the card pays this billing period's share at payment.url, which is taken off the next bill, and repeating the call with the SAME idempotency key then completes it — see LargeOrderPayment). An outcome carrying provisioning, and a quoteOnly preview, are NOT recorded against your Idempotency-Key — retrying with the same key re-runs the call rather than replaying the unfinished answer.
nextSteps (design §7.2) names what this account should do next — the SAME derivation GET /infrastructure-status embeds.
Changes
- warning
added the new
large_order_payment_pendingenum value to the///response property for the response status - info
added the new optional request property
- info
added the new optional request property
- info
added the optional property
////////to the response with the status - info
added the optional property
////////to the response with the status - info
added the optional property
to the response with the status
- warning