Namecheap is a useful site for purchasing and maintaining your domains. We wanted to test the ability to use its API for registering and renewing domains, as well as setting up host records after purchase. The API documentation has many request options, but not all the documentation is clear and previous attempts to use the API are imperfect. Through testing and reaching out to the Namecheap staff, we were able to figure out how to get around some of our obstacles and learned that some are currently unfixable.
The first step for working with Namecheap’s API was creating a sandbox account, so that we were not making any real purchases throughout the testing process. Creating the account and setting up the API was simple following the steps on the Namecheap API introduction page.
Before writing our own methods, we wanted to take advantage of python code that had already been written to work with the Namecheap API. We found Bemmu’s PyNamecheap code on GitHub. At first glance, we thought we would not need much else. However, it turned out the code needed some tweaks to work in all circumstances and didn’t have functions for all the requests we wanted.
We found Bemmu’s most useful functions to be the domains_getList function which returns a list of all the account’s domains as dictionaries, the domains_create function which works for purchasing non-premium domains, and the domains_dns_getHosts function which returns a list of host records for a given domain. The domains_getList function was especially helpful for renewing domains because the dictionaries contain information that allow us to know when the domain is expiring, whether it will be auto renewing, and if it is a premium domain.
Bemmu’s domains_getList function description, which shows all the keys each
dictionary returned contains.
One of the issues that we found in the PyNamecheap code comes from the way Bemmu splits a domain into its SLD and TLD. We realized that whenever it is required to enter the SLD and TLD separately, Bemmu uses the split() function on the ‘.’ character. However, this raises an error for any domains that have multiple dots, such as a co.uk domain. We replaced this part of the code using tldextract to ensure the SLD and TLD were accurate.
One of the edits we made to Bemmu’s code to account for domains that have multiple ‘.’ characters.
We later learned, however, that handling a co.uk domain this way still wouldn’t work for purchasing due to a Namecheap error. Even on the web interface, the purchase of a co.uk domain does not go through. This was confirmed by the Namecheap help staff to be an issue with the sandbox environment.
Another issue we found with Bemmu’s code is that the domains_create function doesn’t work for premium domains. This stems from a fluke with the Namecheap API that requires that you to input whether the domain is premium and give the correct price for registration and renewal of premium domains. Including the price is especially confusing in the sandbox environment because Namecheap sometimes shows incorrect renewal prices for a premium domain on its sandbox web interface. This issue is resolvable though. You can obtain the premium registration and renewal price from the namecheap.domains.check command. The check command also tells you whether the domain is available, so it is an important method to call when using the API to make purchases.
An example of what the namecheap.domains.check command returns (from the Namecheap API documentation).
To deal with premium domains, we created our own methods for registering and renewing domains that account for the requirements of premium domains. A function to renew domains was also necessary for non-premium domains because Bemmu’s code does not have one.
Unfortunately, if you want to check the price of a domain before purchasing or renewing, the check command doesn’t give the prices for non-premium domains. It instead returns 0 for premium registration and premium renewal price. To check non-premium prices we instead had to use the namecheap.users.getPricing command.
The response to this command was difficult to work with at first because there are a few parameters that are optional to input, but without them the amount of information returned slows the code and is difficult to process. This is easily resolved by including the ActionName parameter as either REGISTER or RENEW, entering the ProductName parameter as the TLD for the domain (NOT the entire domain), and using xmltodict to turn the xml response into a dictionary that is much easier to extract information from. Utilizing xmltodict also proved helpful for all the other API calls and allowed us to check success of a call by checking if the dictionary’s equals ‘OK’ or ‘ERROR’.
Our code to find the price to renew a domain for one year.
Another API call that caused issues initially was the domains.dns.setHosts command. It is important to note that with the setHosts call, all previous hosts are deleted, so we needed to enter the A and MX record in the same call in order for both to be saved. Bemmu’s code has a domains_dns_setHosts call for setting multiple hosts, but it did not work for us with setting up MX records. This is because Bemmu’s code appends a number to all parameters being passed into the API call so that the API knows which record each parameter corresponds to. For most parameters, this is the correct way to make the call. However, for EmailType (which should be set to MX for setting up an MX record), there should not be a number appended. This small change affects whether the MX record goes through or not. Although we could not use Bemmu’s code for setting our records, we still used the domains_dns_getHosts method to check that the host records were created.
Our code to properly set an A and MX record in a single call.
While there were clearly some bumps in the road, we found that the Namecheap API had all the necessary calls for working with domains the way we wished to–it just took further exploration to understand exactly how some of its functions work. We also learned that the Bemmu’s PyNamecheap code was a good place to start, but not enough to meet our specific needs. Hopefully our experience can help anyone else with a similar task.
All third-party trademarks referenced by Cofense whether in logo form, name form or product form, or otherwise, remain the property of their respective holders, and use of these trademarks in no way indicates any relationship between Cofense and the holders of the trademarks.