Skip to content

Orders

Account Scope Required, please include X-Auth-Account header with your Account ID. Index/show require the billing:read OAuth scope; create / update / destroy are not available via OAuth (there is intentionally no billing:write scope) — they require a session or API-key credential.

Ordering flows through the cart/billing system and charges the account's default saved payment method off-session. There is no Stripe checkout redirect.

Two order types

POST /api/orders provisions WordPress sites. POST /api/orders/domain registers or transfers a domain through the same cart/billing flow. Both always return a 202 cart envelope and are OAuth-blocked (require a session or API-key credential).

List all orders for an account

GET /api/orders

Params (optional)
  • page: Integer | page number (default: 1)
  • per_page: Integer | records per page (default: 50, max: 100)
Returned Params
  • orders: Array
    • id: String | uuid
    • status: String
    • created_at: DateTime
    • updated_at: DateTime
    • location: String | location short_name, or null for orders with no location (e.g. domain-registration orders)
    • account: Object
      • id: String
      • name: String

View an Order

GET /api/orders/:id

Poll this endpoint until status reaches a terminal value (completed, failed, cancelled).

Returned Params
  • order: Object
    • id: String | uuid
    • status: String
    • created_at: DateTime
    • updated_at: DateTime
    • location: String | location short_name, or null for orders with no location (e.g. domain-registration orders)
  • tasks: Array
    • id: Integer
    • status: String
  • site: Object | present when the order provisioned a site
    • id: String
    • name: String
    • domain: String
    • variant: String
    • location: String
    • ssh_data: Object
      • ipaddr: String
      • username: String
      • password: String
      • port: Integer
  • subscription: Object | present when the order has a backing subscription
    • id: String
    • status: String
    • bucket_type: String
    • bucket_year: Integer
    • bucket_month: Integer
    • stripe_id: String
  • payment: Object
    • status: String | see payment status enum below
    • method_type: String | card, sepa_debit, or null
    • hosted_invoice_url: String | null
    • amount_charged_cents: Integer
    • credit_applied_cents: Integer
  • account: Object | See accounts#show
  • user: Object | See users#show

Order a new Site

POST /api/orders

Charges the billing account's default payment method off-session and asynchronously provisions a WordPress site. There is no synchronous success branch — the endpoint always returns 202 Accepted with a polling envelope.

Location and plan names can be found by querying the /api/about endpoint.

Pre-flight gate

Requires the billing account to be ready to charge — a Stripe customer ID, a saved default payment method, and a complete billing contact. Failing the gate returns 400 with code: "no_default_payment_method" and no order is created.

Params
  • site: Object (required)
    • name: String (required)
    • variant: String (required) | vanilla, extendify
    • location: String (required) | Location short_name (e.g. "pdx")
    • plan: String (required) | Product short_name (e.g. "basic")
    • term: String (required) | monthly or annual
  • callback: Object | optional outbound notification POSTed when the order's async task completes — see Callbacks
    • authorization: String | full Authorization header value. Example: Bearer 12345
    • url: String | fully qualified URL
Returned Params (always 202 Accepted)
  • status: String | "accepted"
  • cart: Object
    • token: String
    • status: String | active, processing, checked_out
    • rollup_status: String | pending, processing, completed, ...
    • poll_url: String | /api/carts/<token>
  • payment: Object
    • status: String | processing, succeeded, awaiting_authentication
    • method_type: String | card, sepa_debit, or null
    • hosted_invoice_url: String | null
  • orders: Array
    • id: String | uuid
    • status: String | pending
    • poll_url: String | /api/orders/<id>

