setup_infrastructure
Provision cold-email sending infrastructure by buying branded lookalike domains, creating mailboxes, and starting warmup. Use quoteOnly to preview the projected monthly cost before committing.
Instructions
Provision sending infrastructure: buy branded lookalike domains, create mailboxes, start warmup. New mailboxes are ramp-limited server-side — 5 sends/day in week 1, rising to 40/day after 4 weeks — and your own calls cannot exceed that cap; poll infrastructure_status for the current dailyCap. Inputs: brand, primaryDomain, domains + inboxesEach counts, persona, physicalAddress, senderIdentity. Billing is per-provisioned-mailbox ($10/mailbox + $49 platform, min 5) and the billed quantity follows what you provision here — pass quoteOnly:true first to preview the new count + projected monthly price before committing (no silent capacity addition). Every response carries a billing projection { provisionedAfter (the live count AFTER this call — reality, not the ask), projectedMonthlyCents, formula }: on quoteOnly it's the preview, on an actual provision it's the real post-provision bill (a capacity-limited partial reflects only what landed). Returns { jobId, billing } — 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; it exists to correlate this response with logs. A provisioning field is present ONLY when the call returned still OWING work, and names which state: 'pending' (a domain's DNS registration is still completing — pendingDomain names one of them) or 'capacity_pending' (held at a spend/plan-slot limit, so polling will NOT progress until an operator raises it — call contact_operator instead of waiting). Its ABSENCE is what says the provision finished; the only way to find out is to re-call setup_infrastructure or read infrastructure_status's nextSteps. An outcome carrying provisioning, and a quoteOnly preview, are deliberately NOT recorded against your idempotencyKey — retrying with the same key re-runs the call and finishes the job rather than replaying the unfinished answer. domains and inboxesEach are the infrastructure you want to HAVE, not an amount to add: each call keeps and resumes what this account already has and buys only the shortfall, so to provision MORE you ask for a LARGER number (domains:2 after a call that provisioned one buys the second; raising inboxesEach tops each domain up). Repeating a call therefore never buys twice, whatever you do with idempotencyKey — resend it, change it, or omit it. The key controls response replay only and has no bearing on what is purchased, so a retry is always safe. A domain this account already registered but that never landed in your account (a prior call that failed after the purchase) is ADOPTED on the retry at zero extra cost rather than bought again. A domain whose DNS setup has not finished yet is recorded and never lost — there is no per-domain DNS field to poll (infrastructure_status reports a domain count, not per-domain detail), so read its nextSteps for what to do next, and repeat this same call to converge on the domain and finish its DNS setup. Slot semantics: domains: N covers ordinals 0..N-1, and each ordinal fills to its own mailbox count (uniform via inboxesEach, or per-ordinal via distribution — see below); a repeat call at the SAME domains provisions nothing new once every ordinal is satisfied, so reaching ordinal 1 needs domains:2, not a second domains:1 call. Mailbox addresses are DETERMINISTIC — derived from persona + ordinal + slot — so keep persona EXACTLY as it was on a resume or retry; changing it mid-account does not move existing addresses but does change what a NEW ordinal derives. distribution (optional, alternative to inboxesEach) names the per-ordinal mailbox count directly — one entry per domain ordinal, e.g. [3, 2] for 3 mailboxes on domain 0 and 2 on domain 1 — for a shape inboxesEach's single uniform number cannot express; supply exactly one of the two (an array with domains entries, or the uniform count). registerDomains is this tenant's opt-in consent to real domain purchases made on the platform's own account (our COGS — your bill is unchanged, mailbox-count-based only); only the operator's own global switch being armed too can ever actually enable it. OMITTING it leaves any consent you previously gave UNCHANGED — pass false explicitly to revoke it. A call that omits registerDomains (or sends it false) on a buy-bearing request (one that needs to purchase a new domain) is refused BEFORE any spend. Once this account has consented at least once, that refusal is a 400 registrar_optin_missing: 'registerDomains was not set on this request' — resend the identical call with it set to true to self-correct; this is never an operator escalation. (An account that has never consented, on a platform where domain registration is not yet enabled at all, instead sees the operator-facing 503 registrar_unarmed — indistinguishable from the outside except by status code, but the fix is the same: set registerDomains: true and retry.) Separately, a registerDomains:true call with NO registrant anywhere (neither in this request nor persisted from a prior one) fails with a 400 incomplete_registrant naming the missing fields — also before any purchase. Fresh candidates are de-duplicated against what this account already owns and checked for availability; if a call needs to buy a domain and no available un-owned candidate exists it fails with a 400 naming that, never a silent repeat purchase (a call that needs to buy nothing is unaffected). registrant (a full registrant-of-record object { firstName, lastName, email, phone, addressLine1, city, state, country, postalCode, organization (optional, defaults to brand) }) is OPTIONAL even when registerDomains is true whenever a complete registrant is already on file from a prior call — supplying one makes it authoritative for THIS call; omitting it re-uses the persisted one. This platform never invents a domain registrant's legal identity, so a call with no registrant anywhere (neither supplied nor persisted) is rejected naming the missing fields, at or before the actual purchase — never silently. There is NO background retry: a call returning provisioning needs the caller to retry it; the platform does not complete it for you on a timer. Every response carries nextSteps (see the discriminated status/steps shape) — the account's own next action, computed fresh each time, so a stalled setup is never silent.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| brand | Yes | ||
| domains | Yes | ||
| persona | Yes | ||
| quoteOnly | No | ||
| registrant | No | ||
| inboxesEach | No | ||
| distribution | No | ||
| primaryDomain | Yes | ||
| idempotencyKey | No | Optional idempotency key: resend the SAME key when retrying this call so a dropped-response retry is not applied twice (no duplicate campaign/provision/send). | |
| senderIdentity | Yes | ||
| physicalAddress | Yes | ||
| registerDomains | No |