Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 33 additions & 21 deletions src/GodaddyWrapper/Client.DomainV2.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@ public partial class GoDaddyClient
/// <summary>
/// Get domain details for a specific domain (v2)
/// </summary>
/// <param name="customerId">Customer ID (UUID). Can be retrieved via RetrieveShopper with includes="customerId"</param>
/// <param name="domain">Domain name</param>
/// <param name="includes">Optional comma-separated list of additional fields to include (nameServers, contacts, etc.)</param>
/// <param name="XShopperId">Shopper ID to be operated on, if different from JWT</param>
/// <returns>Domain details</returns>
public async Task<DomainDetailResponse> GetDomainV2(string domain, string includes = null, string XShopperId = null)
public async Task<DomainDetailResponse> GetDomainV2(string customerId, string domain, string includes = null, string XShopperId = null)
{
if (XShopperId != null)
httpClient.DefaultRequestHeaders.Add("X-Shopper-Id", XShopperId);
Expand All @@ -32,14 +33,15 @@ public async Task<DomainDetailResponse> GetDomainV2(string domain, string includ
queryParams.Add("includes", includes);

var queryString = QueryStringBuilder.DictionaryToQueryString(queryParams);
var response = await httpClient.GetAsync($"{V2_BASE}customers/{{customerId}}/domains/{domain}{queryString}");
var response = await httpClient.GetAsync($"{V2_BASE}customers/{customerId}/domains/{domain}{queryString}");
await CheckResponseMessageIsValid(response);
return await response.Content.ReadAsAsync<DomainDetailResponse>(JsonSettings);
}

/// <summary>
/// List domains for a customer (v2)
/// </summary>
/// <param name="customerId">Customer ID (UUID). Can be retrieved via RetrieveShopper with includes="customerId"</param>
/// <param name="statuses">Filter by domain status (ACTIVE, PENDING, etc.)</param>
/// <param name="statusGroups">Filter by domain status groups</param>
/// <param name="limit">Maximum number of domains to return (default 1000)</param>
Expand All @@ -48,6 +50,7 @@ public async Task<DomainDetailResponse> GetDomainV2(string domain, string includ
/// <param name="XShopperId">Shopper ID to be operated on, if different from JWT</param>
/// <returns>List of domains</returns>
public async Task<DomainListV2Response> ListDomainsV2(
string customerId,
string statuses = null,
string statusGroups = null,
int? limit = null,
Expand All @@ -71,41 +74,43 @@ public async Task<DomainListV2Response> ListDomainsV2(
queryParams.Add("includes", includes);

var queryString = QueryStringBuilder.DictionaryToQueryString(queryParams);
var response = await httpClient.GetAsync($"{V2_BASE}customers/{{customerId}}/domains{queryString}");
var response = await httpClient.GetAsync($"{V2_BASE}customers/{customerId}/domains{queryString}");
await CheckResponseMessageIsValid(response);
return await response.Content.ReadAsAsync<DomainListV2Response>(JsonSettings);
}

/// <summary>
/// Update domain details (v2)
/// </summary>
/// <param name="customerId">Customer ID (UUID). Can be retrieved via RetrieveShopper with includes="customerId"</param>
/// <param name="domain">Domain name</param>
/// <param name="request">Domain update request</param>
/// <param name="XShopperId">Shopper ID to be operated on, if different from JWT</param>
/// <returns>Success status</returns>
public async Task<bool> UpdateDomainV2(string domain, DomainUpdateV2 request, string XShopperId = null)
public async Task<bool> UpdateDomainV2(string customerId, string domain, DomainUpdateV2 request, string XShopperId = null)
{
CheckRequestValid(request);
if (XShopperId != null)
httpClient.DefaultRequestHeaders.Add("X-Shopper-Id", XShopperId);

var response = await httpClient.PatchAsJsonAsync($"{V2_BASE}customers/{{customerId}}/domains/{domain}", request, JsonSettings);
var response = await httpClient.PatchAsJsonAsync($"{V2_BASE}customers/{customerId}/domains/{domain}", request, JsonSettings);
await CheckResponseMessageIsValid(response);
return response.IsSuccessStatusCode;
}

/// <summary>
/// Cancel domain (v2)
/// </summary>
/// <param name="customerId">Customer ID (UUID). Can be retrieved via RetrieveShopper with includes="customerId"</param>
/// <param name="domain">Domain name</param>
/// <param name="XShopperId">Shopper ID to be operated on, if different from JWT</param>
/// <returns>Success status</returns>
public async Task<bool> CancelDomainV2(string domain, string XShopperId = null)
public async Task<bool> CancelDomainV2(string customerId, string domain, string XShopperId = null)
{
if (XShopperId != null)
httpClient.DefaultRequestHeaders.Add("X-Shopper-Id", XShopperId);

var response = await httpClient.DeleteAsync($"{V2_BASE}customers/{{customerId}}/domains/{domain}");
var response = await httpClient.DeleteAsync($"{V2_BASE}customers/{customerId}/domains/{domain}");
await CheckResponseMessageIsValid(response);
return response.IsSuccessStatusCode;
}
Expand Down Expand Up @@ -134,52 +139,55 @@ public async Task<DomainAvailabilityV2Response> CheckDomainAvailabilityV2(string
/// <summary>
/// Purchase a domain (v2)
/// </summary>
/// <param name="customerId">Customer ID (UUID). Can be retrieved via RetrieveShopper with includes="customerId"</param>
/// <param name="request">Domain purchase request</param>
/// <param name="XShopperId">Shopper ID to be operated on, if different from JWT</param>
/// <returns>Domain purchase response</returns>
public async Task<DomainPurchaseV2Response> PurchaseDomainV2(DomainPurchaseV2 request, string XShopperId = null)
public async Task<DomainPurchaseV2Response> PurchaseDomainV2(string customerId, DomainPurchaseV2 request, string XShopperId = null)
{
CheckRequestValid(request);
if (XShopperId != null)
httpClient.DefaultRequestHeaders.Add("X-Shopper-Id", XShopperId);

var response = await httpClient.PostAsJsonAsync($"{V2_BASE}customers/{{customerId}}/domains/purchase", request, JsonSettings);
var response = await httpClient.PostAsJsonAsync($"{V2_BASE}customers/{customerId}/domains/purchase", request, JsonSettings);
await CheckResponseMessageIsValid(response);
return await response.Content.ReadAsAsync<DomainPurchaseV2Response>(JsonSettings);
}

/// <summary>
/// Renew a domain (v2)
/// </summary>
/// <param name="customerId">Customer ID (UUID). Can be retrieved via RetrieveShopper with includes="customerId"</param>
/// <param name="domain">Domain name</param>
/// <param name="request">Domain renewal request</param>
/// <param name="XShopperId">Shopper ID to be operated on, if different from JWT</param>
/// <returns>Domain purchase response</returns>
public async Task<DomainPurchaseV2Response> RenewDomainV2(string domain, DomainRenewV2 request, string XShopperId = null)
public async Task<DomainPurchaseV2Response> RenewDomainV2(string customerId, string domain, DomainRenewV2 request, string XShopperId = null)
{
CheckRequestValid(request);
if (XShopperId != null)
httpClient.DefaultRequestHeaders.Add("X-Shopper-Id", XShopperId);

var response = await httpClient.PostAsJsonAsync($"{V2_BASE}customers/{{customerId}}/domains/{domain}/renew", request, JsonSettings);
var response = await httpClient.PostAsJsonAsync($"{V2_BASE}customers/{customerId}/domains/{domain}/renew", request, JsonSettings);
await CheckResponseMessageIsValid(response);
return await response.Content.ReadAsAsync<DomainPurchaseV2Response>(JsonSettings);
}

/// <summary>
/// Get DNS records for a domain (v2)
/// </summary>
/// <param name="customerId">Customer ID (UUID). Can be retrieved via RetrieveShopper with includes="customerId"</param>
/// <param name="domain">Domain name</param>
/// <param name="type">Record type filter (A, CNAME, MX, etc.)</param>
/// <param name="name">Record name filter</param>
/// <param name="XShopperId">Shopper ID to be operated on, if different from JWT</param>
/// <returns>List of DNS records</returns>
public async Task<List<DNSRecordResponse>> GetDNSRecordsV2(string domain, string type = null, string name = null, string XShopperId = null)
public async Task<List<DNSRecordResponse>> GetDNSRecordsV2(string customerId, string domain, string type = null, string name = null, string XShopperId = null)
{
if (XShopperId != null)
httpClient.DefaultRequestHeaders.Add("X-Shopper-Id", XShopperId);

var path = $"{V2_BASE}customers/{{customerId}}/domains/{domain}/records";
var path = $"{V2_BASE}customers/{customerId}/domains/{domain}/records";
if (!string.IsNullOrEmpty(type))
{
path += $"/{type}";
Expand All @@ -195,70 +203,74 @@ public async Task<List<DNSRecordResponse>> GetDNSRecordsV2(string domain, string
/// <summary>
/// Replace all DNS records for a domain (v2)
/// </summary>
/// <param name="customerId">Customer ID (UUID). Can be retrieved via RetrieveShopper with includes="customerId"</param>
/// <param name="domain">Domain name</param>
/// <param name="records">List of DNS records</param>
/// <param name="XShopperId">Shopper ID to be operated on, if different from JWT</param>
/// <returns>Success status</returns>
public async Task<bool> ReplaceDNSRecordsV2(string domain, List<DNSRecord> records, string XShopperId = null)
public async Task<bool> ReplaceDNSRecordsV2(string customerId, string domain, List<DNSRecord> records, string XShopperId = null)
{
CheckRequestValid(records);
if (XShopperId != null)
httpClient.DefaultRequestHeaders.Add("X-Shopper-Id", XShopperId);

var response = await httpClient.PutAsJsonAsync($"{V2_BASE}customers/{{customerId}}/domains/{domain}/records", records, JsonSettings);
var response = await httpClient.PutAsJsonAsync($"{V2_BASE}customers/{customerId}/domains/{domain}/records", records, JsonSettings);
await CheckResponseMessageIsValid(response);
return response.IsSuccessStatusCode;
}

/// <summary>
/// Add DNS records to a domain (v2)
/// </summary>
/// <param name="customerId">Customer ID (UUID). Can be retrieved via RetrieveShopper with includes="customerId"</param>
/// <param name="domain">Domain name</param>
/// <param name="records">List of DNS records to add</param>
/// <param name="XShopperId">Shopper ID to be operated on, if different from JWT</param>
/// <returns>Success status</returns>
public async Task<bool> AddDNSRecordsV2(string domain, List<DNSRecord> records, string XShopperId = null)
public async Task<bool> AddDNSRecordsV2(string customerId, string domain, List<DNSRecord> records, string XShopperId = null)
{
CheckRequestValid(records);
if (XShopperId != null)
httpClient.DefaultRequestHeaders.Add("X-Shopper-Id", XShopperId);

var response = await httpClient.PatchAsJsonAsync($"{V2_BASE}customers/{{customerId}}/domains/{domain}/records", records, JsonSettings);
var response = await httpClient.PatchAsJsonAsync($"{V2_BASE}customers/{customerId}/domains/{domain}/records", records, JsonSettings);
await CheckResponseMessageIsValid(response);
return response.IsSuccessStatusCode;
}

/// <summary>
/// Update contacts for a domain (v2)
/// </summary>
/// <param name="customerId">Customer ID (UUID). Can be retrieved via RetrieveShopper with includes="customerId"</param>
/// <param name="domain">Domain name</param>
/// <param name="request">Domain contacts update request</param>
/// <param name="XShopperId">Shopper ID to be operated on, if different from JWT</param>
/// <returns>Success status</returns>
public async Task<bool> UpdateDomainContactsV2(string domain, DomainContactsV2 request, string XShopperId = null)
public async Task<bool> UpdateDomainContactsV2(string customerId, string domain, DomainContactsV2 request, string XShopperId = null)
{
CheckRequestValid(request);
if (XShopperId != null)
httpClient.DefaultRequestHeaders.Add("X-Shopper-Id", XShopperId);

var response = await httpClient.PatchAsJsonAsync($"{V2_BASE}customers/{{customerId}}/domains/{domain}/contacts", request, JsonSettings);
var response = await httpClient.PatchAsJsonAsync($"{V2_BASE}customers/{customerId}/domains/{domain}/contacts", request, JsonSettings);
await CheckResponseMessageIsValid(response);
return response.IsSuccessStatusCode;
}

/// <summary>
/// Transfer a domain in (v2)
/// </summary>
/// <param name="customerId">Customer ID (UUID). Can be retrieved via RetrieveShopper with includes="customerId"</param>
/// <param name="request">Domain transfer request</param>
/// <param name="XShopperId">Shopper ID to be operated on, if different from JWT</param>
/// <returns>Domain transfer response</returns>
public async Task<DomainTransferV2Response> TransferDomainV2(DomainTransferV2 request, string XShopperId = null)
public async Task<DomainTransferV2Response> TransferDomainV2(string customerId, DomainTransferV2 request, string XShopperId = null)
{
CheckRequestValid(request);
if (XShopperId != null)
httpClient.DefaultRequestHeaders.Add("X-Shopper-Id", XShopperId);

var response = await httpClient.PostAsJsonAsync($"{V2_BASE}customers/{{customerId}}/domains/transfer", request, JsonSettings);
var response = await httpClient.PostAsJsonAsync($"{V2_BASE}customers/{customerId}/domains/transfer", request, JsonSettings);
await CheckResponseMessageIsValid(response);
return await response.Content.ReadAsAsync<DomainTransferV2Response>(JsonSettings);
}
Expand Down
8 changes: 6 additions & 2 deletions src/GodaddyWrapper/Client.Shopper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,15 @@ public async Task<ShopperIdResponse> CreateSubaccount(SubaccountCreate request)
/// Get details for the specified Shopper
/// </summary>
/// <param name="request"></param>
/// <param name="includes">Optional comma-separated list of additional fields (e.g., "customerId")</param>
/// <returns></returns>
public async Task<ShopperResponse> RetrieveShopper(ShopperRetrieve request)
public async Task<ShopperResponse> RetrieveShopper(ShopperRetrieve request, string includes = null)
{
CheckRequestValid(request);
var response = await httpClient.GetAsync($"{V1_BASE}shoppers/{request.ShopperId}");
var url = $"{V1_BASE}shoppers/{request.ShopperId}";
if (!string.IsNullOrEmpty(includes))
url += $"?includes={includes}";
var response = await httpClient.GetAsync(url);
await CheckResponseMessageIsValid(response);
return await response.Content.ReadAsAsync<ShopperResponse>(JsonSettings);
}
Expand Down
1 change: 1 addition & 0 deletions src/GodaddyWrapper/Responses/ShopperResponse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ namespace GodaddyWrapper.Responses
public class ShopperResponse
{
public string ShopperId { get; set; }
public string CustomerId { get; set; }
public string NameFirst { get; set; }
public string NameLast { get; set; }
public string Email { get; set; }
Expand Down
23 changes: 20 additions & 3 deletions src/V2_IMPLEMENTATION_SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,14 @@ All existing v1 methods remain unchanged and functional:

## Usage Examples

### Getting Customer ID
Before using v2 domain endpoints, you need to retrieve the customer ID:
```csharp
var client = new GoDaddyClient(options);
var shopper = await client.RetrieveShopper(new ShopperRetrieve { ShopperId = "12345" }, includes: "customerId");
string customerId = shopper.CustomerId; // UUID like "295e3bc3-a3b9-4d95-aae5-edf41a994d13"
```

### Using v1 API (existing code):
```csharp
var client = new GoDaddyClient(options);
Expand All @@ -112,17 +120,25 @@ var domain = await client.CheckDomainAvailable(new DomainAvailable { domain = "e
### Using v2 API (new methods):
```csharp
var client = new GoDaddyClient(options);

// First, get the customer ID
var shopper = await client.RetrieveShopper(new ShopperRetrieve { ShopperId = "12345" }, includes: "customerId");
string customerId = shopper.CustomerId;

// Now use v2 endpoints
var availability = await client.CheckDomainAvailabilityV2("example.com");
var domains = await client.ListDomainsV2(statuses: "ACTIVE", limit: 100);
var domains = await client.ListDomainsV2(customerId, statuses: "ACTIVE", limit: 100);
var domainDetails = await client.GetDomainV2(customerId, "example.com");
```

## Key Differences: v1 vs v2

### Domain Endpoints
- **v2** uses `/v2/customers/{customerId}/domains/` structure
- **v2** uses `/v2/customers/{customerId}/domains/` structure and requires customerId parameter
- **v2** supports enhanced filtering with `includes` parameter
- **v2** has improved pagination with markers
- **v2** includes consent tracking for purchases
- **customerId** is a UUID that must be retrieved via `RetrieveShopper` with `includes="customerId"`

### Response Enhancements
- More detailed status information
Expand All @@ -148,6 +164,7 @@ All code has been validated:

## Notes

- The v2 endpoints use placeholder `{customerId}` in paths - this should be replaced with actual customer ID in production use
- All v2 domain endpoints require a `customerId` (UUID) parameter
- The `customerId` can be retrieved by calling `RetrieveShopper` with `includes="customerId"` parameter
- Some v2 endpoints may require additional authentication or permissions
- Consult GoDaddy API documentation for specific v2 endpoint requirements