---
name: domain-register
description: Register domains via Google Cloud Domains API and immediately point to Cloudflare nameservers. Supports programmatic registration with instant Cloudflare integration. Optional: Transfer registrar to Cloudflare after 60-day ICANN lock.
homepage: https://cloud.google.com/domains
metadata:
  clawdbot:
    emoji: 🌐
    requires:
      bins:
        - gcloud
        - curl
        - jq
      env:
        - CLOUDFLARE_API_TOKEN
    primaryEnv: CLOUDFLARE_API_TOKEN
---

# Domain Registration + Cloudflare Setup

Register domains programmatically via Google Cloud Domains API and immediately configure Cloudflare nameservers.

## Prerequisites

### 1. Google Cloud Setup
```bash
# Authenticate
gcloud auth login

# Set project
gcloud config set project YOUR_PROJECT_ID

# Enable API
gcloud services enable domains.googleapis.com

# Verify billing is enabled
gcloud billing accounts list
```

### 2. Cloudflare Setup
```bash
# Set API token (get from: https://dash.cloudflare.com/profile/api-tokens)
export CLOUDFLARE_API_TOKEN="your_token_here"

# Get account ID
curl -X GET "https://api.cloudflare.com/client/v4/accounts" \
  -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
  -H "Content-Type: application/json" | jq -r '.result[0].id'

export CLOUDFLARE_ACCOUNT_ID="your_account_id"
```

### 3. Contact Data File
Create `contact.yaml` with registrant info:
```yaml
allContacts:
  email: 'your@email.com'
  phoneNumber: '+1.5555551234'
  postalAddress:
    regionCode: 'US'
    postalCode: '12345'
    administrativeArea: 'NY'
    locality: 'New York'
    addressLines: ['123 Main St']
    recipients: ['Your Name']
```

---

## Full Registration Flow (New Domain)

### Step 1: Check Domain Availability
```bash
DOMAIN="example.com"

# Search for domain
gcloud domains registrations search-domains "$DOMAIN"

# Get pricing and registration parameters
gcloud domains registrations get-register-parameters "$DOMAIN"
```

**Example output:**
```
availability: AVAILABLE
domainName: example.com
supportedPrivacy:
- PRIVATE_CONTACT_DATA
- PUBLIC_CONTACT_DATA
yearlyPrice:
  currencyCode: USD
  units: '12'
```

### Step 2: Add Domain to Cloudflare (Get Nameservers)
```bash
# Create Cloudflare zone
ZONE_RESPONSE=$(curl -X POST "https://api.cloudflare.com/client/v4/zones" \
  -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
  -H "Content-Type: application/json" \
  --data "{
    \"account\": {
      \"id\": \"$CLOUDFLARE_ACCOUNT_ID\"
    },
    \"name\": \"$DOMAIN\",
    \"type\": \"full\"
  }")

# Extract nameservers
NS1=$(echo "$ZONE_RESPONSE" | jq -r '.result.name_servers[0]')
NS2=$(echo "$ZONE_RESPONSE" | jq -r '.result.name_servers[1]')

echo "Cloudflare Nameservers:"
echo "  $NS1"
echo "  $NS2"
```

**Typical nameservers:**
- `bob.ns.cloudflare.com`
- `lola.ns.cloudflare.com`

(Names vary per domain)

### Step 3: Register Domain with Cloudflare Nameservers
```bash
# Get exact price first
PRICE=$(gcloud domains registrations get-register-parameters "$DOMAIN" \
  --format="value(yearlyPrice.units)")

# Register with custom nameservers
gcloud domains registrations register "$DOMAIN" \
  --contact-data-from-file=contact.yaml \
  --contact-privacy=private-contact-data \
  --yearly-price="${PRICE}.00 USD" \
  --name-servers="$NS1,$NS2" \
  --quiet
```

**What happens:**
1. Google Cloud Domains registers the domain
2. Domain is immediately configured with Cloudflare nameservers
3. Registration state: `REGISTRATION_PENDING` → `ACTIVE` (usually < 5 mins)
4. Cloudflare DNS is live immediately after activation

