Support

End-to-end workflow

View as Markdown

Complete workflow for buying and configuring a domain — search, quote, register, add DNS, verify. Runnable start-to-finish in under 5 minutes.

What you'll build

A complete end-to-end workflow: search for an available domain, lock a price with a quote, register it (with idempotency for retry safety), add a DNS record, and verify. Every step is copy-paste runnable in curl, Node, Python, or Go.

Overview

Rendering diagram...

Prerequisites: a GoDaddy account with a payment method on file, a Personal Access Token with domains.domain:read, domains.registration:write, and domains.dns:update scopes, and the CLI or curl. Export the token:

export GODADDY_PAT="<YOUR_TOKEN>"
export BASE="https://api.godaddy.com"  # or api.ote-godaddy.com for testing

Check availability

GET /v3/domains/check-availability returns availability and indicative pricing for a domain.

curl -s "$BASE/v3/domains/check-availability?domain=example.com" \
  -H "Authorization: Bearer $GODADDY_PAT"
const res = await fetch(`${process.env.BASE}/v3/domains/check-availability?domain=example.com`, {
  headers: { Authorization: `Bearer ${process.env.GODADDY_PAT}` },
});
const { available, prices } = await res.json();
if (!available) throw new Error("Domain not available");
console.log("Available at", prices[0].price.value / 100, prices[0].price.currencyCode);
import os, requests

res = requests.get(
    f"{os.environ['BASE']}/v3/domains/check-availability",
    params={"domain": "example.com"},
    headers={"Authorization": f"Bearer {os.environ['GODADDY_PAT']}"},
)
data = res.json()
assert data["available"], "Domain not available"
price = data["prices"][0]["price"]
print(f"Available at {price['value'] / 100} {price['currencyCode']}")
package main

import (
    "encoding/json"
    "fmt"
    "net/http"
    "os"
)

type Price struct {
    Value        int    `json:"value"`
    CurrencyCode string `json:"currencyCode"`
}

func main() {
    req, _ := http.NewRequest("GET",
        os.Getenv("BASE")+"/v3/domains/check-availability?domain=example.com", nil)
    req.Header.Set("Authorization", "Bearer "+os.Getenv("GODADDY_PAT"))
    res, _ := http.DefaultClient.Do(req)
    defer res.Body.Close()

    var data struct {
        Available bool `json:"available"`
        Prices    []struct{ Price Price } `json:"prices"`
    }
    json.NewDecoder(res.Body).Decode(&data)
    if !data.Available { panic("not available") }
    fmt.Printf("Available at %d %s\n", data.Prices[0].Price.Value/100, data.Prices[0].Price.CurrencyCode)
}

Response shape:

{
  "domain": "example.com",
  "available": true,
  "prices": [
    { "term": "YEAR", "period": 1, "price": { "currencyCode": "USD", "value": 1199 } }
  ]
}

Get a registration quote

POST /v3/domains/registration-quotes locks the price. The returned quoteToken guarantees the price you see is the price you'll pay when you execute registration.

curl -s -X POST "$BASE/v3/domains/registration-quotes" \
  -H "Authorization: Bearer $GODADDY_PAT" \
  -H "Content-Type: application/json" \
  -d '{"domain": "example.com", "period": 1}'
const res = await fetch(`${process.env.BASE}/v3/domains/registration-quotes`, {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.GODADDY_PAT}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ domain: "example.com", period: 1 }),
});
const { quoteToken, expiresAt } = await res.json();
console.log("Quote locked until", expiresAt);
import os, requests

res = requests.post(
    f"{os.environ['BASE']}/v3/domains/registration-quotes",
    json={"domain": "example.com", "period": 1},
    headers={
        "Authorization": f"Bearer {os.environ['GODADDY_PAT']}",
        "Content-Type": "application/json",
    },
)
quote = res.json()
print("Quote locked until", quote["expiresAt"])
body := strings.NewReader(`{"domain": "example.com", "period": 1}`)
req, _ := http.NewRequest("POST",
    os.Getenv("BASE")+"/v3/domains/registration-quotes", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("GODADDY_PAT"))
req.Header.Set("Content-Type", "application/json")

res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()

var quote struct {
    QuoteToken string `json:"quoteToken"`
    ExpiresAt  string `json:"expiresAt"`
}
json.NewDecoder(res.Body).Decode(&quote)
fmt.Println("Quote locked until", quote.ExpiresAt)

Register the domain

POST /v3/domains/registrations executes the registration. Send an Idempotency-Key header — if the request times out or returns 5xx, replay with the same key and the server dedupes.

Charges real money

This call charges the account's payment profile. Verify the domain name and quoted price before executing.

curl -s -X POST "$BASE/v3/domains/registrations" \
  -H "Authorization: Bearer $GODADDY_PAT" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "quoteToken": "qt_abc123...",
    "domain": "example.com",
    "period": 1,
    "consent": {
      "agreedAt": "2026-07-07T10:30:00.000Z",
      "agreementTypes": ["API_DPA"]
    }
  }'