Poll cart.poll_url (or each order's poll_url) until the orders materialize and reach a terminal state. orders is empty during the async window — the order id is discovered by polling the cart.

Payment status enum

payment.status may be processing (PI in flight / off-session charge), succeeded (finalized), or awaiting_authentication (3DS/SCA required or a recoverable decline — direct the user to hosted_invoice_url). For SEPA, the method confirms as processing and settles in 1–5 business days.

Pre-flight / validation errors (400)
  • no_default_payment_method | billing account not ready to charge
  • unknown variant / location / term / plan
  • variant not available (over capacity)
  • missing pricing information
  • "Account unable to create orders."

Payment could not be initiated (422)

If the cart is valid but Cart::PayService fails to start the off-session charge, the response is 422 with code: "cart_pay_failed". (A pre-flight failure is 400; a payment-initiation failure is 422.)


Register or Transfer a Domain

POST /api/orders/domain

Registers or transfers a domain through the same cart/billing flow as POST /api/orders, charging the account's default saved payment method off-session, then asynchronously registering (or transferring) the domain and creating a renewal subscription and DNS zone. Always returns 202 Accepted with the shared cart envelope; poll /api/orders/:id (which carries a domain block) until status is terminal.

Not available via OAuth and requires a user-scoped credential. A system Account-bearer API key (no user) returns 401 user_required. Requires the X-Auth-Account header and the domain-registration feature flag — when the flag is off, returns 503 feature_disabled. Trial accounts return 403 trial_account.

Params
  • domain: Object (required)
    • name: String (required) | fully-qualified, e.g. example.com
    • action: String (optional) | register (default) or transfer
    • authcode: String | required for transfers when the TLD requires an authcode
    • contact: Object | inline registrant; required unless contact_source is given
      • first_name: String (required)
      • last_name: String (required)
      • organization: String (optional)
      • street_address: String (required)
      • post_code: String (required)
      • city: String (required)
      • state: String (optional/required per TLD)
      • country: String (required) | 2-letter ISO code
      • email: String (required)
      • phone: String (required) | E.164, e.g. +1.5555555555
      • extra_properties: Object | TLD-specific registry fields (e.g. .it entityType)
    • contact_source: Object | reuse an owned registration's contacts instead of contact
      • registration_id: Integer (required) | an owned DomainRegistration that has an owner contact
    • role_contacts: Object (optional) | admin / billing / tech; each:
      • source: String | same_as_owner (default), existing, or new
      • source_registration_id: Integer | when source is existing
      • first_name, last_name, ... | the same contact fields as above, when source is new
  • callback: Object (optional) | same callback contract as POST /api/orders — see Callbacks
    • authorization: String | full Authorization header value. Example: Bearer 12345
    • url: String | fully qualified URL

Provide a registrant via either an inline contact object or contact_source.registration_id (to reuse the contacts of an owned registration), not both.

Returned Params (always 202 Accepted)

Identical envelope to POST /api/orders:

  • status: String | "accepted"
  • cart: Object | { token, status, rollup_status, poll_url }
  • payment: Object | { status, method_type, hosted_invoice_url }
  • orders: Array | [{ id, status, poll_url }] (empty during the async window)
Errors

Authorization / gating:

  • 401 user_required | system Account-bearer key (no user)
  • 503 feature_disabled | domain registration not enabled
  • 403 trial_account | trial accounts cannot order domains

Validation (400, no charge / no order created):

  • invalid_action | action not register or transfer
  • invalid_domain | name failed normalization/validation
  • unsupported_tld | no configured TLD for the name
  • pricing_unavailable | no orderable price for the account's billing plan
  • authcode_required | transfer of a TLD that requires an authcode, none supplied
  • incomplete_contact | inline contact missing required fields
  • invalid_contact | inline contact has a bad value (e.g. country not 2 letters)
  • invalid_contact_source | contact_source.registration_id not found or has no owner contact
  • no_default_payment_method | billing account not ready to charge

Processing (422):

  • domain_unavailable | registry says the name is not registerable (register only)
  • domain_add_failed | cart rejected the domain (e.g. already owned)
  • domain_contact_invalid | registrant contact rejected (body carries violations)
  • domain_contact_needs_augmentation | TLD needs extra contact fields (body carries needs_augmentation)
  • cart_pay_failed | payment could not be initiated (any contacts created for this request are torn down)

Cancel an Order

Cancels an in-progress order.

DELETE /api/orders/:id

Returns 202.

PATCH is a no-op

PATCH /api/orders/:id is reserved and returns 400.


Carts

Poll cart-level state during the async window after POST /api/orders or a site plan change.

Account Scope Required (X-Auth-Account). Scope: billing:read. Carts are scoped to your own account; an unknown token returns 404.

GET /api/carts/:token

The cart token comes from the create response (cart.token / cart.poll_url). The response shape mirrors POST /api/orders so you can reuse the same parser:

Returned Params
  • status: String | "accepted"
  • cart: Object
    • token: String
    • status: String
    • rollup_status: String
    • poll_url: String
  • payment: Object
    • status: String
    • method_type: String | card, sepa_debit, or null
    • hosted_invoice_url: String | null
  • orders: Array
    • id: String | uuid
    • status: String
    • poll_url: String