They told me there was no API. The dashboard was making one on every click.
I run a sports SaaS that sits behind a GoDaddy private-label reseller account. Over a thousand customer domains are managed inside GoDaddy’s DCC (Domain Control Center) reseller panel. As part of moving the whole platform behind Cloudflare, I needed to flip the www CNAME on every one of those domains. The naive plan was the one the GoDaddy docs imply: log into the panel, find each domain, edit the record by hand, save, repeat. With north of a thousand domains, that estimate came back at three to six months of dull clicking.
It was framed as manual because there is no API. Or rather, that is what every answer you find says. developer.godaddy.com exists, but it does not work for WWD private-label reseller accounts. The reseller program is a separate world, and the public developer API does not reach into it. So the official story is: no programmatic access, do it in the browser, one domain at a time.
That story is wrong in the way these stories are almost always wrong. “No API” meant “no documented public API.” The DCC web app itself is a JavaScript front end. It does not have magic powers a script cannot have. When you edit a DNS record in that panel and click save, the browser fires an HTTP request to a backend. Find that request, replay it with your own auth, and you have the API they said did not exist.
Watch the click
The whole method is one move: do the manual action once, with the network tab open, and read what the page actually sent.
Log into the DCC panel like normal. Navigate to a single domain’s DNS records. Open Chrome devtools, go to the Network tab, and filter to Fetch/XHR so you are only looking at API calls, not images and scripts. Then edit one record by hand. Change a www CNAME, click save, and watch what shows up.
The request that mattered went to:
domdns.api.secureserver.netNot godaddy.com, not developer.godaddy.com. A separate secureserver.net host that the reseller panel talks to behind the scenes. That host is the real DNS API. It just has no public documentation because it was never meant to be called by anyone except GoDaddy’s own front end.
Click on that request in devtools and read the three things that make it work: the method, the headers, and the body.
Read what makes it authenticate
The method was a PATCH. The body was a small JSON payload describing the DNS record being changed. Nothing exotic, the kind of shape you would design yourself if you were building a DNS editor:
{ "rtype": "cname", "guid": "<record-guid-from-GET>", "name": "www", "data": "<target-hostname>", "ttl": 3600}The guid is the internal identifier for the existing record; you get it from the GET call the panel fires when it loads a domain’s record list. Everything else is self-explanatory.
The auth is the part everyone assumes is the wall, and it is the part that turns out to be a cookie. Because you are already logged into the DCC panel, the browser is sending your session cookie with every one of these backend requests. The endpoint trusts that cookie. There is no separate OAuth dance, no API key you have to register for, no signed-request scheme. You authenticated once in the browser, and that session is good for the API.
The one non-obvious header was an app key:
x-app-key: DCC-DomainControllerThis is the front end identifying itself to the backend. The endpoint expects it. Leave it off and the call gets rejected even with a valid cookie. You would never guess this header from the outside, which is exactly why you watch a real request instead of trying to construct one from a spec. The spec does not exist. The real request is the spec.
So the full recipe to drive the endpoint yourself is:
PATCHtodomdns.api.secureserver.net- the session cookie copied straight out of the logged-in browser session
x-app-key: DCC-DomainController- the same JSON record body the panel sent
Replay it, then loop it
Once you have one request reproduced outside the browser, you have everything. Replay it as-is against a single domain and confirm it lands. The DNS record changes, the panel reflects it, no error. That is the proof. After that, the bulk version is not a research problem anymore, it is a for loop. You already have the list of domains, you have the cookie, you have the header, and you have the body template. Swap the domain and the target per iteration and let it run.
A proof run across 19 domains went clean on the first attempt. The path to the rest of the reseller portfolio is the same for loop, not three to six months of clicking. The thing that was supposedly impossible to automate turned into the least interesting part of the migration.
The trade-offs, said plainly
This is an undocumented endpoint, so be honest about what that means. GoDaddy can change the host, the header, or the body shape whenever they redeploy their panel, and they owe you no warning. There is no rate-limit contract you can rely on, so do not hammer it. A cookie-based session expires, so a long bulk run can outlive its own auth and you have to handle re-authentication. None of this is a reason not to use it. It is a reason to treat it as what it is: a private interface you are borrowing, not a stable contract you are entitled to. For a one-shot bulk migration, borrowing it is completely fine. For something you need to run forever, you would want to revisit whether the relationship supports a real reseller API tier.
There is also a credential-hygiene note. You are copying a live session cookie into a script. Treat it like the password it effectively is. Do not commit it, do not log it, and throw it away when the job is done.
Related
- The GoDaddy reseller Catch-22: the account with the domains has no API, the API account has no domains: why the public API couldn’t reach these domains and the internal endpoint was the only option
- A three-reviewer naming cascade for the string every domain will CNAME to forever: choosing the CNAME target value this script writes to every domain
- The runbook said the domain was in account A. It was in account B. Verify ownership before touching live DNS.: verifying domain ownership before scripting bulk DNS changes
- My whole provider split died instantly: keep a second DoH provider on hand: what to have ready when verifying DNS changes at scale