infrastructure

Set up branded lookalike domains and mailboxes; start warmup.

Changed on

Domain 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.

post/setup-infrastructure

Request

  • Base URL: https://api.coldrig.dev
  • URL: https://api.coldrig.dev/setup-infrastructure
  • Auth: HTTP bearer

Headers

Idempotency-Keystring

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

brandstring required

One line of plain text: a line break, tab, control character or invisible text-direction mark is refused (400) naming this field.

primaryDomainstring required
domainsinteger required

Number of lookalike domains to set up.

inboxesEachinteger

Mailboxes to set up per domain, UNIFORM across every ordinal. 3 to 5 mailboxes per domain (3 by default, 5 when you order more than 10 in your first month); on a paying account a new domain needs 3 to 5. Putting 5 on a domain means fewer domains, but if that domain gets burned, 5 mailboxes stop sending instead of 3. Optional only when distribution is supplied.

distributioninteger[]

The per-ordinal mailbox count directly — one entry per domain ordinal (e.g. [4, 3] for 4 mailboxes on domain 0 and 3 on domain 1), for a shape inboxesEach's single uniform number cannot express. Its length must equal domains. Alternative to inboxesEach, not additive with it.

personastring required
physicalAddressstring required

CAN-SPAM-required physical postal address, injected into the footer of every campaign email (replies sent with the reply tool or the dashboard carry no footer).

senderIdentitystring required

Legal sender identity captured at setup, injected into the footer of every campaign email (replies sent with the reply tool or the dashboard carry no footer).

quoteOnlyboolean

Quote-before-add. true previews the new mailbox count + projected monthly (returns 200 { quoteOnly, billing }) WITHOUT setup. false (default) sets up and returns { jobId, billing }.

registerDomainsboolean

This account's opt-in consent to real domain purchases made on the platform's own account (the customer's bill is unchanged, mailbox-count-based only). Omitting this field entirely leaves any previously-given consent UNCHANGED; an explicit false revokes it. There is no default — an absent field is never treated as false. true opts in; registrant is required only when no complete registrant is already on file from a prior call (see Registrant) — a call omitting registerDomains (or sending false) on a request that needs to buy a domain is refused before any spend: 400 registrar_optin_missing once this account has consented at least once, or 503 registrar_unarmed if domain registration is not enabled for the platform at all. The 400 is cleared by sending registerDomains: true, and only after the account owner has approved the quoted purchase; a request cannot clear the 503.

dotComDomainsboolean

Only when the quote's billing.domainEnding is set: true keeps those new domains on .com for the one-time fee it shows per domain, added to the next bill. Leave it out for .co. Ask the account owner first.

prepaySecondMonthboolean

Only when the quote's billing.prepay is set (an order making more than 4 new domains in your first billing month): true accepts paying month 2 up front with this order (the amount it shows, charged right after the mailboxes are set up; the next renewal moves one month later; a cancel at any time ends the plan on that date; the prepaid month is not refunded). Ask the account owner first.

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_pending enum 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