{"id":19366,"date":"2026-10-30T09:14:03","date_gmt":"2026-10-30T09:14:03","guid":{"rendered":"https:\/\/truehost.com\/support\/?post_type=docs&#038;p=19366"},"modified":"2026-11-03T09:33:05","modified_gmt":"2026-11-03T09:33:05","password":"","slug":"truehost-domains-reseller-api","status":"publish","type":"docs","link":"https:\/\/truehost.com\/support\/knowledge-base\/truehost-domains-reseller-api\/","title":{"rendered":"Truehost Domains Reseller API"},"content":{"rendered":"\n<p><strong>Reference for integrating domain registration into your own website or software<\/strong><\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><\/td><td><\/td><\/tr><tr><td>Version<\/td><td>1.0 (October 2026)<\/td><\/tr><tr><td>Protocol<\/td><td>HTTPS, REST-style paths<\/td><\/tr><tr><td>Request format<\/td><td>application\/x-www-form-urlencoded<\/td><\/tr><tr><td>Response format<\/td><td>JSON (one exception:<a href=\"https:\/\/claude.ai\/chat\/49748676-241b-4d96-9e39-4f1578022604#post-domainslookup\"> domain lookup<\/a>)<\/td><\/tr><tr><td>Authentication<\/td><td>Username plus an hourly HMAC-SHA256 token<\/td><\/tr><tr><td>Time zone<\/td><td>UTC for all times<\/td><\/tr><tr><td>Standards<\/td><td>ISO 8601 dates, ISO 3166-1 alpha-2 country codes, ITU-T E.164 phone numbers, IDNA 2008 (Punycode) for internationalised names<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>This is for: developers at a Truehost reseller who want to register, transfer, renew and manage domains from their own system, without WHMCS or the Truehost Reseller Panel. If you use either, use its Truehost module instead; it makes these calls for you, and the panel&#8217;s module also keeps your extension prices in step with your price list.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Contents<\/strong><\/h2>\n\n\n\n<div class=\"table-of-contents\">\n  <h2>Table of Contents<\/h2>\n\n  <ol>\n    <li><a href=\"#before-you-start\">Before you start<\/a><\/li>\n    <li><a href=\"#base-url\">Base URL<\/a><\/li>\n    <li><a href=\"#authentication\">Authentication<\/a><\/li>\n    <li><a href=\"#requests\">Requests<\/a><\/li>\n    <li><a href=\"#responses-errors\">Responses and errors<\/a><\/li>\n    <li><a href=\"#endpoint-summary\">Endpoint summary<\/a><\/li>\n    <li><a href=\"#account\">Account<\/a><\/li>\n    <li><a href=\"#availability\">Availability<\/a><\/li>\n    <li><a href=\"#orders\">Orders<\/a><\/li>\n    <li><a href=\"#domain-status\">Domain status<\/a><\/li>\n    <li><a href=\"#nameservers\">Nameservers<\/a><\/li>\n    <li><a href=\"#child-nameservers\">Child nameservers (glue records)<\/a><\/li>\n    <li><a href=\"#transfer-lock-epp-code\">Transfer lock and EPP code<\/a><\/li>\n    <li><a href=\"#contacts-whois-privacy\">Contacts and WHOIS privacy<\/a><\/li>\n    <li><a href=\"#dns-email-forwarding\">DNS and email forwarding<\/a><\/li>\n    <li><a href=\"#release-deletion\">Release and deletion<\/a><\/li>\n    <li><a href=\"#data-formats\">Data formats<\/a><\/li>\n    <li><a href=\"#code-examples\">Code examples<\/a><\/li>\n    <li><a href=\"#integration-flow\">Recommended integration flow<\/a><\/li>\n    <li><a href=\"#troubleshooting\">Troubleshooting<\/a><\/li>\n  <\/ol>\n<\/div>\n\n\n\n<h2 id=\"before-you-start\">1. Before you start<\/h2>\n\n\n\n\n<p>You need:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><strong>Item<\/strong><\/td><td><strong>Where to get it<\/strong><\/td><\/tr><tr><td>A <strong>reseller account<\/strong> on a Truehost site, for example truehost.cloud or truehost.co.ke<\/td><td>Sign up on that site and ask Truehost to switch on domain reselling<\/td><\/tr><tr><td>Your <strong>API username<\/strong><\/td><td>The email address you log in to that site with<\/td><\/tr><tr><td>Your <strong>API key<\/strong><\/td><td>That site&#8217;s client area \u2192 <strong>Domains Reseller<\/strong> \u2192 <strong>API settings<\/strong><\/td><\/tr><tr><td>A <strong>reseller balance<\/strong><\/td><td>Top up in the same client area. Every registration, transfer and renewal is paid from it<\/td><\/tr><tr><td>A server with an <strong>accurate clock<\/strong><\/td><td>Use NTP. The token changes every hour (see<a href=\"https:\/\/claude.ai\/chat\/49748676-241b-4d96-9e39-4f1578022604#3-authentication\"> Authentication<\/a>)<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p><strong>Each Truehost site is separate.<\/strong> Accounts, API keys, balances and price lists are not shared between sites. Always call the site where your reseller account was opened, with the key issued by that site.<\/p>\n\n\n\n<p><strong>Keep the API key on your server.<\/strong> Never put it in a browser, mobile app or public repository. Anyone with the key can spend your balance.<\/p>\n\n\n\n<h2 id=\"base-url\">2. Base URL<\/h2>\n\n\n\n\n<p><a href=\"https:\/\/{site}\/cloud\/modules\/addons\/DomainsReseller\/api\/index.php\">https:\/\/{site}\/cloud\/modules\/addons\/DomainsReseller\/api\/index.php<\/a><\/p>\n\n\n\n<p>{site} is the Truehost site of your reseller account. Examples:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><strong>Site<\/strong><\/td><td><strong>Base URL<\/strong><\/td><\/tr><tr><td>truehost.cloud<\/td><td>https:\/\/truehost.cloud\/cloud\/modules\/addons\/DomainsReseller\/api\/index.php<\/td><\/tr><tr><td>truehost.co.ke<\/td><td>https:\/\/truehost.co.ke\/cloud\/modules\/addons\/DomainsReseller\/api\/index.php<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>Every endpoint is appended to the base URL with a \/. For example, the balance endpoint on truehost.cloud is:<\/p>\n\n\n\n<p><a href=\"https:\/\/truehost.cloud\/cloud\/modules\/addons\/DomainsReseller\/api\/index.php\/billing\/credits\">https:\/\/truehost.cloud\/cloud\/modules\/addons\/DomainsReseller\/api\/index.php\/billing\/credits<\/a><\/p>\n\n\n\n<p>In this document, {BASE} means the base URL and {domain} means a domain name such as example.co.ke.<\/p>\n\n\n\n<h2 id=\"authenication\">3. Authentication<\/h2>\n\n\n\n\n<p>Send these two HTTP headers with <strong>every<\/strong> request:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><strong>Header<\/strong><\/td><td><strong>Value<\/strong><\/td><\/tr><tr><td>username<\/td><td>Your API username (login email)<\/td><\/tr><tr><td>token<\/td><td>The hourly token described below<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Building the token<\/strong><\/h3>\n\n\n\n<p>hour&nbsp; = current UTC time formatted as &#8220;yy-mm-dd HH&#8221; &nbsp; &nbsp; e.g. &#8220;26-10-26 14&#8221;<\/p>\n\n\n\n<p>key &nbsp; = username + &#8220;:&#8221; + hour &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; e.g. &#8220;reseller@example.com:26-10-26 14&#8221;<\/p>\n\n\n\n<p>hex &nbsp; = HMAC-SHA256(message = API key, key = key), as lowercase hexadecimal<\/p>\n\n\n\n<p>token = Base64(hex)<\/p>\n\n\n\n<p>Note the details that are easy to get wrong:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>The <strong>API key is the message<\/strong> and username:hour is the <strong>HMAC key<\/strong>.<\/li>\n\n\n\n<li>The hour uses a <strong>two-digit year<\/strong>, a <strong>space<\/strong>, and the <strong>24-hour clock<\/strong> in <strong>UTC<\/strong>.<\/li>\n\n\n\n<li>Base64 is applied to the <strong>64-character hex string<\/strong>, not to the raw 32-byte digest.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Test vector<\/strong><\/h3>\n\n\n\n<p>Check your implementation against these values (sample credentials, not real ones):<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><strong>Input<\/strong><\/td><td><strong>Value<\/strong><\/td><\/tr><tr><td>username<\/td><td>reseller@example.com<\/td><\/tr><tr><td>API key<\/td><td>EXAMPLE-API-KEY-123<\/td><\/tr><tr><td>UTC hour<\/td><td>26-10-26 14 (14:00\u201314:59 UTC on 26 October 2026)<\/td><\/tr><tr><td>hex<\/td><td>c57336cac850d7b04d27cf524932d3804fa2f2fdb8a8c54f34341fb99843bbdf<\/td><\/tr><tr><td><strong>token<\/strong><\/td><td>YzU3MzM2Y2FjODUwZDdiMDRkMjdjZjUyNDkzMmQzODA0ZmEyZjJmZGI4YThjNTRmMzQzNDFmYjk5ODQzYmJkZg==<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>Generate a fresh token for each request, or at least each hour. A server clock that is wrong by an hour or more makes every request fail with <em>token is invalid<\/em>.<\/p>\n\n\n\n<h2 id=\"requests\">4. Requests<\/h2>\n\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><strong>Rule<\/strong><\/td><td><strong>Detail<\/strong><\/td><\/tr><tr><td>Methods<\/td><td>GET to read, POST to change or order<\/td><\/tr><tr><td>GET<\/td><td>No body and no query parameters. Everything is in the path<\/td><\/tr><tr><td>POST<\/td><td>Body encoded as application\/x-www-form-urlencoded<\/td><\/tr><tr><td>Lists and objects<\/td><td>PHP bracket notation: nameservers[0]=ns1.example.com, contacts[registrant][firstname]=Jane<\/td><\/tr><tr><td>Domain in the path<\/td><td>Lowercase ASCII. Internationalised names in Punycode (xn--\u2026). URL-encode the value<\/td><\/tr><tr><td>Domain in the body<\/td><td>Domain endpoints that take a body also expect domain, with the same value as in the path<\/td><\/tr><tr><td>Redirects<\/td><td>Do not follow redirects. A redirect turns a POST into a GET<\/td><\/tr><tr><td>Timeouts<\/td><td>Allow at least 60 seconds for orders. Registries can be slow<\/td><\/tr><tr><td>Character set<\/td><td>UTF-8<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>Example of a form body with nested values:<\/p>\n\n\n\n<p>domain=example.co.ke&amp;regperiod=1&amp;nameservers%5B0%5D=ns1.example.com&amp;nameservers%5B1%5D=ns2.example.com&amp;addons%5Bidprotection%5D=1<\/p>\n\n\n\n<h2 id=\"response-and-errors\">5.Response and Errors <\/h2>\n\n\n\n\n<p>Responses are JSON. Treat a response as <strong>failed<\/strong> if any of these is true:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>The HTTP status is 400 or higher.<\/li>\n\n\n\n<li>The body has a non-empty error field: {&#8220;error&#8221;: &#8220;Domain name is invalid&#8221;}.<\/li>\n\n\n\n<li>The body has &#8220;result&#8221;: &#8220;error&#8221; (the reason is in message).<\/li>\n\n\n\n<li>The body has &#8220;success&#8221;: false (the reason is in message).<\/li>\n\n\n\n<li>The body is empty when you expected data, or is not valid JSON (an HTML page means a proxy or server error).<\/li>\n<\/ol>\n\n\n\n<p>Otherwise the call succeeded. A successful change usually answers {&#8220;success&#8221;: true}; a successful read answers the data.<\/p>\n\n\n\n<p>Do not treat &#8220;no error field&#8221; alone as success. A server error page has no error field either. Apply all five rules.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Common error messages<\/strong><\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><strong>HTTP<\/strong><\/td><td><strong>Message contains<\/strong><\/td><td><strong>Meaning<\/strong><\/td><td><strong>What to do<\/strong><\/td><\/tr><tr><td>401<\/td><td>Username has not been provided<\/td><td>The username header is missing<\/td><td>Send both headers<\/td><\/tr><tr><td>401<\/td><td>username is invalid<\/td><td>This site has no reseller account with that username<\/td><td>Use the site where your account was opened, and your login email<\/td><\/tr><tr><td>401<\/td><td>token is invalid<\/td><td>Wrong API key, key from another site, or clock off<\/td><td>Copy the key again from this site; check the server clock (UTC)<\/td><\/tr><tr><td>\u2014<\/td><td>Action not found<\/td><td>The endpoint path is wrong<\/td><td>Check the path and method<\/td><\/tr><tr><td>\u2014<\/td><td>not been found in reseller account<\/td><td>The domain is not in your reseller account<\/td><td>Check the spelling, or register or transfer it first<\/td><\/tr><tr><td>\u2014<\/td><td>Provided domain period is unavailable for sale<\/td><td>The extension is not in your price list, or not for that number of years<\/td><td>Check<a href=\"https:\/\/claude.ai\/chat\/49748676-241b-4d96-9e39-4f1578022604#get-tldspricing\"> GET tlds\/pricing<\/a><\/td><\/tr><tr><td>\u2014<\/td><td>balance or credit messages<\/td><td>Not enough balance<\/td><td>Top up, then retry<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>Some error messages include the IP address the API sees (Your IP is: \u2026). If your API settings restrict access by IP address, that IP must be allowed.<\/p>\n\n\n\n<h2 id=\"endpoint-summary\">6.Endpoint Summary <\/h2>\n\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><strong>Method<\/strong><\/td><td><strong>Endpoint<\/strong><\/td><td><strong>Purpose<\/strong><\/td><\/tr><tr><td>GET<\/td><td>\/billing\/credits<\/td><td>Reseller balance<\/td><\/tr><tr><td>GET<\/td><td>\/tlds\/pricing<\/td><td>Your price list per extension<\/td><\/tr><tr><td>POST<\/td><td>\/domains\/lookup<\/td><td>Check availability<\/td><\/tr><tr><td>POST<\/td><td>\/order\/domains\/register<\/td><td>Register a domain<\/td><\/tr><tr><td>POST<\/td><td>\/order\/domains\/transfer<\/td><td>Transfer a domain in<\/td><\/tr><tr><td>POST<\/td><td>\/order\/domains\/renew<\/td><td>Renew a domain<\/td><\/tr><tr><td>POST<\/td><td>\/domains\/{domain}\/sync<\/td><td>Expiry date and status<\/td><\/tr><tr><td>POST<\/td><td>\/domains\/{domain}\/transfersync<\/td><td>Transfer progress<\/td><\/tr><tr><td>GET<\/td><td>\/domains\/{domain}\/nameservers<\/td><td>Read nameservers<\/td><\/tr><tr><td>POST<\/td><td>\/domains\/{domain}\/nameservers<\/td><td>Change nameservers<\/td><\/tr><tr><td>POST<\/td><td>\/domains\/{domain}\/nameservers\/register<\/td><td>Create a child nameserver<\/td><\/tr><tr><td>POST<\/td><td>\/domains\/{domain}\/nameservers\/modify<\/td><td>Change a child nameserver&#8217;s IP<\/td><\/tr><tr><td>POST<\/td><td>\/domains\/{domain}\/nameservers\/delete<\/td><td>Delete a child nameserver<\/td><\/tr><tr><td>GET<\/td><td>\/domains\/{domain}\/lock<\/td><td>Read the transfer lock<\/td><\/tr><tr><td>POST<\/td><td>\/domains\/{domain}\/lock<\/td><td>Set the transfer lock<\/td><\/tr><tr><td>GET<\/td><td>\/domains\/{domain}\/eppcode<\/td><td>Get the EPP (auth) code<\/td><\/tr><tr><td>GET<\/td><td>\/domains\/{domain}\/contact<\/td><td>Read WHOIS contacts<\/td><\/tr><tr><td>POST<\/td><td>\/domains\/{domain}\/contact<\/td><td>Change WHOIS contacts<\/td><\/tr><tr><td>POST<\/td><td>\/domains\/{domain}\/protectid<\/td><td>WHOIS privacy on or off<\/td><\/tr><tr><td>GET<\/td><td>\/domains\/{domain}\/dns<\/td><td>Read DNS records (DNS management add-on)<\/td><\/tr><tr><td>POST<\/td><td>\/domains\/{domain}\/dns<\/td><td>Save DNS records<\/td><\/tr><tr><td>GET<\/td><td>\/domains\/{domain}\/email<\/td><td>Read email forwarding<\/td><\/tr><tr><td>POST<\/td><td>\/domains\/{domain}\/email<\/td><td>Save email forwarding<\/td><\/tr><tr><td>POST<\/td><td>\/domains\/{domain}\/release<\/td><td>Release to another registrar by tag (.uk and similar)<\/td><\/tr><tr><td>POST<\/td><td>\/domains\/{domain}\/delete<\/td><td>Request deletion<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>The response examples below show the fields you should read. Responses can contain more fields than shown; ignore the ones you don&#8217;t need.<\/p>\n\n\n\n<h2 id=\"account\">7. Account<\/h2>\n\n\n\n\n<h3 class=\"wp-block-heading\"><strong>GET \/billing\/credits<\/strong><\/h3>\n\n\n\n<p>Your reseller balance, in your account&#8217;s currency on that site. Use it as a connection test: it changes nothing.<\/p>\n\n\n\n<p><strong>Request<\/strong><\/p>\n\n\n\n<p>GET {BASE}\/billing\/credits<\/p>\n\n\n\n<p><strong>Response<\/strong><\/p>\n\n\n\n<p>{ &#8220;credits&#8221;: &#8220;1520.00&#8221; }<\/p>\n\n\n\n<p>The amount can also arrive as credit or balance, or as a bare number. Read it as a decimal.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>GET \/tlds\/pricing<\/strong><\/h3>\n\n\n\n<p>The extensions you can sell, with your cost for each, from your reseller price list.<\/p>\n\n\n\n<p><strong>Request<\/strong><\/p>\n\n\n\n<p>GET {BASE}\/tlds\/pricing<\/p>\n\n\n\n<p><strong>Response<\/strong>: a list, one entry per extension <strong>and currency<\/strong>:<\/p>\n\n\n\n<p>[<\/p>\n\n\n\n<p>&nbsp;&nbsp;{<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&#8220;tld&#8221;: &#8220;.co.ke&#8221;,<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&#8220;years&#8221;: [1],<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&#8220;registrationPrice&#8221;: &#8220;999.00&#8221;,<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&#8220;transferPrice&#8221;: &#8220;1000.00&#8221;,<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&#8220;renewalPrice&#8221;: &#8220;1500.00&#8221;,<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&#8220;currencyCode&#8221;: &#8220;KES&#8221;<\/p>\n\n\n\n<p>&nbsp;&nbsp;},<\/p>\n\n\n\n<p>&nbsp;&nbsp;{<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&#8220;tld&#8221;: &#8220;.co.ke&#8221;,<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&#8220;years&#8221;: [1],<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&#8220;registrationPrice&#8221;: &#8220;7.69&#8221;,<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&#8220;transferPrice&#8221;: &#8220;7.70&#8221;,<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&#8220;renewalPrice&#8221;: &#8220;9.24&#8221;,<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&#8220;currencyCode&#8221;: &#8220;USD&#8221;<\/p>\n\n\n\n<p>&nbsp;&nbsp;}<\/p>\n\n\n\n<p>]<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><strong>Field<\/strong><\/td><td><strong>Meaning<\/strong><\/td><\/tr><tr><td>tld<\/td><td>Extension, with the leading dot<\/td><\/tr><tr><td>years<\/td><td>Registration periods sold, in years<\/td><\/tr><tr><td>registrationPrice \/ transferPrice \/ renewalPrice<\/td><td>Your cost, per year. A negative value means not sold<\/td><\/tr><tr><td>currencyCode<\/td><td>The currency of the prices in this entry<\/td><\/tr><tr><td>graceDays \/ graceFee, redemptionDays \/ redemptionFee<\/td><td>Also sent: the grace and redemption periods after expiry, and their fees<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p><strong>The same extension appears once per currency.<\/strong> truehost.co.ke, for example, lists every extension in KES, USD and NGN (about 520 extensions, so some 1,560 entries). Keep only the entries in <strong>your account&#8217;s currency<\/strong>, the one your balance is charged in: reading the list by tld alone leaves you with whichever currency came last, which on truehost.co.ke is naira.<\/p>\n\n\n\n<p>Cache this list (for example daily) rather than calling it on every order.<\/p>\n\n\n\n<h2 id=\"availability\">8. Availability<\/h2>\n\n\n\n\n<h3 class=\"wp-block-heading\"><strong>POST \/domains\/lookup<\/strong><\/h3>\n\n\n\n<p>Checks one name against one or more extensions in a single call.<\/p>\n\n\n\n<p><strong>Request<\/strong><\/p>\n\n\n\n<p>POST {BASE}\/domains\/lookup<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><strong>Field<\/strong><\/td><td><strong>Type<\/strong><\/td><td><strong>Required<\/strong><\/td><td><strong>Description<\/strong><\/td><\/tr><tr><td>searchTerm<\/td><td>string<\/td><td>yes<\/td><td>The name without extension: mybrand<\/td><\/tr><tr><td>punyCodeSearchTerm<\/td><td>string<\/td><td>yes<\/td><td>The same name in Punycode. Equal to searchTerm for ASCII names<\/td><\/tr><tr><td>tldsToInclude[]<\/td><td>list of strings<\/td><td>yes<\/td><td>Extensions with the leading dot: tldsToInclude[0]=.com&amp;tldsToInclude[1]=.co.ke<\/td><\/tr><tr><td>isIdnDomain<\/td><td>0 or 1<\/td><td>yes<\/td><td>1 when the name has non-ASCII characters<\/td><\/tr><tr><td>premiumEnabled<\/td><td>0 or 1<\/td><td>yes<\/td><td>Send 0<\/td><\/tr><tr><td>isWhmcs<\/td><td>0 or 1<\/td><td>yes<\/td><td>Send 1 (see the format note below)<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p><strong>Response<\/strong><\/p>\n\n\n\n<p>&nbsp;<strong>Not JSON.<\/strong> This endpoint answers in <strong>PHP serialisation format<\/strong>: a list of result objects. In PHP, read it with unserialize($body, [&#8216;allowed_classes&#8217; =&gt; false]). Never allow classes: that would let the response create objects in your application. In other languages, use a PHP-serialisation parser (for example phpserialize in Python or php-serialize in Node.js). Some installations wrap the serialised string in a JSON string; decode the JSON first in that case.<\/p>\n\n\n\n<p>Each result object contains, among other fields:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><strong>Field<\/strong><\/td><td><strong>Meaning<\/strong><\/td><\/tr><tr><td>domainName<\/td><td>The full name checked: mybrand.co.ke (or sld plus tld)<\/td><\/tr><tr><td>isAvailable<\/td><td>true if it can be registered<\/td><\/tr><tr><td>isRegistered<\/td><td>true if it is taken, including names already registered through Truehost<\/td><\/tr><tr><td>legacyStatus \/ status<\/td><td>Text status. error or unknown means the registry did not answer<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>How to read a result:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>legacyStatus is error or status is unknown \u2192 <strong>unknown<\/strong>. Do not tell your customer the name is taken: retry or check WHOIS.<\/li>\n\n\n\n<li>isRegistered is true \u2192 <strong>taken<\/strong>.<\/li>\n\n\n\n<li>Otherwise use isAvailable.<\/li>\n<\/ol>\n\n\n\n<p>Private field names in the serialised data have a prefix (\\0*\\0domainName). Strip it before reading.<\/p>\n\n\n\n<h2 id=\"orders\">9. Orders<\/h2>\n\n\n\n\n<p>Orders are charged to your reseller balance at your price-list cost. Check the balance and price list before ordering, and confirm the result afterwards (see<a href=\"https:\/\/claude.ai\/chat\/49748676-241b-4d96-9e39-4f1578022604#19-recommended-integration-flow\"> Recommended integration flow<\/a>).<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>POST \/order\/domains\/register<\/strong><\/h3>\n\n\n\n<p><strong>Request<\/strong><\/p>\n\n\n\n<p>POST {BASE}\/order\/domains\/register<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><strong>Field<\/strong><\/td><td><strong>Type<\/strong><\/td><td><strong>Required<\/strong><\/td><td><strong>Description<\/strong><\/td><\/tr><tr><td>domain<\/td><td>string<\/td><td>yes<\/td><td>Full domain name: mybrand.co.ke<\/td><\/tr><tr><td>regperiod<\/td><td>integer<\/td><td>yes<\/td><td>Years, one of the periods in your price list<\/td><\/tr><tr><td>nameservers[0] \u2026 nameservers[4]<\/td><td>string<\/td><td>yes<\/td><td>Up to five nameservers. Send at least two; send empty strings for unused positions<\/td><\/tr><tr><td>contacts[registrant][\u2026]<\/td><td>object<\/td><td>yes<\/td><td>The registrant. Fields in<a href=\"https:\/\/claude.ai\/chat\/49748676-241b-4d96-9e39-4f1578022604#contact-object-for-orders\"> Contact object<\/a><\/td><\/tr><tr><td>addons[dnsmanagement]<\/td><td>0 or 1<\/td><td>yes<\/td><td>DNS management add-on<\/td><\/tr><tr><td>addons[emailforwarding]<\/td><td>0 or 1<\/td><td>yes<\/td><td>Email forwarding add-on<\/td><\/tr><tr><td>addons[idprotection]<\/td><td>0 or 1<\/td><td>yes<\/td><td>WHOIS privacy add-on<\/td><\/tr><tr><td>domainfields<\/td><td>string<\/td><td>yes<\/td><td>Extra registry fields: Base64 of a <strong>PHP-serialised<\/strong> array. With no extra fields send YTowOnt9 (an empty array)<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>Add-ons may be charged separately according to your price list.<\/p>\n\n\n\n<p><strong>Example body<\/strong> (shown decoded, one field per line for reading):<\/p>\n\n\n\n<p>domain=mybrand.co.ke<\/p>\n\n\n\n<p>regperiod=1<\/p>\n\n\n\n<p>domainfields=YTowOnt9<\/p>\n\n\n\n<p>addons[dnsmanagement]=0<\/p>\n\n\n\n<p>addons[emailforwarding]=0<\/p>\n\n\n\n<p>addons[idprotection]=1<\/p>\n\n\n\n<p>nameservers[0]=ns1.cloudoon.com<\/p>\n\n\n\n<p>nameservers[1]=ns2.cloudoon.net<\/p>\n\n\n\n<p>nameservers[2]=ns3.cloudoon.org<\/p>\n\n\n\n<p>nameservers[3]=<\/p>\n\n\n\n<p>nameservers[4]=<\/p>\n\n\n\n<p>contacts[registrant][firstname]=Jane<\/p>\n\n\n\n<p>contacts[registrant][lastname]=Wanjiru<\/p>\n\n\n\n<p>contacts[registrant][companyname]=Mybrand Ltd<\/p>\n\n\n\n<p>contacts[registrant][email]=jane@mybrand.co.ke<\/p>\n\n\n\n<p>contacts[registrant][address1]=1 Kenyatta Avenue<\/p>\n\n\n\n<p>contacts[registrant][address2]=<\/p>\n\n\n\n<p>contacts[registrant][city]=Nairobi<\/p>\n\n\n\n<p>contacts[registrant][state]=Nairobi<\/p>\n\n\n\n<p>contacts[registrant][postcode]=00100<\/p>\n\n\n\n<p>contacts[registrant][country]=KE<\/p>\n\n\n\n<p>contacts[registrant][phonenumber]=712345678<\/p>\n\n\n\n<p>contacts[registrant][phonecc]=254<\/p>\n\n\n\n<p>contacts[registrant][fullphonenumber]=+254.712345678<\/p>\n\n\n\n<p>contacts[registrant][tax_id]=<\/p>\n\n\n\n<p><strong>Response<\/strong><\/p>\n\n\n\n<p>{ &#8220;success&#8221;: true }<\/p>\n\n\n\n<p><strong>Confirm every registration.<\/strong> After a successful answer, call<a href=\"https:\/\/claude.ai\/chat\/49748676-241b-4d96-9e39-4f1578022604#post-domainsdomainsync\"> POST \/domains\/{domain}\/sync<\/a>. Only treat the domain as registered when it answers without <em>not been found in reseller account<\/em>. Then read the nameservers back with<a href=\"https:\/\/claude.ai\/chat\/49748676-241b-4d96-9e39-4f1578022604#get-domainsdomainnameservers\"> GET \/domains\/{domain}\/nameservers<\/a>, and send them again if none are set.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>POST \/order\/domains\/transfer<\/strong><\/h3>\n\n\n\n<p>Same fields as <strong>register<\/strong>, plus:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><strong>Field<\/strong><\/td><td><strong>Type<\/strong><\/td><td><strong>Required<\/strong><\/td><td><strong>Description<\/strong><\/td><\/tr><tr><td>eppcode<\/td><td>string<\/td><td>yes<\/td><td>The authorisation (EPP) code from the current registrar<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>regperiod is usually 1: most registries add one year on transfer.<\/p>\n\n\n\n<p><strong>Response<\/strong>: {&#8220;success&#8221;: true} means the transfer <strong>started<\/strong>. Follow it with<a href=\"https:\/\/claude.ai\/chat\/49748676-241b-4d96-9e39-4f1578022604#post-domainsdomaintransfersync\"> POST \/domains\/{domain}\/transfersync<\/a> until it completes or fails. Transfers usually take five to seven days.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>POST \/order\/domains\/renew<\/strong><\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><strong>Field<\/strong><\/td><td><strong>Type<\/strong><\/td><td><strong>Required<\/strong><\/td><td><strong>Description<\/strong><\/td><\/tr><tr><td>domain<\/td><td>string<\/td><td>yes<\/td><td>Full domain name<\/td><\/tr><tr><td>regperiod<\/td><td>integer<\/td><td>yes<\/td><td>Years to add<\/td><\/tr><tr><td>addons[dnsmanagement]<\/td><td>0 or 1<\/td><td>yes<\/td><td>Keep the DNS management add-on<\/td><\/tr><tr><td>addons[emailforwarding]<\/td><td>0 or 1<\/td><td>yes<\/td><td>Keep the email forwarding add-on<\/td><\/tr><tr><td>addons[idprotection]<\/td><td>0 or 1<\/td><td>yes<\/td><td>Keep WHOIS privacy<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p><strong>Response<\/strong><\/p>\n\n\n\n<p>{ &#8220;success&#8221;: true, &#8220;expirydate&#8221;: &#8220;2028-10-26&#8221; }<\/p>\n\n\n\n<p>If expirydate is present, store it. Otherwise read the new date with<a href=\"https:\/\/claude.ai\/chat\/49748676-241b-4d96-9e39-4f1578022604#post-domainsdomainsync\"> sync<\/a>.<\/p>\n\n\n\n<h2 id=\"domain-status\">10. Domain Status<\/h2>\n\n\n\n\n<h3 class=\"wp-block-heading\"><strong>POST \/domains\/{domain}\/sync<\/strong><\/h3>\n\n\n\n<p>The domain&#8217;s current expiry date and status at the registry. Use it to confirm registrations and in a daily synchronisation job. It changes nothing.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><strong>Field<\/strong><\/td><td><strong>Type<\/strong><\/td><td><strong>Required<\/strong><\/td><\/tr><tr><td>domain<\/td><td>string<\/td><td>yes<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p><strong>Response<\/strong><\/p>\n\n\n\n<p>{<\/p>\n\n\n\n<p>&nbsp;&nbsp;&#8220;active&#8221;: true,<\/p>\n\n\n\n<p>&nbsp;&nbsp;&#8220;expired&#8221;: false,<\/p>\n\n\n\n<p>&nbsp;&nbsp;&#8220;transferredAway&#8221;: false,<\/p>\n\n\n\n<p>&nbsp;&nbsp;&#8220;expirydate&#8221;: &#8220;2027-10-26&#8221;<\/p>\n\n\n\n<p>}<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><strong>Field<\/strong><\/td><td><strong>Meaning<\/strong><\/td><\/tr><tr><td>active<\/td><td>Registered and in force<\/td><\/tr><tr><td>expired<\/td><td>Past its expiry date<\/td><\/tr><tr><td>transferredAway<\/td><td>Moved to another registrar<\/td><\/tr><tr><td>expirydate<\/td><td>Expiry date, YYYY-MM-DD. Ignore 0000-00-00<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>An error containing <em>not been found in reseller account<\/em> means the domain is not in your account.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>POST \/domains\/{domain}\/transfersync<\/strong><\/h3>\n\n\n\n<p>Progress of a transfer started with order\/domains\/transfer.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><strong>Field<\/strong><\/td><td><strong>Type<\/strong><\/td><td><strong>Required<\/strong><\/td><\/tr><tr><td>domain<\/td><td>string<\/td><td>yes<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p><strong>Response<\/strong><\/p>\n\n\n\n<p>{ &#8220;completed&#8221;: true, &#8220;expirydate&#8221;: &#8220;2027-10-26&#8221; }<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><strong>Field<\/strong><\/td><td><strong>Meaning<\/strong><\/td><\/tr><tr><td>completed<\/td><td>The transfer finished; the domain is now active in your account<\/td><\/tr><tr><td>failed<\/td><td>The transfer failed; the reason is in reason<\/td><\/tr><tr><td>expirydate<\/td><td>New expiry date, when completed<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>Neither completed nor failed means the transfer is <strong>still in progress<\/strong>. Check again later, for example daily.<\/p>\n\n\n\n<h2 id=\"nameservers\">11. Nameservers<\/h2>\n\n\n\n\n<h3 class=\"wp-block-heading\"><strong>GET \/domains\/{domain}\/nameservers<\/strong><\/h3>\n\n\n\n<p><strong>Request<\/strong><\/p>\n\n\n\n<p>GET {BASE}\/domains\/{domain}\/nameservers<\/p>\n\n\n\n<p><strong>Response<\/strong><\/p>\n\n\n\n<p>{ &#8220;ns1&#8221;: &#8220;ns1.cloudoon.com&#8221;, &#8220;ns2&#8221;: &#8220;ns2.cloudoon.net&#8221;, &#8220;ns3&#8221;: &#8220;ns3.cloudoon.org&#8221;, &#8220;ns4&#8221;: &#8220;&#8221;, &#8220;ns5&#8221;: &#8220;&#8221; }<\/p>\n\n\n\n<p>Read ns1 to ns5 and ignore empty values. To be robust, also accept the values wrapped in nameservers or data, or as a plain list.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>POST \/domains\/{domain}\/nameservers<\/strong><\/h3>\n\n\n\n<p>Replaces all nameservers.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><strong>Field<\/strong><\/td><td><strong>Type<\/strong><\/td><td><strong>Required<\/strong><\/td><td><strong>Description<\/strong><\/td><\/tr><tr><td>domain<\/td><td>string<\/td><td>yes<\/td><td><\/td><\/tr><tr><td>ns1 \u2026 ns5<\/td><td>string<\/td><td>ns1, ns2 yes<\/td><td>Host names. Send empty strings for unused positions<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p><strong>Response<\/strong>: {&#8220;success&#8221;: true}<\/p>\n\n\n\n<p>Truehost&#8217;s default nameservers are ns1.cloudoon.com, ns2.cloudoon.net and ns3.cloudoon.org.<\/p>\n\n\n\n<h2 id=\"child-nameservers-(glue records)\n\">12. Child nameservers (glue records)\n<\/h2>\n\n\n\n\n<p>Child nameservers are host names under the domain itself, such as ns1.mybrand.co.ke, registered with an IP address at the registry. They let you offer branded nameservers.<\/p>\n\n\n\n<p>The API has no endpoint that <strong>lists<\/strong> child nameservers. Store the ones you create, with their IP addresses, in your own system.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>POST \/domains\/{domain}\/nameservers\/register<\/strong><\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><strong>Field<\/strong><\/td><td><strong>Type<\/strong><\/td><td><strong>Required<\/strong><\/td><td><strong>Description<\/strong><\/td><\/tr><tr><td>domain<\/td><td>string<\/td><td>yes<\/td><td>The parent domain: mybrand.co.ke<\/td><\/tr><tr><td>nameserver<\/td><td>string<\/td><td>yes<\/td><td>Full host name: ns1.mybrand.co.ke<\/td><\/tr><tr><td>ipaddress<\/td><td>string<\/td><td>yes<\/td><td>One IPv4 address<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>POST \/domains\/{domain}\/nameservers\/modify<\/strong><\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><strong>Field<\/strong><\/td><td><strong>Type<\/strong><\/td><td><strong>Required<\/strong><\/td><td><strong>Description<\/strong><\/td><\/tr><tr><td>domain<\/td><td>string<\/td><td>yes<\/td><td><\/td><\/tr><tr><td>nameserver<\/td><td>string<\/td><td>yes<\/td><td>Full host name<\/td><\/tr><tr><td>currentipaddress<\/td><td>string<\/td><td>yes<\/td><td>The IP address registered now<\/td><\/tr><tr><td>newipaddress<\/td><td>string<\/td><td>yes<\/td><td>The new IP address<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>POST \/domains\/{domain}\/nameservers\/delete<\/strong><\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><strong>Field<\/strong><\/td><td><strong>Type<\/strong><\/td><td><strong>Required<\/strong><\/td><td><strong>Description<\/strong><\/td><\/tr><tr><td>domain<\/td><td>string<\/td><td>yes<\/td><td><\/td><\/tr><tr><td>nameserver<\/td><td>string<\/td><td>yes<\/td><td>Full host name<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p><strong>Response<\/strong> (all three): {&#8220;success&#8221;: true}<\/p>\n\n\n\n<h2 id=\"transfer-lock-and-epp-code\">13. Transfer lock and EPP code<\/h2>\n\n\n\n\n<h3 class=\"wp-block-heading\"><strong>GET \/domains\/{domain}\/lock<\/strong><\/h3>\n\n\n\n<p><strong>Response<\/strong>: the lock status, either as a bare JSON string or in a field:<\/p>\n\n\n\n<p>&#8220;locked&#8221;<\/p>\n\n\n\n<p>{ &#8220;lockstatus&#8221;: &#8220;locked&#8221; }<\/p>\n\n\n\n<p>unlocked (or 0, false, off) means unlocked; anything else means locked. If the call fails, assume <strong>locked<\/strong>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>POST \/domains\/{domain}\/lock<\/strong><\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><strong>Field<\/strong><\/td><td><strong>Type<\/strong><\/td><td><strong>Required<\/strong><\/td><td><strong>Values<\/strong><\/td><\/tr><tr><td>domain<\/td><td>string<\/td><td>yes<\/td><td><\/td><\/tr><tr><td>lockstatus<\/td><td>string<\/td><td>yes<\/td><td>locked or unlocked<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p><strong>Response<\/strong>: {&#8220;success&#8221;: true}<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>GET \/domains\/{domain}\/eppcode<\/strong><\/h3>\n\n\n\n<p><strong>Response<\/strong><\/p>\n\n\n\n<p>{ &#8220;eppcode&#8221;: &#8220;aB3#kL9$xQ&#8221; }<\/p>\n\n\n\n<p>Some registries do not return the code and email it to the registrant instead. In that case the call succeeds with no eppcode: tell your customer to check the registrant&#8217;s email.<\/p>\n\n\n\n<p>The EPP code allows the domain to be transferred away. Show it only to the domain&#8217;s owner, over HTTPS, and never log it.<\/p>\n\n\n\n<h2 id=\"contacts-and-whois-privacy\">14. Contacts and WHOIS privacy<\/h2>\n\n\n\n\n<h3 class=\"wp-block-heading\"><strong>GET \/domains\/{domain}\/contact<\/strong><\/h3>\n\n\n\n<p><strong>Response<\/strong>: one object per contact role. Field names use underscores:<\/p>\n\n\n\n<p>{<\/p>\n\n\n\n<p>&nbsp;&nbsp;&#8220;Registrant&#8221;: {<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&#8220;First_Name&#8221;: &#8220;Jane&#8221;,<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&#8220;Last_Name&#8221;: &#8220;Wanjiru&#8221;,<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&#8220;Company_Name&#8221;: &#8220;Mybrand Ltd&#8221;,<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&#8220;Email_Address&#8221;: &#8220;jane@mybrand.co.ke&#8221;,<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&#8220;Address_1&#8221;: &#8220;1 Kenyatta Avenue&#8221;,<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&#8220;City&#8221;: &#8220;Nairobi&#8221;,<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&#8220;State&#8221;: &#8220;Nairobi&#8221;,<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&#8220;Postcode&#8221;: &#8220;00100&#8221;,<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&#8220;Country&#8221;: &#8220;KE&#8221;,<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&#8220;Phone_Number&#8221;: &#8220;+254.712345678&#8221;<\/p>\n\n\n\n<p>&nbsp;&nbsp;},<\/p>\n\n\n\n<p>&nbsp;&nbsp;&#8220;Admin&#8221;: { &#8220;\u2026&#8221;: &#8220;\u2026&#8221; },<\/p>\n\n\n\n<p>&nbsp;&nbsp;&#8220;Technical&#8221;: { &#8220;\u2026&#8221;: &#8220;\u2026&#8221; },<\/p>\n\n\n\n<p>&nbsp;&nbsp;&#8220;Billing&#8221;: { &#8220;\u2026&#8221;: &#8220;\u2026&#8221; }<\/p>\n\n\n\n<p>}<\/p>\n\n\n\n<p>Roles and fields vary by registry. Some registries give the name whole (Contact_Name), and some add their own fields (for example an ID number for .ke). The registrant role may be called Registrant or Owner.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>POST \/domains\/{domain}\/contact<\/strong><\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><strong>Field<\/strong><\/td><td><strong>Type<\/strong><\/td><td><strong>Required<\/strong><\/td><td><strong>Description<\/strong><\/td><\/tr><tr><td>domain<\/td><td>string<\/td><td>yes<\/td><td><\/td><\/tr><tr><td>contactdetails[{Role}][{Field Name}]<\/td><td>string<\/td><td>yes<\/td><td>Every role and field, with <strong>spaces instead of underscores<\/strong> in field names<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>Example (decoded):<\/p>\n\n\n\n<p>domain=mybrand.co.ke<\/p>\n\n\n\n<p>contactdetails[Registrant][First Name]=chelsie<\/p>\n\n\n\n<p>contactdetails[Registrant][Last Name]=Kalya<\/p>\n\n\n\n<p>contactdetails[Registrant][Email Address]=chelsiekalya@mybrand.co.ke<\/p>\n\n\n\n<p>contactdetails[Registrant][Phone Number]=+254.712345678<\/p>\n\n\n\n<p>contactdetails[Registrant][Country]=KE<\/p>\n\n\n\n<p><strong>Read, change, send back.<\/strong> Call GET \u2026\/contact first, change the values you need, and send back <strong>every role and field you received<\/strong>, under the same names (underscores replaced by spaces). This keeps registry-specific fields that you don&#8217;t edit. If the read fails, send the four roles Registrant, Admin, Technical and Billing with the fields First Name, Last Name, Company Name, Email Address, Address 1, Address 2, City, State, Postcode, Country, Phone Number.<\/p>\n\n\n\n<p><strong>Response<\/strong>: {&#8220;success&#8221;: true}<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>POST \/domains\/{domain}\/protectid<\/strong><\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><strong>Field<\/strong><\/td><td><strong>Type<\/strong><\/td><td><strong>Required<\/strong><\/td><td><strong>Values<\/strong><\/td><\/tr><tr><td>domain<\/td><td>string<\/td><td>yes<\/td><td><\/td><\/tr><tr><td>status<\/td><td>integer<\/td><td>yes<\/td><td>1 on, 0 off<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p><strong>Response<\/strong>: {&#8220;success&#8221;: true}. Not every extension supports WHOIS privacy; the error message says so when it is not available.<\/p>\n\n\n\n<p>These work only when the domain has the matching add-on (dnsmanagement or emailforwarding) and uses Truehost&#8217;s nameservers.<\/p>\n\n\n\n<h2 id=\"dns-and-email-forwarding\">15. DNS and email forwarding<\/h2>\n\n\n\n\n<h3 class=\"wp-block-heading\"><strong>GET \/domains\/{domain}\/dns<\/strong><\/h3>\n\n\n\n<p><strong>Response<\/strong><\/p>\n\n\n\n<p>[<\/p>\n\n\n\n<p>&nbsp;&nbsp;{ &#8220;hostname&#8221;: &#8220;@&#8221;, &#8220;type&#8221;: &#8220;A&#8221;, &#8220;address&#8221;: &#8220;203.0.113.10&#8221;, &#8220;priority&#8221;: &#8220;&#8221; },<\/p>\n\n\n\n<p>&nbsp;&nbsp;{ &#8220;hostname&#8221;: &#8220;www&#8221;, &#8220;type&#8221;: &#8220;CNAME&#8221;, &#8220;address&#8221;: &#8220;mybrand.co.ke&#8221;, &#8220;priority&#8221;: &#8220;&#8221; },<\/p>\n\n\n\n<p>&nbsp;&nbsp;{ &#8220;hostname&#8221;: &#8220;@&#8221;, &#8220;type&#8221;: &#8220;MX&#8221;, &#8220;address&#8221;: &#8220;mail.mybrand.co.ke&#8221;, &#8220;priority&#8221;: &#8220;10&#8221; }<\/p>\n\n\n\n<p>]<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>POST \/domains\/{domain}\/dns<\/strong><\/h3>\n\n\n\n<p>Replaces <strong>all<\/strong> records: send the complete list.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><strong>Field<\/strong><\/td><td><strong>Type<\/strong><\/td><td><strong>Required<\/strong><\/td><td><strong>Description<\/strong><\/td><\/tr><tr><td>domain<\/td><td>string<\/td><td>yes<\/td><td><\/td><\/tr><tr><td>dnsrecords[n][hostname]<\/td><td>string<\/td><td>yes<\/td><td>@ for the domain itself, or a sub-name<\/td><\/tr><tr><td>dnsrecords[n][type]<\/td><td>string<\/td><td>yes<\/td><td>A, AAAA, CNAME, MX, TXT, and so on<\/td><\/tr><tr><td>dnsrecords[n][address]<\/td><td>string<\/td><td>yes<\/td><td>The value<\/td><\/tr><tr><td>dnsrecords[n][priority]<\/td><td>string<\/td><td>MX only<\/td><td>MX priority<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>GET \/domains\/{domain}\/email<\/strong><\/h3>\n\n\n\n<p><strong>Response<\/strong><\/p>\n\n\n\n<p>[ { &#8220;prefix&#8221;: &#8220;info&#8221;, &#8220;forwardto&#8221;: &#8220;jane@gmail.com&#8221; } ]<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>POST \/domains\/{domain}\/email<\/strong><\/h3>\n\n\n\n<p>Replaces all forwarders. The two lists are matched by position.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><strong>Field<\/strong><\/td><td><strong>Type<\/strong><\/td><td><strong>Required<\/strong><\/td><td><strong>Description<\/strong><\/td><\/tr><tr><td>domain<\/td><td>string<\/td><td>yes<\/td><td><\/td><\/tr><tr><td>prefix[n]<\/td><td>string<\/td><td>yes<\/td><td>The part before @: info<\/td><\/tr><tr><td>forwardto[n]<\/td><td>string<\/td><td>yes<\/td><td>The destination address<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p><strong>Response<\/strong> (both POSTs): {&#8220;success&#8221;: true}<\/p>\n\n\n\n<h2 id=\"release-and-deletion\">16. Release and deletion<\/h2>\n\n\n\n\n<p>Both actions are hard or impossible to undo. Ask your customer to confirm first.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>POST \/domains\/{domain}\/release<\/strong><\/h3>\n\n\n\n<p>Moves the domain to another registrar by <strong>transfer tag<\/strong> (IPS tag), used by .uk and similar registries.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><strong>Field<\/strong><\/td><td><strong>Type<\/strong><\/td><td><strong>Required<\/strong><\/td><td><strong>Description<\/strong><\/td><\/tr><tr><td>domain<\/td><td>string<\/td><td>yes<\/td><td><\/td><\/tr><tr><td>transfertag<\/td><td>string<\/td><td>yes<\/td><td>The receiving registrar&#8217;s tag<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>POST \/domains\/{domain}\/delete<\/strong><\/h3>\n\n\n\n<p>Asks the registry to delete the domain.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><strong>Field<\/strong><\/td><td><strong>Type<\/strong><\/td><td><strong>Required<\/strong><\/td><\/tr><tr><td>domain<\/td><td>string<\/td><td>yes<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p><strong>Response<\/strong> (both): {&#8220;success&#8221;: true}<\/p>\n\n\n\n<h2 id=\"data-formats\">17. Data formats<\/h2>\n\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Contact object for orders<\/strong><\/h3>\n\n\n\n<p>Used as contacts[registrant][\u2026] in register and transfer.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><strong>Field<\/strong><\/td><td><strong>Required<\/strong><\/td><td><strong>Format<\/strong><\/td><td><strong>Example<\/strong><\/td><\/tr><tr><td>firstname<\/td><td>yes<\/td><td>Text<\/td><td>Jane<\/td><\/tr><tr><td>lastname<\/td><td>yes<\/td><td>Text<\/td><td>Wanjiru<\/td><\/tr><tr><td>companyname<\/td><td>no<\/td><td>Text; empty for individuals<\/td><td>Mybrand Ltd<\/td><\/tr><tr><td>email<\/td><td>yes<\/td><td>Email address<\/td><td>jane@mybrand.co.ke<\/td><\/tr><tr><td>address1<\/td><td>yes<\/td><td>Street address<\/td><td>1 Kenyatta Avenue<\/td><\/tr><tr><td>address2<\/td><td>no<\/td><td>Text<\/td><td><\/td><\/tr><tr><td>city<\/td><td>yes<\/td><td>Text<\/td><td>Nairobi<\/td><\/tr><tr><td>state<\/td><td>yes<\/td><td>Region or county<\/td><td>Nairobi<\/td><\/tr><tr><td>postcode<\/td><td>yes<\/td><td>Postal code<\/td><td>00100<\/td><\/tr><tr><td>country<\/td><td>yes<\/td><td>ISO 3166-1 alpha-2, uppercase<\/td><td>KE<\/td><\/tr><tr><td>phonenumber<\/td><td>yes<\/td><td>National number, digits only, no leading zero<\/td><td>712345678<\/td><\/tr><tr><td>phonecc<\/td><td>yes<\/td><td>Country calling code, digits only, no +<\/td><td>254<\/td><\/tr><tr><td>fullphonenumber<\/td><td>yes<\/td><td>+{phonecc}.{phonenumber}<\/td><td>+254.712345678<\/td><\/tr><tr><td>tax_id<\/td><td>no<\/td><td>VAT or tax number<\/td><td><\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Phone numbers<\/strong><\/h3>\n\n\n\n<p>Registries use the EPP form of E.164: + country code, a dot, then the national number without its trunk zero.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><strong>Customer typed<\/strong><\/td><td><strong>phonecc<\/strong><\/td><td><strong>phonenumber<\/strong><\/td><td><strong>fullphonenumber<\/strong><\/td><\/tr><tr><td>0712 345 678 (Kenya)<\/td><td>254<\/td><td>712345678<\/td><td>+254.712345678<\/td><\/tr><tr><td>+234 803 123 4567 (Nigeria)<\/td><td>234<\/td><td>8031234567<\/td><td>+234.8031234567<\/td><\/tr><tr><td>+27 82 123 4567 (South Africa)<\/td><td>27<\/td><td>821234567<\/td><td>+27.821234567<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Other formats<\/strong><\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><strong>Data<\/strong><\/td><td><strong>Format<\/strong><\/td><\/tr><tr><td>Dates<\/td><td>ISO 8601 calendar date YYYY-MM-DD. Treat 0000-00-00 as unknown<\/td><\/tr><tr><td>Domain names<\/td><td>Lowercase ASCII; internationalised names in Punycode, e.g. xn--mnchen-3ya.de<\/td><\/tr><tr><td>Extensions<\/td><td>With the leading dot: .co.ke<\/td><\/tr><tr><td>Money<\/td><td>Decimal string in your reseller account&#8217;s currency, e.g. &#8220;999.00&#8221;<\/td><\/tr><tr><td>Booleans<\/td><td>true\/false in responses; 1\/0 in requests<\/td><\/tr><tr><td>Empty domainfields<\/td><td>YTowOnt9 (Base64 of the PHP-serialised empty array a:0:{})<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n\n<h2 id=\"code-examples\">18. Code examples<\/h2>\n\n\n\n\n<p>Replace the placeholder credentials with your own, loaded from environment variables or a secrets store, never written in code.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>cURL (Bash)<\/strong><\/h3>\n\n\n\n<p>SITE=&#8221;truehost.cloud&#8221;<\/p>\n\n\n\n<p>BASE=&#8221;https:\/\/SITE\/cloud\/modules\/addons\/DomainsReseller\/api\/index.php&#8221;THUSER=&#8221;TRUEHOST_USERNAME&#8221; &nbsp; # not USERNAME:zshreservesthatnameTHKEY=&#8221;TRUEHOST_API_KEY&#8221;<\/p>\n\n\n\n<p>HOUR=(date-u+&#8221;%y-%m-%d%H&#8221;)TOKEN=(printf &#8216;%s&#8217; &#8220;$TH_KEY&#8221; \\<\/p>\n\n\n\n<p>&nbsp;&nbsp;| openssl dgst -sha256 -hmac &#8220;THUSER:HOUR&#8221; -hex \\<\/p>\n\n\n\n<p>&nbsp;&nbsp;| sed &#8216;s\/^.*= \/\/&#8217; | tr -d &#8216;\\n&#8217; | base64 -w0)<\/p>\n\n\n\n<p># Balance<\/p>\n\n\n\n<p>curl -s &#8220;$BASE\/billing\/credits&#8221; -H &#8220;username: $TH_USER&#8221; -H &#8220;token: TOKEN&#8221;#Changenameserverscurl-s-XPOST&#8221;BASE\/domains\/mybrand.co.ke\/nameservers&#8221; \\<\/p>\n\n\n\n<p>&nbsp;&nbsp;-H &#8220;username: $TH_USER&#8221; -H &#8220;token: $TOKEN&#8221; \\<\/p>\n\n\n\n<p>&nbsp;&nbsp;&#8211;data-urlencode &#8220;domain=mybrand.co.ke&#8221; \\<\/p>\n\n\n\n<p>&nbsp;&nbsp;&#8211;data-urlencode &#8220;ns1=ns1.cloudoon.com&#8221; \\<\/p>\n\n\n\n<p>&nbsp;&nbsp;&#8211;data-urlencode &#8220;ns2=ns2.cloudoon.net&#8221; \\<\/p>\n\n\n\n<p>&nbsp;&nbsp;&#8211;data-urlencode &#8220;ns3=&#8221; &#8211;data-urlencode &#8220;ns4=&#8221; &#8211;data-urlencode &#8220;ns5=&#8221;<\/p>\n\n\n\n<p>On macOS use base64 without -w0.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>PHP<\/strong><\/h3>\n\n\n\n<p>&lt;?php<\/p>\n\n\n\n<p>final class TruehostApi<\/p>\n\n\n\n<p>{<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;public function __construct(<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;private string $site,&nbsp; &nbsp; &nbsp; \/\/ e.g. &#8220;truehost.cloud&#8221;<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;private string $username,<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;private string $apiKey,<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;) {}<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;private function base(): string<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;{<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return &#8220;https:\/\/{$this-&gt;site}\/cloud\/modules\/addons\/DomainsReseller\/api\/index.php&#8221;;<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;}<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;private function token(): string<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;{<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$hour = gmdate(&#8216;y-m-d H&#8217;);<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return base64_encode(hash_hmac(&#8216;sha256&#8217;, $this-&gt;apiKey, &#8220;{$this-&gt;username}:{$hour}&#8221;));<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;}<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;\/** @return array{ok: bool, data: mixed, error: ?string, raw: string} *\/<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;public function call(string $method, string $path, array $body = []): array<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;{<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ch=curlinit(this-&gt;base().&#8217;\/&#8217;.ltrim(path,&#8217;\/&#8217;));curlsetoptarray(ch, [<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CURLOPT_RETURNTRANSFER =&gt; true,<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CURLOPT_FOLLOWLOCATION =&gt; false,<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CURLOPT_TIMEOUT =&gt; 60,<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CURLOPT_HTTPHEADER =&gt; [<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#8216;username: &#8216;.this-&gt;username,&#8217;token:&#8217;.this-&gt;token(),<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;],<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;]);<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if ($method === &#8216;POST&#8217;) {<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;curl_setopt($ch, CURLOPT_POST, true);<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;curl_setopt(ch,CURLOPTPOSTFIELDS,httpbuildquery(body)); \/\/ bracket notation<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;raw=(string)curlexec(ch);<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;status=(int)curlgetinfo(ch, CURLINFO_HTTP_CODE);<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;curlError=curlerror(ch);<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;curl_close(ch);if(curlError !== &#8221;) {<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return [&#8216;ok&#8217; =&gt; false, &#8216;data&#8217; =&gt; null, &#8216;error&#8217; =&gt; $curlError, &#8216;raw&#8217; =&gt; &#8221;];<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;data=jsondecode(raw, true);<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$error = match (true) {<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;is_array($data) &amp;&amp; ! empty($data[&#8216;error&#8217;]) =&gt; (string) data[&#8216;error&#8217;],isarray(data) &amp;&amp; strtolower((string) (data[&#8216;result&#8217;]??&#8221;))===&#8217;error&#8217;=&gt;(string)(data[&#8216;message&#8217;] ?? &#8216;Error&#8217;),<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;is_array(data)&amp;&amp;(data[&#8216;success&#8217;] ?? null) === false =&gt; (string) ($data[&#8216;message&#8217;] ?? &#8216;Failed&#8217;),<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$status &gt;= 400 =&gt; &#8220;HTTP {$status}&#8221;,<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;json_last_error() !== JSON_ERROR_NONE &amp;&amp; $path !== &#8216;domains\/lookup&#8217; =&gt; &#8216;Response is not JSON&#8217;,<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;default =&gt; null,<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return [&#8216;ok&#8217; =&gt; $error === null, &#8216;data&#8217; =&gt; $data, &#8216;error&#8217; =&gt; $error, &#8216;raw&#8217; =&gt; $raw];<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;}<\/p>\n\n\n\n<p>}<\/p>\n\n\n\n<p>$api = new TruehostApi(&#8216;truehost.cloud&#8217;, getenv(&#8216;TRUEHOST_USERNAME&#8217;), getenv(&#8216;TRUEHOST_API_KEY&#8217;));<\/p>\n\n\n\n<p>\/\/ Availability (serialised PHP response)<\/p>\n\n\n\n<p>$r = $api-&gt;call(&#8216;POST&#8217;, &#8216;domains\/lookup&#8217;, [<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&#8216;searchTerm&#8217; =&gt; &#8216;mybrand&#8217;,<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&#8216;punyCodeSearchTerm&#8217; =&gt; &#8216;mybrand&#8217;,<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&#8216;tldsToInclude&#8217; =&gt; [&#8216;.com&#8217;, &#8216;.co.ke&#8217;],<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&#8216;isIdnDomain&#8217; =&gt; 0,<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&#8216;premiumEnabled&#8217; =&gt; 0,<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&#8216;isWhmcs&#8217; =&gt; 1,<\/p>\n\n\n\n<p>]);<\/p>\n\n\n\n<p>results=@unserialize(r[&#8216;raw&#8217;], [&#8216;allowed_classes&#8217; =&gt; false]);<\/p>\n\n\n\n<p>\/\/ Registration<\/p>\n\n\n\n<p>$r = $api-&gt;call(&#8216;POST&#8217;, &#8216;order\/domains\/register&#8217;, [<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&#8216;domain&#8217; =&gt; &#8216;mybrand.co.ke&#8217;,<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&#8216;regperiod&#8217; =&gt; 1,<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&#8216;domainfields&#8217; =&gt; base64_encode(serialize([])),<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&#8216;addons&#8217; =&gt; [&#8216;dnsmanagement&#8217; =&gt; 0, &#8217;emailforwarding&#8217; =&gt; 0, &#8216;idprotection&#8217; =&gt; 0],<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&#8216;nameservers&#8217; =&gt; [&#8216;ns1.cloudoon.com&#8217;, &#8216;ns2.cloudoon.net&#8217;, &#8216;ns3.cloudoon.org&#8217;, &#8221;, &#8221;],<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&#8216;contacts&#8217; =&gt; [&#8216;registrant&#8217; =&gt; [<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#8216;firstname&#8217; =&gt; &#8216;Jane&#8217;, &#8216;lastname&#8217; =&gt; &#8216;Wanjiru&#8217;, &#8216;companyname&#8217; =&gt; &#8221;,<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#8217;email&#8217; =&gt; &#8216;jane@mybrand.co.ke&#8217;, &#8216;address1&#8217; =&gt; &#8216;1 Kenyatta Avenue&#8217;, &#8216;address2&#8217; =&gt; &#8221;,<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#8216;city&#8217; =&gt; &#8216;Nairobi&#8217;, &#8216;state&#8217; =&gt; &#8216;Nairobi&#8217;, &#8216;postcode&#8217; =&gt; &#8216;00100&#8217;, &#8216;country&#8217; =&gt; &#8216;KE&#8217;,<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#8216;phonenumber&#8217; =&gt; &#8216;712345678&#8217;, &#8216;phonecc&#8217; =&gt; &#8216;254&#8217;, &#8216;fullphonenumber&#8217; =&gt; &#8216;+254.712345678&#8217;,<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#8216;tax_id&#8217; =&gt; &#8221;,<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;]],<\/p>\n\n\n\n<p>]);<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Python<\/strong><\/h3>\n\n\n\n<p>import base64, hashlib, hmac, os<\/p>\n\n\n\n<p>from datetime import datetime, timezone<\/p>\n\n\n\n<p>from urllib.parse import quote<\/p>\n\n\n\n<p>import requests&nbsp; # pip install requests<\/p>\n\n\n\n<p>SITE = &#8220;truehost.cloud&#8221;<\/p>\n\n\n\n<p>BASE = f&#8221;https:\/\/{SITE}\/cloud\/modules\/addons\/DomainsReseller\/api\/index.php&#8221;<\/p>\n\n\n\n<p>USERNAME = os.environ[&#8220;TRUEHOST_USERNAME&#8221;]<\/p>\n\n\n\n<p>API_KEY = os.environ[&#8220;TRUEHOST_API_KEY&#8221;]<\/p>\n\n\n\n<p>def token() -&gt; str:<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;hour = datetime.now(timezone.utc).strftime(&#8220;%y-%m-%d %H&#8221;)<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;hexdigest = hmac.new(f&#8221;{USERNAME}:{hour}&#8221;.encode(), API_KEY.encode(), hashlib.sha256).hexdigest()<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;return base64.b64encode(hexdigest.encode()).decode()<\/p>\n\n\n\n<p>def flatten(data, prefix=&#8221;&#8221;):<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&#8220;&#8221;&#8221;PHP bracket notation: {&#8220;a&#8221;: {&#8220;b&#8221;: 1}} -&gt; [(&#8220;a[b]&#8221;, 1)].&#8221;&#8221;&#8221;<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;pairs = []<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;items = data.items() if isinstance(data, dict) else enumerate(data)<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;for key, value in items:<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;name = f&#8221;{prefix}[{key}]&#8221; if prefix else str(key)<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if isinstance(value, (dict, list)):<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pairs += flatten(value, name)<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else:<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pairs.append((name, value))<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;return pairs<\/p>\n\n\n\n<p>def call(method: str, path: str, body: dict | None = None):<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;response = requests.request(<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;method,<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f&#8221;{BASE}\/{path}&#8221;,<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;headers={&#8220;username&#8221;: USERNAME, &#8220;token&#8221;: token()},<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;data=flatten(body) if body else None,<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;timeout=60,<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;allow_redirects=False,<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;)<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;try:<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;data = response.json()<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;except ValueError:<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;data = None<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;if isinstance(data, dict):<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if data.get(&#8220;error&#8221;):<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;raise RuntimeError(data[&#8220;error&#8221;])<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if str(data.get(&#8220;result&#8221;, &#8220;&#8221;)).lower() == &#8220;error&#8221; or data.get(&#8220;success&#8221;) is False:<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;raise RuntimeError(data.get(&#8220;message&#8221;, &#8220;Truehost reported a failure&#8221;))<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;if response.status_code &gt;= 400:<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;raise RuntimeError(f&#8221;HTTP {response.status_code}&#8221;)<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;return data<\/p>\n\n\n\n<p>print(call(&#8220;GET&#8221;, &#8220;billing\/credits&#8221;))<\/p>\n\n\n\n<p>domain = &#8220;mybrand.co.ke&#8221;<\/p>\n\n\n\n<p>print(call(&#8220;POST&#8221;, f&#8221;domains\/{quote(domain)}\/sync&#8221;, {&#8220;domain&#8221;: domain}))<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Node.js (18 or later)<\/strong><\/h3>\n\n\n\n<p>import crypto from &#8220;node:crypto&#8221;;<\/p>\n\n\n\n<p>const SITE = &#8220;truehost.cloud&#8221;;<\/p>\n\n\n\n<p>const BASE = `https:\/\/${SITE}\/cloud\/modules\/addons\/DomainsReseller\/api\/index.php`;<\/p>\n\n\n\n<p>const USERNAME = process.env.TRUEHOST_USERNAME;<\/p>\n\n\n\n<p>const API_KEY = process.env.TRUEHOST_API_KEY;<\/p>\n\n\n\n<p>function token() {<\/p>\n\n\n\n<p>&nbsp;&nbsp;const d = new Date();<\/p>\n\n\n\n<p>&nbsp;&nbsp;const p = (n) =&gt; String(n).padStart(2, &#8220;0&#8221;);<\/p>\n\n\n\n<p>&nbsp;&nbsp;const hour = `${p(d.getUTCFullYear() % 100)}-p(d.getUTCMonth()+1)-{p(d.getUTCDate())} p(d.getUTCHours())`;consthex=crypto.createHmac(&#8220;sha256&#8221;,`{USERNAME}:${hour}`).update(API_KEY).digest(&#8220;hex&#8221;);<\/p>\n\n\n\n<p>&nbsp;&nbsp;return Buffer.from(hex).toString(&#8220;base64&#8221;);<\/p>\n\n\n\n<p>}<\/p>\n\n\n\n<p>function flatten(data, prefix = &#8220;&#8221;, out = new URLSearchParams()) {<\/p>\n\n\n\n<p>&nbsp;&nbsp;for (const [key, value] of Object.entries(data)) {<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;const name = prefix ? `${prefix}[${key}]` : key;<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;if (value !== null &amp;&amp; typeof value === &#8220;object&#8221;) flatten(value, name, out);<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;else out.append(name, value ?? &#8220;&#8221;);<\/p>\n\n\n\n<p>&nbsp;&nbsp;}<\/p>\n\n\n\n<p>&nbsp;&nbsp;return out;<\/p>\n\n\n\n<p>}<\/p>\n\n\n\n<p>async function call(method, path, body) {<\/p>\n\n\n\n<p>&nbsp;&nbsp;const res = await fetch(`${BASE}\/${path}`, {<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;method,<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;redirect: &#8220;manual&#8221;,<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;headers: { username: USERNAME, token: token() },<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;body: body ? flatten(body) : undefined,<\/p>\n\n\n\n<p>&nbsp;&nbsp;});<\/p>\n\n\n\n<p>&nbsp;&nbsp;const text = await res.text();<\/p>\n\n\n\n<p>&nbsp;&nbsp;let data = null;<\/p>\n\n\n\n<p>&nbsp;&nbsp;try { data = JSON.parse(text); } catch {}<\/p>\n\n\n\n<p>&nbsp;&nbsp;if (data &amp;&amp; typeof data === &#8220;object&#8221;) {<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;if (data.error) throw new Error(data.error);<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;if (String(data.result ?? &#8220;&#8221;).toLowerCase() === &#8220;error&#8221; || data.success === false) {<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw new Error(data.message ?? &#8220;Truehost reported a failure&#8221;);<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;}<\/p>\n\n\n\n<p>&nbsp;&nbsp;}<\/p>\n\n\n\n<p>&nbsp;&nbsp;if (res.status &gt;= 400) throw new Error(`HTTP ${res.status}`);<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Search<\/strong>: POST \/domains\/lookup. Show &#8220;unknown&#8221; results as &#8220;try again&#8221;, never as &#8220;taken&#8221;.<\/li>\n\n\n\n<li><strong>Price<\/strong>: charge your customer your own selling price. Keep it above your cost from GET \/tlds\/pricing.<\/li>\n\n\n\n<li><strong>Take payment<\/strong> from your customer.<\/li>\n\n\n\n<li><strong>Check balance<\/strong>: GET \/billing\/credits covers the cost.<\/li>\n\n\n\n<li><strong>Register<\/strong>: POST \/order\/domains\/register.<\/li>\n\n\n\n<li><strong>Confirm<\/strong>: POST \/domains\/{domain}\/sync. Mark the domain active only if it is in your account.<\/li>\n\n\n\n<li><strong>Nameservers<\/strong>: GET \/domains\/{domain}\/nameservers. If empty, POST the ordered ones.<\/li>\n\n\n\n<li><strong>Store<\/strong> the expiry date from sync.<\/li>\n<\/ol>\n\n\n\n<p>&nbsp;&nbsp;return data;<\/p>\n\n\n\n<p>}<\/p>\n\n\n\n<p>console.log(await call(&#8220;GET&#8221;, &#8220;billing\/credits&#8221;));<\/p>\n\n\n\n\n<h2 id=\"recommended-intergration-flow\">19. Recommended integration flow\n<\/h2>\n\n\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Selling a domain<\/strong><\/h3>\n\n\n\n<p>If step 5 or 6 fails, keep the order <strong>pending<\/strong>, show the error to your staff, and retry once the cause (usually balance) is fixed. Do not register the same domain twice: run step 6 before any retry, because the first attempt may have succeeded.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Daily jobs<\/strong><\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><strong>Job<\/strong><\/td><td><strong>Calls<\/strong><\/td><\/tr><tr><td>Synchronise every domain<\/td><td>POST \/domains\/{domain}\/sync (expiry, status) and GET \u2026\/nameservers<\/td><\/tr><tr><td>Follow transfers<\/td><td>POST \/domains\/{domain}\/transfersync for each pending transfer<\/td><\/tr><tr><td>Watch the balance<\/td><td>GET \/billing\/credits; alert below a threshold<\/td><\/tr><tr><td>Renew<\/td><td>Invoice your customers before expiry; call POST \/order\/domains\/renew once paid<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>Spread the sync calls over time (for example one per second) rather than sending hundreds at once.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Good practice<\/strong><\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Log<\/strong> every request and response, without the token header, API key or EPP codes.<\/li>\n\n\n\n<li><strong>Retry<\/strong> only on network errors and HTTP 5xx, with backoff. Never retry an order blindly: check with sync first.<\/li>\n\n\n\n<li><strong>Time out<\/strong> at 60 seconds or more for orders.<\/li>\n\n\n\n<li><strong>Keep your clock<\/strong> synchronised with NTP.<\/li>\n<\/ul>\n\n\n\n<h2 id=\"troubleshooting\">20. Troubleshooting<\/h2>\n\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><strong>Problem<\/strong><\/td><td><strong>Cause and fix<\/strong><\/td><\/tr><tr><td>Every call fails with token is invalid<\/td><td>Wrong key, key from another Truehost site, or server clock off by an hour or more. Check against the<a href=\"https:\/\/claude.ai\/chat\/49748676-241b-4d96-9e39-4f1578022604#test-vector\"> test vector<\/a><\/td><\/tr><tr><td>username is invalid<\/td><td>The account is on another Truehost site. Use that site&#8217;s base URL<\/td><\/tr><tr><td>An HTML page instead of JSON<\/td><td>Wrong base URL, or a server or proxy error. Check the URL includes \/cloud\/modules\/addons\/DomainsReseller\/api\/index.php<\/td><\/tr><tr><td>Action not found<\/td><td>Wrong path or method. Compare with the<a href=\"https:\/\/claude.ai\/chat\/49748676-241b-4d96-9e39-4f1578022604#6-endpoint-summary\"> endpoint summary<\/a><\/td><\/tr><tr><td>A POST behaves like a GET<\/td><td>Your HTTP client followed a redirect. Turn redirects off and call the exact base URL<\/td><\/tr><tr><td>Lookup results can&#8217;t be read<\/td><td>The response is PHP-serialised, not JSON. See<a href=\"https:\/\/claude.ai\/chat\/49748676-241b-4d96-9e39-4f1578022604#post-domainslookup\"> lookup<\/a><\/td><\/tr><tr><td>unavailable for sale<\/td><td>The extension or period isn&#8217;t in your price list. Ask Truehost to add it<\/td><\/tr><tr><td>Registration accepted but domain missing<\/td><td>Confirm with sync; check the balance; contact Truehost support with the time of the request<\/td><\/tr><tr><td>Contact changes lose fields<\/td><td>Send back every role and field from GET \u2026\/contact, not only the ones you changed<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>For account, pricing or balance questions, contact Truehost support through the client of your Truehost site.<\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Reference for integrating domain registration into your own website or software Version 1.0 (October 2026) Protocol HTTPS, REST-style paths Request format application\/x-www-form-urlencoded Response format JSON (one exception: domain lookup) Authentication Username plus an hourly HMAC-SHA256 token Time zone UTC for all times Standards ISO 8601 dates, ISO 3166-1 alpha-2 country codes, ITU-T E.164 phone numbers, [&hellip;]<\/p>\n","protected":false},"author":34,"featured_media":0,"comment_status":"open","ping_status":"closed","template":"","meta":{"_eb_attr":"","_exactmetrics_skip_tracking":false,"footnotes":""},"doc_category":[2152],"doc_tag":[],"class_list":["post-19366","docs","type-docs","status-publish","hentry","doc_category-truehost-reseller-panel"],"year_month":"2026-11","word_count":5251,"total_views":"5","reactions":{"happy":"0","normal":"0","sad":"0"},"author_info":{"name":"Faith Chelangat","author_nicename":"faithc","author_url":"https:\/\/truehost.com\/support\/author\/faithc\/"},"doc_category_info":[{"term_name":"Truehost Reseller Panel","term_url":"https:\/\/truehost.com\/support\/docs-category\/guides\/truehost-reseller-panel\/"}],"doc_tag_info":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.7 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Truehost Domains Reseller API -<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/truehost.com\/support\/knowledge-base\/truehost-domains-reseller-api\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Truehost Domains Reseller API -\" \/>\n<meta property=\"og:description\" content=\"Reference for integrating domain registration into your own website or software Version 1.0 (October 2026) Protocol HTTPS, REST-style paths Request format application\/x-www-form-urlencoded Response format JSON (one exception: domain lookup) Authentication Username plus an hourly HMAC-SHA256 token Time zone UTC for all times Standards ISO 8601 dates, ISO 3166-1 alpha-2 country codes, ITU-T E.164 phone numbers, [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/truehost.com\/support\/knowledge-base\/truehost-domains-reseller-api\/\" \/>\n<meta property=\"article:modified_time\" content=\"2026-11-03T09:33:05+00:00\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data1\" content=\"19 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/truehost.com\\\/support\\\/knowledge-base\\\/truehost-domains-reseller-api\\\/\",\"url\":\"https:\\\/\\\/truehost.com\\\/support\\\/knowledge-base\\\/truehost-domains-reseller-api\\\/\",\"name\":\"Truehost Domains Reseller API -\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/truehost.com\\\/support\\\/#website\"},\"datePublished\":\"2026-10-30T09:14:03+00:00\",\"dateModified\":\"2026-11-03T09:33:05+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/truehost.com\\\/support\\\/knowledge-base\\\/truehost-domains-reseller-api\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/truehost.com\\\/support\\\/knowledge-base\\\/truehost-domains-reseller-api\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/truehost.com\\\/support\\\/knowledge-base\\\/truehost-domains-reseller-api\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/truehost.com\\\/support\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Truehost Domains Reseller API\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/truehost.com\\\/support\\\/#website\",\"url\":\"https:\\\/\\\/truehost.com\\\/support\\\/\",\"name\":\"\",\"description\":\"Help In a Click\",\"publisher\":{\"@id\":\"https:\\\/\\\/truehost.com\\\/support\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/truehost.com\\\/support\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/truehost.com\\\/support\\\/#organization\",\"name\":\"Truehost Kenya\",\"url\":\"https:\\\/\\\/truehost.com\\\/support\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/truehost.com\\\/support\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/truehost.com\\\/support\\\/wp-content\\\/uploads\\\/2026\\\/04\\\/cropped-image_2026-04-16_174808866.png\",\"contentUrl\":\"https:\\\/\\\/truehost.com\\\/support\\\/wp-content\\\/uploads\\\/2026\\\/04\\\/cropped-image_2026-04-16_174808866.png\",\"width\":240,\"height\":48,\"caption\":\"Truehost Kenya\"},\"image\":{\"@id\":\"https:\\\/\\\/truehost.com\\\/support\\\/#\\\/schema\\\/logo\\\/image\\\/\"}}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Truehost Domains Reseller API -","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/truehost.com\/support\/knowledge-base\/truehost-domains-reseller-api\/","og_locale":"en_US","og_type":"article","og_title":"Truehost Domains Reseller API -","og_description":"Reference for integrating domain registration into your own website or software Version 1.0 (October 2026) Protocol HTTPS, REST-style paths Request format application\/x-www-form-urlencoded Response format JSON (one exception: domain lookup) Authentication Username plus an hourly HMAC-SHA256 token Time zone UTC for all times Standards ISO 8601 dates, ISO 3166-1 alpha-2 country codes, ITU-T E.164 phone numbers, [&hellip;]","og_url":"https:\/\/truehost.com\/support\/knowledge-base\/truehost-domains-reseller-api\/","article_modified_time":"2026-11-03T09:33:05+00:00","twitter_card":"summary_large_image","twitter_misc":{"Est. reading time":"19 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/truehost.com\/support\/knowledge-base\/truehost-domains-reseller-api\/","url":"https:\/\/truehost.com\/support\/knowledge-base\/truehost-domains-reseller-api\/","name":"Truehost Domains Reseller API -","isPartOf":{"@id":"https:\/\/truehost.com\/support\/#website"},"datePublished":"2026-10-30T09:14:03+00:00","dateModified":"2026-11-03T09:33:05+00:00","breadcrumb":{"@id":"https:\/\/truehost.com\/support\/knowledge-base\/truehost-domains-reseller-api\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/truehost.com\/support\/knowledge-base\/truehost-domains-reseller-api\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/truehost.com\/support\/knowledge-base\/truehost-domains-reseller-api\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/truehost.com\/support\/"},{"@type":"ListItem","position":2,"name":"Truehost Domains Reseller API"}]},{"@type":"WebSite","@id":"https:\/\/truehost.com\/support\/#website","url":"https:\/\/truehost.com\/support\/","name":"","description":"Help In a Click","publisher":{"@id":"https:\/\/truehost.com\/support\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/truehost.com\/support\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/truehost.com\/support\/#organization","name":"Truehost Kenya","url":"https:\/\/truehost.com\/support\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/truehost.com\/support\/#\/schema\/logo\/image\/","url":"https:\/\/truehost.com\/support\/wp-content\/uploads\/2026\/04\/cropped-image_2026-04-16_174808866.png","contentUrl":"https:\/\/truehost.com\/support\/wp-content\/uploads\/2026\/04\/cropped-image_2026-04-16_174808866.png","width":240,"height":48,"caption":"Truehost Kenya"},"image":{"@id":"https:\/\/truehost.com\/support\/#\/schema\/logo\/image\/"}}]}},"_links":{"self":[{"href":"https:\/\/truehost.com\/support\/wp-json\/wp\/v2\/docs\/19366","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/truehost.com\/support\/wp-json\/wp\/v2\/docs"}],"about":[{"href":"https:\/\/truehost.com\/support\/wp-json\/wp\/v2\/types\/docs"}],"author":[{"embeddable":true,"href":"https:\/\/truehost.com\/support\/wp-json\/wp\/v2\/users\/34"}],"replies":[{"embeddable":true,"href":"https:\/\/truehost.com\/support\/wp-json\/wp\/v2\/comments?post=19366"}],"version-history":[{"count":4,"href":"https:\/\/truehost.com\/support\/wp-json\/wp\/v2\/docs\/19366\/revisions"}],"predecessor-version":[{"id":19376,"href":"https:\/\/truehost.com\/support\/wp-json\/wp\/v2\/docs\/19366\/revisions\/19376"}],"wp:attachment":[{"href":"https:\/\/truehost.com\/support\/wp-json\/wp\/v2\/media?parent=19366"}],"wp:term":[{"taxonomy":"doc_category","embeddable":true,"href":"https:\/\/truehost.com\/support\/wp-json\/wp\/v2\/doc_category?post=19366"},{"taxonomy":"doc_tag","embeddable":true,"href":"https:\/\/truehost.com\/support\/wp-json\/wp\/v2\/doc_tag?post=19366"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}