---
title: "Buy a domain with Orgo credits"
method: POST
path: "/api/projects/{id}/domains"
tags: ["domains"]
---

# Buy a domain with Orgo credits

`POST /api/projects/{id}/domains`

## Request

- Base URL: `https://www.orgo.ai`
- URL: `https://www.orgo.ai/api/projects/{id}/domains`
- Auth: HTTP bearer

Body: { domain, registrant, expected_price_cents? }. domain is a name and an extension from the search (orgo.agency). Send expected_price_cents, the search’s price_cents: if the price changed since, nothing is bought and the answer is 409 PRICE_CHANGED with the new price (without it, the current price is charged). The price comes out of the buyer’s Orgo credits (402 INSUFFICIENT_CREDITS, with price_cents and available_cents, when they fall short).

The domain is registered for the extension’s shortest term (min_years: 1 for most, 2 for some, like .ai), with WHOIS privacy and the transfer lock on, and its DNS on Orgo DNS (GET .../dns). It renews by itself from the payer’s Orgo credits, auto_renew on, until auto-renew is turned off (PATCH .../domains/{domainId}); expires_at says when the term ends. The registrant is the domain’s legal owner: the registry emails them to confirm within 15 days, or suspends the domain.

201 with the domain, active. 200 when this workspace already owns it. When the registry’s answer is lost the answer is 502 REGISTRATION_UNKNOWN and the domain stays pending with its credits held: GET /api/projects/{id}/domains finds out and charges or gives them back. A session or an account-wide key with write access: a workspace-scoped key gets 403 ACCOUNT_KEY_REQUIRED, since buying spends money. 10 purchases a day per account, refused ones included (asking again for a domain this workspace owns does not count).

## Path parameters

- `id` string, uuid, required

## Request body

- object
  - `domain` string, required
  - `registrant` Registrant, required: Who the domain is registered to: its legal owner. The registry emails this address to confirm within 15 days, or suspends the domain. WHOIS privacy keeps it out of public lookups.
    - `first_name` string, required
    - `last_name` string, required
    - `org_name` string: Left out: the person’s own name.
    - `email` string, email, required
    - `phone` string, required: +<country code>.<number>; "+1 415 555 0123" and a 10 digit US number are accepted too.
    - `address1` string, required
    - `address2` string
    - `city` string, required
    - `state` string, required: State, province or region.
    - `postal_code` string, required
    - `country` string, required: Two letter country code.
  - `expected_price_cents` integer: price_cents from the search. A different price now is 409 PRICE_CHANGED.

## Response `200`

This workspace already owns it.

- RegisteredDomain
  - `id` string, uuid, required
  - `domain` string, required
  - `status` 'pending' | 'active', required: pending: the registry has not confirmed it yet; its price is held from the credits until it does.
  - `expires_at` string, date-time, nullable, required: When the term ends, as the registry has it. With auto_renew on it renews before then.
  - `created_at` string, date-time, required
  - `auto_renew` boolean, required: Orgo renews it in its last 14 days from the payer’s Orgo credits. On when bought, off when adopted.
  - `renewal_cents` integer, nullable, required: What the next renewal costs, for renewal_years years. null while there is no price.
  - `renewal_years` integer, required: The years one renewal adds: 1 for most extensions, 2 for a few (like .ai).
  - `renewal_paid_by` 'you' | 'member' | 'null', nullable, required: Whose Orgo credits pay the renewal: yours, or another member’s (whoever turned auto-renew on last, else the buyer). null with auto-renew off.
  - `renewal_state` 'off' | 'scheduled' | 'renewing' | 'retrying' | 'expired', required: off: auto-renew is off and it expires at expires_at. scheduled: the price is taken 14 days before expires_at, and it renews then (only where renewals_enabled). renewing: the renewal is with the registry (it can take up to a day to confirm). retrying: the last try failed (renewal_error) and Orgo tries again every day until expiry. expired: expires_at has passed.
  - `renewal_error` 'insufficient_credits' | 'no_payer' | 'registry_refused' | 'null', nullable, required: Why the last try failed, while retrying: the payer’s credits fall short, the payer can no longer pay (turn auto-renew on, PATCH true, to pay yourself), or the registry refused it.
  - `pointed` object[], required: Names on the domain connected to a computer.
    - `domain` string
    - `computer_id` string, uuid
    - `computer_name` string, nullable
    - `status` string: The custom domain’s status (pending, verifying, active, ...).

## Other responses

- `201`: Bought.
- `400`: Not a domain from the search (INVALID_DOMAIN), a registrant field that is missing or not valid (INVALID_REGISTRANT, with field), or an extension not sold here (TLD_NOT_SOLD).
- `401`: Unauthenticated.
- `402`: The credits fall short (INSUFFICIENT_CREDITS, with price_cents and available_cents). Add credits, then buy again.
- `403`: A workspace-scoped key (ACCOUNT_KEY_REQUIRED), view-only access (workspace_read_only), no access, or a share-link guest.
- `404`: Domains are not enabled for this account (DOMAINS_NOT_ENABLED), or the workspace was not found.
- `409`: Someone already bought it through Orgo (DOMAIN_TAKEN), the registry says it is not free (DOMAIN_UNAVAILABLE, with status), or the price changed (PRICE_CHANGED, with price_cents, renewal_cents_per_year and min_years: check it, then buy again).
- `422`: The registry refused the registration (REGISTRATION_FAILED); the credits were given back.
- `429`: The day’s purchase attempts are used (rate_limited). retry_after and Retry-After say when.
- `502`: The registry has not confirmed it yet (REGISTRATION_UNKNOWN; it shows in the list once it does, and the credits stay held until then), or the registry could not be reached or could not say whether the name is free; nothing was bought (REGISTRAR_UNAVAILABLE).
- `503`: Domains are unavailable right now (DOMAINS_UNAVAILABLE), or the purchase limit could not be checked (unavailable). Try again shortly.

## Changes

- **2026-11-01** `60e768a2bb9d`: 24 info
  - added the optional property `docs_url` to the response with the `400` status
  - added the optional property `docs_url` to the response with the `402` status
  - added the optional property `docs_url` to the response with the `403` status
  - added the optional property `docs_url` to the response with the `404` status
  - …20 more
- **2026-10-26** `3cc83acab9fd`: 12 info
  - added the required property `auto_renew` to the response with the `200` status
  - added the required property `auto_renew` to the response with the `201` status
  - added the required property `renewal_cents` to the response with the `200` status
  - added the required property `renewal_cents` to the response with the `201` status
  - …8 more
- **2026-10-22** `a506f6169bb5`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/orgo/apis/orgo-api/changes/api/projects/:id/domains/post.md)

---

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