---
title: "Buy and register domains"
method: POST
path: "/v1/domains/purchase"
tags: ["Domains"]
---

# Buy and register domains

`POST /v1/domains/purchase`

## Request

- Base URL: `https://api.winnr.app`
- URL: `https://api.winnr.app/v1/domains/purchase`
- Auth: HTTP bearer

Purchase domains: charges the account's Stripe payment method, then
registers each domain and queues DNS/email setup (including any
`users` passed per domain). Prices are always resolved server-side
from the registrar — client-supplied prices are ignored. Domains the
account has already paid for are skipped (idempotent; safe to retry).

**Synchronous mode (default):** the charge happens during the request
and the response reports the invoice and per-domain job IDs. Because
the gateway closes the connection after ~30 seconds, large orders can
time out client-side (HTTP 503) *after* the charge succeeds
server-side. For more than 2-3 domains, use async mode instead.

**Async mode (`"async": true`):** the request validates the order,
returns `202` with a `job_id` immediately, and the purchase (pricing,
charge, registration queueing) runs in the background. Poll
`GET /v1/jobs/{job_id}`: when `status` is `completed`, `result`
contains exactly the synchronous response payload; when `failed`,
`error` carries the failure (e.g. `code: payment_failed` with the
card decline details). Recommended for all multi-domain orders.

## Request body

- PurchaseDomainsRequest
  - `async` boolean: Run the purchase in the background and return 202 + job_id immediately. Recommended for orders of more than 2-3 domains (the synchronous path can exceed the gateway's ~30s response window). The job result carries the synchronous response payload.
  - `domains` object[], required
    - `domain` string, required: Domain name to purchase (e.g. example.com).
    - `register` boolean: Register the domain at a registrar (charged). Set false to bring a domain you already own through checkout unbilled (setup only).
    - `setup_dns` boolean
    - `setup_email` boolean
    - `users` object[]: Email users to create on the domain after setup.
      - `name` string, required
      - `username` string, required
    - `redirect_url` string, nullable
    - `forward_address` string, email, nullable: Optional. Once the domain is set up, send a copy of every message that reaches its mailboxes to this address (the same forwarding as POST /v1/domains/{domain_id}/forward). It is not a catch-all: mail to addresses that do not exist on the domain is not forwarded. Validated before any charge (400 if it is not an email address); blank means no forwarding. On a Subdomain Strategy entry it applies to each subdomain, since the parent hosts no mailboxes.
    - `tags` string[]
    - `subdomains` object[]: Subdomain Strategy only (register:true, on the standard four or a premium .io/.sh/.to/.vc): up to 5 subdomains provisioned under this domain, each with up to 10 mailboxes. Subdomains are free - only the parent registration is charged.
      - `label` string, required
      - `users` object[]
        - `name` string, required
        - `username` string, required

## Response `200`

Payment succeeded and domains queued (synchronous mode)

- PurchaseDomainsResponse
  - `data` object
    - `payment` object
      - `success` boolean
      - `invoice_id` string, nullable
      - `amount_paid` number
      - `credits_used` integer
    - `domains` object[]
      - `domain` string
      - `domain_id` string
      - `job_id` string
      - `status` string: queued | already_paid | unavailable
      - `payment_method` string: stripe | credit | bundled
      - `message` string
  - `meta` Meta
    - `request_id` string
    - `timestamp` string, date-time

## Other responses

- `202`: Purchase accepted and processing in the background (async mode)
- `400`: Validation error
- `401`: Authentication required or token invalid
- `402`: Payment failed (synchronous mode only — async payment failures surface on the job)
- `409`: A requested domain already exists in another account

---

[API](https://skmtc.dev/winnr/apis/winnr-api.md) · [All operations](https://skmtc.dev/winnr/apis/winnr-api/llms.txt) · [OpenAPI document](https://skmtc.dev/winnr/apis/winnr-api/revisions/a4f960beb1eb?raw)
