# Register Domain

Buy a domain with end-user registrant contacts, then track delivery to the customer easyDNS account.

## Discovery

- Identifier: `domain.register`
- Version: `v1`
- Category: Domain intelligence
- Status: `live-paid`
- Access: `x402-quoted-price`
- Human docs: https://dnsskills.md/register-domain
- Agent Markdown: https://dnsskills.md/register-domain.md
- SKILL.md: https://dnsskills.md/register-domain/SKILL.md
- OpenAPI: https://dnsskills.md/openapi.yaml
- Public GitHub mirror: https://github.com/easydns/dns-agent-skills
- Web UI: https://app.domainhelp.com/skills/register-domain


## Registration contact information

Ask the user for accurate registrant details before preparing an order. Never invent contact information, use the agent developer as the owner, or substitute the shared easyDNS account details. Use an existing reachable email address, not an address under the domain being registered.

| Field in registrant | Required | Description | Example |
| --- | --- | --- | --- |
| `first_name` | Yes | Registrant given name. | `Alex` |
| `last_name` | Yes | Registrant family name. | `Example` |
| `org_name` | No | Organization name, where applicable. | `Example Company` |
| `address1` | Yes | Street address. | `123 Example Street` |
| `address2` | No | Apartment, suite or second address line. | `Suite 200` |
| `city` | Yes | City or locality. | `Toronto` |
| `state` | Yes | Province, state or region. | `ON` |
| `country` | Yes | Uppercase ISO 3166-1 two-letter country code. | `CA` |
| `postal_code` | Yes | Postal or ZIP code. | `M5V 1A1` |
| `phone` | Yes | International number with country prefix. easyDNS dotted notation is accepted. | `+1.4165550100` |
| `email` | Yes | Reachable registrant email; also used for delivery to the customer easyDNS account. | `alex@example.net` |
| `language` | For .ca | Owner contact language: en or fr. | `en` |
| `cpr` | For .ca | Canadian Presence Requirement category. Use the requirements response for allowed codes and select the category the registrant actually meets. | `CCT` |

Put these fields inside registrant. Admin, technical and billing contacts reuse this registrant by default. To supply different people, provide a complete contact object under contacts.admin, contacts.tech or contacts.billing, using the same required fields.

## Check current requirements

Start with GET /api/v1/register-domain/requirements?domain=YOUR_DOMAIN. The live policy accepts active IANA generic TLDs, including legacy and new gTLDs, when easyDNS returns a supported available offer. The permitted country-code exceptions are .ai, .io, .tv and .to; all other ccTLDs, including internationalized ccTLDs, are excluded. Registration terms are two years for .ai and .to, and one year otherwise; use the quoted term_years and total price. The response supplies the current quote, registrant_fields, TLD-specific fields, agreement version and email verification requirement. If tld_fields.extra is present, supply the required registry fields under extra in the prepared order; these are validated before payment. For example, .cat requires registrant_type and intended_use, .law requires lawyer accreditation fields, and .paris requires paris_nexus. Never invent eligibility information. The .ca language/Canadian Presence Requirement fields are retained for the older explicit-allowlist mode; .ca is not enabled under the live gTLD-plus-ccTLD-exceptions policy.

## Check the registrant email

Read offer.email_validation_method and offer.email_verification_required. In smtp mode, email_verification_required is false: omit verification_token and do not call the email challenge endpoint. The server resolves the email domain’s MX and checks SMTP recipient acceptance during order preparation, before payment, without sending DATA or an email. An accepted RCPT permits preparation; it does not prove email ownership or guarantee delivery. A clear invalid mailbox/no mail route returns 422 email_undeliverable with a message. Timeouts, greylisting or policy blocks return retryable 503 email_deliverability_unconfirmed. Neither failure collects payment. In code mode only, POST email and payer to /api/v1/registration-email/challenges, then POST challenge_id and the emailed code to /api/v1/registration-email/verify. Keep the resulting verification_token private. Registrar contact verification remains separate.

## Prepare the order

Obtain the user’s agreement to the current registration terms. Generate a cryptographically random 32-byte order_token encoded as 64 hexadecimal characters. POST the following shape to /api/v1/registration-orders with a unique Idempotency-Key header (16–200 characters). Replace all example contacts, wallet, quote ID and tokens with the actual values. Omit verification_token only when the requirements response explicitly says verification is not required.

```json
{
    "quote_id": "58dc6c2d-43a3-4bfe-b2fb-53b6b2cc820e",
    "payer": "0x1111111111111111111111111111111111111111",
    "order_token": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
    "agreement_version": "<version from requirements>",
    "accept_terms": true,
    "registrant": {
        "first_name": "Alex",
        "last_name": "Example",
        "address1": "123 Example Street",
        "city": "Toronto",
        "state": "ON",
        "country": "CA",
        "postal_code": "M5V 1A1",
        "phone": "+1.4165550100",
        "email": "alex@example.net"
    }
}
```

## Pay and register

The preparation response returns order_id and status_url; it has not charged the wallet or registered the domain. POST only {"order_id":"<prepared order ID>"} to /api/v1/register-domain with Authorization: Bearer ORDER_TOKEN. Use a standard x402 SDK to satisfy the PAYMENT-REQUIRED challenge at the quoted registration price. The payer must match the prepared wallet. Lookup payments are separate from registration payments.