import { randomUUID } from "node:crypto";

const res = await fetch(`${process.env.BASE}/v3/domains/registrations`, {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.GODADDY_PAT}`,
    "Content-Type": "application/json",
    "Idempotency-Key": randomUUID(),
  },
  body: JSON.stringify({
    quoteToken: "qt_abc123...",
    domain: "example.com",
    period: 1,
    consent: {
      agreedAt: new Date().toISOString(),
      agreementTypes: ["API_DPA"]
    },
  }),
});
if (res.status !== 201) throw new Error(`Registration failed: ${res.status}`);
console.log("Registered:", (await res.json()).domain);
import os, uuid, requests
from datetime import datetime, timezone

res = requests.post(
    f"{os.environ['BASE']}/v3/domains/registrations",
    json={
        "quoteToken": "qt_abc123...",
        "domain": "example.com",
        "period": 1,
        "consent": {
            "agreedAt": datetime.now(timezone.utc).isoformat(),
            "agreementTypes": ["API_DPA"]
        },
    },
    headers={
        "Authorization": f"Bearer {os.environ['GODADDY_PAT']}",
        "Content-Type": "application/json",
        "Idempotency-Key": str(uuid.uuid4()),
    },
)
res.raise_for_status()
print("Registered:", res.json()["domain"])
import "github.com/google/uuid"

body := map[string]any{
    "quoteToken": "qt_abc123...",
    "domain":     "example.com",
    "period":     1,
    "consent": map[string]any{
        "agreedAt":       time.Now().UTC().Format(time.RFC3339),
        "agreementTypes": []string{"API_DPA"},
    },
}
b, _ := json.Marshal(body)
req, _ := http.NewRequest("POST",
    os.Getenv("BASE")+"/v3/domains/registrations", bytes.NewReader(b))
req.Header.Set("Authorization", "Bearer "+os.Getenv("GODADDY_PAT"))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Idempotency-Key", uuid.NewString())

res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
if res.StatusCode != 201 { panic(fmt.Sprint("registration failed: ", res.StatusCode)) }

Returns 201 Created with the order ID and domain metadata.

Add a DNS record

POST /v3/domains/zones/{zone}/dns-records adds a record. Common first step: an A record pointing the apex at your web server.

curl -s -X POST "$BASE/v3/domains/zones/example.com/dns-records" \
  -H "Authorization: Bearer $GODADDY_PAT" \
  -H "Content-Type: application/json" \
  -d '{"type": "A", "name": "@", "data": "192.0.2.1", "ttl": 600}'
const res = await fetch(
  `${process.env.BASE}/v3/domains/zones/example.com/dns-records`,
  {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.GODADDY_PAT}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ type: "A", name: "@", data: "192.0.2.1", ttl: 600 }),
  },
);
const record = await res.json();
console.log("Created record", record.recordId);
import os, requests

res = requests.post(
    f"{os.environ['BASE']}/v3/domains/zones/example.com/dns-records",
    json={"type": "A", "name": "@", "data": "192.0.2.1", "ttl": 600},
    headers={
        "Authorization": f"Bearer {os.environ['GODADDY_PAT']}",
        "Content-Type": "application/json",
    },
)
res.raise_for_status()
print("Created record", res.json()["recordId"])
body := strings.NewReader(`{"type": "A", "name": "@", "data": "192.0.2.1", "ttl": 600}`)
req, _ := http.NewRequest("POST",
    os.Getenv("BASE")+"/v3/domains/zones/example.com/dns-records", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("GODADDY_PAT"))
req.Header.Set("Content-Type", "application/json")

res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()

Verify propagation

Confirm the record was accepted by the API, then confirm it's answering at a public resolver.

  1. Read the zone back through the API. The new record should appear in items[].

    curl -s "$BASE/v3/domains/zones/example.com/dns-records?type=A" \
      -H "Authorization: Bearer $GODADDY_PAT"
  2. Query a public resolver. Global propagation completes within seconds; the delay end-users see depends on their local resolver's TTL cache.

    dig +short A example.com
    # 192.0.2.1

What's next

  • Add more DNS records (CNAME, MX, TXT) via the same endpoint — see the DNS how-to
  • Set up domain forwarding to redirect apex-www or subdomains — see Forwarding
  • Manage renewals and auto-renew — see Renewals
  • Lock the domain against unauthorized transfer — see Registry lock

Agent & Automation Notes

PermissionsPayment Profile, DNS Management
Scopesdomains.domain:read, domains.registration:write, domains.dns:update
Rate limit60 req/min per credential
IdempotentNo
DestructiveYes — confirm before executing
On failureRegistration is NOT idempotent without Idempotency-Key header. On any partial success, GET the domain first before retrying. Real money changes hands — be sure you want to do this before executing.

Last updated on

How is this guide?

On this page