### Step 4: Verify Setup
```bash
# Check registration status
gcloud domains registrations describe "$DOMAIN"

# Verify nameservers propagated
dig NS "$DOMAIN" +short

# Check Cloudflare zone status
curl -X GET "https://api.cloudflare.com/client/v4/zones?name=$DOMAIN" \
  -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" | jq '.result[0].status'
```

**Expected:**
- Registration state: `ACTIVE`
- Nameservers: Match Cloudflare's assigned NS records
- Cloudflare zone status: `active` (once DNS propagates, ~24hrs max)

---

## Update Nameservers (Existing Domain)

If you registered first and need to change nameservers:

```bash
# Get Cloudflare nameservers (from Step 2 above)

# Update DNS settings
gcloud domains registrations configure dns "$DOMAIN" \
  --name-servers="$NS1,$NS2"
```

---

## Configure Cloudflare DNS Records

After registration, add DNS records via Cloudflare:

```bash
ZONE_ID=$(curl -X GET "https://api.cloudflare.com/client/v4/zones?name=$DOMAIN" \
  -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" | jq -r '.result[0].id')

# Add A record (root domain)
curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records" \
  -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{
    "type": "A",
    "name": "@",
    "content": "192.0.2.1",
    "ttl": 3600,
    "proxied": true
  }'

# Add CNAME (www subdomain)
curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records" \
  -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{
    "type": "CNAME",
    "name": "www",
    "content": "'"$DOMAIN"'",
    "ttl": 3600,
    "proxied": true
  }'
```

---

## Transfer to Cloudflare Registrar (After 60 Days)

**ICANN 60-day lock:** New registrations cannot transfer registrar for 60 days.

**After 60 days:**

### 1. Unlock Domain at Google
```bash
# Get authorization code
gcloud domains registrations authorization-code get "$DOMAIN"
```

### 2. Initiate Transfer at Cloudflare
```bash
# Via Cloudflare dashboard:
# https://dash.cloudflare.com/registrar/transfer

# Or via API:
curl -X POST "https://api.cloudflare.com/client/v4/accounts/$CLOUDFLARE_ACCOUNT_ID/registrar/domains/$DOMAIN/transfer" \
  -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{
    "auth_code": "AUTH_CODE_FROM_GOOGLE"
  }'
```

**Benefits of Cloudflare Registrar:**
- At-cost pricing (no markup)
- Free WHOIS privacy
- Auto-renewal
- Integrated with Cloudflare dashboard

---

## Cost Summary

### Google Cloud Domains (During Registration)
- Domain price: Varies by TLD (~$12/year for .com)
- No markup, standard registry prices
- Renewal price: Same as registration

### Cloudflare Nameservers (Free)
- DNS hosting: Free (unlimited queries)
- CDN: Free tier available
- DDoS protection: Included

### Cloudflare Registrar (After Transfer)
- Domain price: At-cost, no markup (~$9.77/year for .com as of 2026)
- WHOIS privacy: Free
- Transfer fee: 1 year extension included

---

## Troubleshooting

### Registration Stuck in REGISTRATION_PENDING
```bash
# Check operation status
gcloud domains operations list --filter="registration:$DOMAIN"

# Get operation details
gcloud domains operations describe OPERATION_ID
```

**Common causes:**
- Payment verification delay
- Domain registry downtime
- ICANN email verification pending

### Cloudflare Zone Not Active
```bash
# Check nameserver propagation
dig NS "$DOMAIN" @8.8.8.8 +short
```

**Wait time:**
- Nameserver changes propagate within 24-48 hours
- Cloudflare detects changes automatically
- Zone status updates to `active` once confirmed

### Email Verification Required
- Google sends verification email to registrant
- Must verify within 15 days or domain becomes inactive
- Check spam folder for email from `no-reply@squarespace.com`

---

## Best Practices

1. **Always check availability first** — Don't create Cloudflare zone until confirmed available
2. **Save authorization codes** — Store in password manager for future transfers
3. **Use private WHOIS** — Always use `--contact-privacy=private-contact-data`
4. **Enable auto-renew** — Enabled by default, verify after registration
5. **Set calendar reminder** — Day 60 for Cloudflare Registrar transfer
6. **Test DNS immediately** — Add a TXT record and verify propagation
7. **Monitor email** — Watch for ICANN verification emails