## Check completion and retries

Poll status_url with the same bearer token. A 202 response means the original order is pending or requires reconciliation. Retry or poll that order; never submit another purchase to recover it. Retain PAYMENT-RESPONSE when present. registration_status=registered and handoff_status=pending means the domain is registered but delivery to the customer account is still pending. Handoff means moving account control from the shared easyDNS account to the customer account, not transferring registrars. Read handoff.blockers for unresolved invoice or registrant-contact issues. An outcome_unknown is not proof of registration failure and must not trigger an automatic refund. Staff must reconcile the existing order against the registrar account and registration evidence.

## Save the recovery key — required

REQUIRED: When payment_status=settled and registration_status=registered, the response contains recovery_key and recovery.save_required=true. Save the recovery key in durable private storage with the domain, order_id and payment receipt before marking the task complete. Ensure the customer can retrieve it independently of the registrant email; do not keep the only copy in email or transient agent context. If email delivery irrecoverably fails and the customer cannot access the domain, this key is required to recover access through easyDNS support. Open a private easyDNS support ticket with the domain and recovery key; staff can match it against the stored registration record. Treat it as an access secret: never put it in URLs, logs, shared chats or public reports. If the response is lost or the key is missing, GET the original authenticated status_url with the saved order_token to retrieve the same key. Do not purchase again. A successful match lets staff continue their recovery process; it does not itself transfer the domain.

## Testing status

This skill is available by direct URL for testing. If an endpoint returns 503 registration_unavailable, stop and report that registration has not been enabled. Do not claim that an order was created or a domain was purchased.

Complete request schema: https://dnsskills.md/register-domain/openapi.yaml

## Agent Invocation

Use the execution API endpoints below. Do not post to browser Web UI form routes; those routes are for humans and may require CSRF and reCAPTCHA.

- `POST https://app.domainhelp.com/api/v1/register-domain`
  - Status: `configuration-required`
  - Response modes: `json`
- `GET https://app.domainhelp.com/api/v1/register-domain/requirements`
  - Status: `configuration-required`
  - Response modes: `json`
- `POST https://app.domainhelp.com/api/v1/registration-orders`
  - Status: `configuration-required`
  - Response modes: `json`
- `GET https://app.domainhelp.com/api/v1/registration-orders/{id}`
  - Status: `configuration-required`
  - Response modes: `json`

## Input Contract

1. Get a quote from Domain Availability, Domain Intelligence or GET /api/v1/register-domain/requirements?domain=NAME. 2. If required, POST email and payer to /api/v1/registration-email/challenges, then POST challenge_id and the emailed code to /api/v1/registration-email/verify. 3. Generate a random 32-byte hex order_token. POST quote_id, payer, order_token, verification_token, registrant, agreement_version and accept_terms=true to /api/v1/registration-orders with a unique Idempotency-Key header (16–200 characters). Optional contacts override admin, tech and billing; otherwise the registrant is used. Optional nameservers must contain 2–6 hosts. 4. POST only order_id to /api/v1/register-domain with Authorization: Bearer ORDER_TOKEN and satisfy its x402 challenge using a standard SDK. 5. Poll the returned status_url with the same bearer token. Do not construct payment signatures by hand.

## Output Contract

Returns separate payment_status, registration_status and handoff_status. A registered domain can still await delivery to the customer account. Successful paid registrations also return a private recovery_key and recovery.save_required=true: save the key securely before completing the task. A pending or uncertain outcome returns 202; poll rather than creating another purchase. Keep the PAYMENT-RESPONSE receipt.

## Errors

Missing contacts or verification: 422. Stale quotes, duplicate domain claims or payment reuse: 409. Unconfigured service: 503. Payment required: 402. Registration uncertainty remains on the original order for reconciliation.

## Auth And Limits

x402 v2 exact EVM payment at the server quote; order access uses the private order_token. Follow the requirements response for the email check method. SMTP mode checks recipient acceptance inline before payment and sends no email; code mode requires a private email verification credential scoped to the email and payer wallet.

Standard API limits apply; verification is limited per IP and email. One domain per order.

## Examples

### Requests

```text
GET /api/v1/register-domain/requirements?domain=example.com
```

```text
POST /api/v1/register-domain {"order_id":"<prepared-order-uuid>"}
```

### Responses

```json
{"product":"register-domain","payment_status":"settled","registration_status":"registered","handoff_status":"pending"}
```

## FAQ

### Does the agent need inbox access?

Not in SMTP mode: the service checks MX and RCPT acceptance when preparing the order. In code mode, an agent needs authorized inbox access or a code from the user. SMTP acceptance is a deliverability signal and does not prove email ownership or guarantee delivery.

### Where does the registered domain go?

The end user is the registry registrant. easyDNS initially holds account control under x402; its cron later creates or selects the customer account using the delivery email.

### Where is the complete request schema?

See /register-domain/openapi.yaml and the requirements endpoint for current agreement and TLD fields. Registrar verification may still be required separately.

## Related Skills

- [Domain Availability](https://dnsskills.md/domain-availability.md)
- [Domain Intelligence — RDAP/WHOIS, DNS & DomainSure](https://dnsskills.md/domain-intelligence.md)
