buy_domain
Start the domain purchase process via Stripe checkout. After verifying domain availability and displaying the price, submit registrant details to complete the order. The domain is registered in your name with WHOIS privacy.
Instructions
Start the purchase flow for an available domain via Stripe checkout.
IMPORTANT: Before calling this tool, you MUST first call check_domain to get the price, then clearly show the user the price and get their explicit confirmation before proceeding. Never call buy_domain without the user seeing and approving the price first.
The registrant contact details are required because the domain will be registered in the buyer's name (they become the legal owner). WHOIS privacy is enabled by default, so these details are not publicly visible.
Creates a Stripe checkout session. Returns a checkout URL that the user should open in their browser to complete payment securely via Stripe, plus the order ID for tracking.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| domain | Yes | The domain to purchase (e.g. "coolstartup.com"). | |
| first_name | Yes | Registrant's first name. | |
| last_name | Yes | Registrant's last name. | |
| Yes | Registrant's email address. | ||
| address1 | Yes | Registrant's street address. | |
| city | Yes | Registrant's city. | |
| state | Yes | Registrant's state or province. | |
| postal_code | Yes | Registrant's postal/zip code. | |
| country | Yes | 2-letter ISO country code (e.g. "US", "GB", "DE"). | |
| phone | Yes | Phone number in format +1.5551234567. | |
| org_name | No | Organization name (optional, leave empty for individuals). |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
No arguments | |||
Implementation Reference
- instadomain/mcp_tools_buy.py:10-74 (handler)MCP tool handler for buy_domain. Accepts domain and registrant contact details, builds payload, POSTs to /buy on backend to create Stripe checkout session.
async def buy_domain( domain: str, first_name: str, last_name: str, email: str, address1: str, city: str, state: str, postal_code: str, country: str, phone: str, org_name: str = "", ) -> dict: """Start the purchase flow for an available domain via Stripe checkout. IMPORTANT: Before calling this tool, you MUST first call check_domain to get the price, then clearly show the user the price and get their explicit confirmation before proceeding. Never call buy_domain without the user seeing and approving the price first. The registrant contact details are required because the domain will be registered in the buyer's name (they become the legal owner). WHOIS privacy is enabled by default, so these details are not publicly visible. Creates a Stripe checkout session. Returns a checkout URL that the user should open in their browser to complete payment securely via Stripe, plus the order ID for tracking. Args: domain: The domain to purchase (e.g. "coolstartup.com"). first_name: Registrant's first name. last_name: Registrant's last name. email: Registrant's email address. address1: Registrant's street address. city: Registrant's city. state: Registrant's state or province. postal_code: Registrant's postal/zip code. country: 2-letter ISO country code (e.g. "US", "GB", "DE"). phone: Phone number in format +1.5551234567. org_name: Organization name (optional, leave empty for individuals). Returns: Dict with order_id, checkout_url, price_cents, and price_display. """ payload = { "domain": domain, "registrant": { "first_name": first_name, "last_name": last_name, "email": email, "org_name": org_name, "address1": address1, "city": city, "state": state, "postal_code": postal_code, "country": country, "phone": phone, }, } async with httpx.AsyncClient(base_url=BACKEND_URL, timeout=15) as client: resp = await client.post("/buy", json=payload) if resp.status_code == 400: return resp.json() resp.raise_for_status() return resp.json() - instadomain/routes_buy.py:35-82 (handler)Backend FastAPI route /buy that checks availability, gets price, creates order, creates Stripe checkout session, returns order_id and checkout_url.
async def buy_domain(body: BuyRequest, request: Request): """Create a Stripe checkout session and order for a domain purchase.""" domain = body.domain.strip().lower() result = await _check_availability(domain) if not result["available"]: raise HTTPException(status_code=400, detail=f"Domain {domain} is not available") pool = request.app.state.pool opensrs = request.app.state.opensrs try: wholesale_cents = await _get_price(domain, opensrs) except Exception as exc: raise HTTPException(status_code=502, detail=f"Price lookup failed: {exc}") tld = domain.rsplit(".", 1)[-1] if "." in domain else "com" retail_cents = calculate_retail_cents(wholesale_cents, tld) order = await create_order( pool, domain=domain.rsplit(".", 1)[0] if "." in domain else domain, tld=tld, amount_cents=retail_cents, wholesale_cents=wholesale_cents, stripe_session_id=None, registrant_contact=body.registrant.model_dump(), ) try: checkout = await asyncio.to_thread( create_checkout_session, domain, retail_cents, order["id"] ) except Exception as exc: raise HTTPException(status_code=502, detail=f"Payment setup failed: {exc}") async with pool.acquire() as conn: await conn.execute( "UPDATE orders SET stripe_session_id = $1 WHERE id = $2", checkout["session_id"], order["id"], ) return { "order_id": order["id"], "checkout_url": checkout["checkout_url"], "price_cents": retail_cents, "price_display": format_price(retail_cents), } - instadomain/models.py:53-55 (schema)Pydantic BuyRequest model with domain and RegistrantContact for input validation on the buy endpoint.
class BuyRequest(BaseModel): domain: str registrant: RegistrantContact - instadomain/mcp_server.py:176-177 (registration)Import statement that triggers registration of buy_domain and buy_domain_crypto tools on the FastMCP instance.
# Import buy tools so they register on the same mcp instance import instadomain.mcp_tools_buy # noqa: E402, F401 - instadomain/pricing.py:28-47 (helper)Pricing helper calculate_retail_cents used by the buy route to compute retail price from wholesale cost using flat markup or percentage markup.
def calculate_retail_cents(wholesale_cents: int, tld: str) -> int: """Calculate the retail price in cents for a domain. Standard domains (wholesale at or below the TLD threshold) get a flat markup. Premium domains (above the threshold) get a percentage markup. For unknown TLDs, falls back to .com thresholds and markup. """ threshold = WHOLESALE_THRESHOLDS.get(tld, WHOLESALE_THRESHOLDS["com"]) markup = STANDARD_MARKUP.get(tld, STANDARD_MARKUP["com"]) if wholesale_cents <= threshold: return wholesale_cents + markup else: return int(wholesale_cents * (1 + PREMIUM_MARKUP_PCT)) def format_price(cents: int) -> str: """Format a price in cents as a dollar string like '$10.99'.""" return f"${cents / 100:.2f}"