---

## Bulk Registration Script

For multiple domains:

```bash
#!/bin/bash
# bulk-register.sh

DOMAINS=(
  "example1.com"
  "example2.com"
  "example3.com"
)

for DOMAIN in "${DOMAINS[@]}"; do
  echo "Processing $DOMAIN..."
  
  # Check availability
  if ! gcloud domains registrations search-domains "$DOMAIN" | grep -q "AVAILABLE"; then
    echo "  ❌ $DOMAIN not available"
    continue
  fi
  
  # Create Cloudflare zone
  ZONE_RESPONSE=$(curl -s -X POST "https://api.cloudflare.com/client/v4/zones" \
    -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
    -H "Content-Type: application/json" \
    --data "{\"account\":{\"id\":\"$CLOUDFLARE_ACCOUNT_ID\"},\"name\":\"$DOMAIN\",\"type\":\"full\"}")
  
  NS1=$(echo "$ZONE_RESPONSE" | jq -r '.result.name_servers[0]')
  NS2=$(echo "$ZONE_RESPONSE" | jq -r '.result.name_servers[1]')
  
  # Get price
  PRICE=$(gcloud domains registrations get-register-parameters "$DOMAIN" \
    --format="value(yearlyPrice.units)")
  
  # Register
  gcloud domains registrations register "$DOMAIN" \
    --contact-data-from-file=contact.yaml \
    --contact-privacy=private-contact-data \
    --yearly-price="${PRICE}.00 USD" \
    --name-servers="$NS1,$NS2" \
    --quiet \
    --async
  
  echo "  ✅ $DOMAIN registration initiated"
  sleep 2  # Rate limit courtesy
done

echo "Done! Check status with: gcloud domains operations list"
```

---

## Quick Reference

### Check Domain Status
```bash
gcloud domains registrations describe DOMAIN
```

### List All Registrations
```bash
gcloud domains registrations list
```

### Get Authorization Code (for transfer)
```bash
gcloud domains registrations authorization-code get DOMAIN
```

### Update Contact Info
```bash
gcloud domains registrations configure contacts DOMAIN \
  --contact-data-from-file=contact.yaml
```

### Renew Domain
```bash
# Auto-renewal is default, but to renew manually:
gcloud domains registrations renew DOMAIN
```

### Delete Registration (cancellation)
```bash
gcloud domains registrations delete DOMAIN
```

---

## API Equivalents (for programmatic integration)

All gcloud commands have REST API equivalents:

**Register domain:**
```bash
POST https://domains.googleapis.com/v1/projects/PROJECT_ID/locations/global/registrations:register
```

**Configure DNS:**
```bash
PATCH https://domains.googleapis.com/v1/projects/PROJECT_ID/locations/global/registrations/DOMAIN?updateMask=dnsSettings
```

**Full API docs:**
https://cloud.google.com/domains/docs/reference/rest

---

## Notes

- **ICANN verification:** Always required, verify email within 15 days
- **DNSSEC:** Disabled by default when using custom nameservers
- **Privacy:** Supported for .com, .net, .org (varies by TLD)
- **Pricing:** Check current prices with `get-register-parameters`
- **Billing:** Charges appear on Google Cloud billing account
- **Renewals:** Auto-renew is enabled by default
- **Grace period:** 30-45 days after expiration before deletion

---

## Security Notes

- **Store API tokens securely** — Use environment variables, never commit
- **Limit token permissions** — Cloudflare tokens should be zone-scoped
- **Enable 2FA** — On both Google Cloud and Cloudflare accounts
- **Audit regularly** — Check domain list monthly
- **Lock domains** — Consider registrar lock for critical domains
- **Monitor expiration** — Set alerts 60/30/7 days before renewal

---

## References

- Google Cloud Domains: https://cloud.google.com/domains/docs
- Cloudflare API: https://developers.cloudflare.com/api
- ICANN Transfer Policy: https://www.icann.org/resources/pages/transfer-policy-2016-06-01-en
- DNS Propagation Checker: https://dnschecker.org
