Your Domain Reseller Plan lets you register and manage .tz domains from your own WHMCS (or from your own software) at wholesale prices. Registrations and renewals are charged to your reseller wallet; transfers are free. This page covers everything you need: where to find your credentials, how to install the WHMCS module, and the full API reference.
1. Where to find what you need
- Your credentials (API Key and API Secret): log in at billing.sakurahost.co.tz, open Services → Domain Reseller Plan. The page also shows your wallet balance, your wholesale prices and your domains.
- WHMCS module: sakurareseller-1.0.0.zip
- Top up your balance, any amount, any time: log in and use Add Funds. It is available as soon as the payment is confirmed. Your balance is your account credit; the module and the API charge it, and your service page shows the same figure.
2. Install the WHMCS module
- Download the zip and unzip it. Upload the
modulesfolder into the root of your WHMCS (it addsmodules/registrars/sakurareseller/). - In your WHMCS admin go to Configuration → System Settings → Domain Registrars, find Sakura .TZ Domain Reseller and click Activate.
- Enter your API Key and API Secret. Leave the endpoint as it is. Save.
- Go to Configuration → System Settings → Domain Pricing. Add the extensions you sell (
.co.tz,.or.tz,.ac.tz,.tzand every other .tz extension in your price list), set Auto Registration to Sakura .TZ Domain Reseller and set your own selling prices. Your wholesale prices are on your service page. - Place a test order for a domain you want. WHMCS registers it through the module and your wallet is charged automatically.
The module supports registration, renewal, transfer in, nameservers, registrar lock, EPP/auth code, contact details, expiry sync and availability search. Deleting a domain is not offered; contact support if you need one removed.
3. API reference
Use the API directly if you are not using WHMCS.
URL: https://billing.sakurahost.co.tz/modules/addons/sakura_reseller/api.php?endpoint=ENDPOINT
Method: POST with a JSON body (send {} when there are no fields).
Authentication
Every request carries three headers:
| Header | Value |
|---|---|
Authorization | Bearer YOUR_API_KEY |
X-Timestamp | Current Unix time in seconds (must be within 5 minutes of our clock) |
X-Signature | Lower-case hex of HMAC-SHA256(API_SECRET, TIMESTAMP + ":" + RAW_BODY) |
Sign the exact bytes you send as the body. Keep the API Secret on your server only; never put it in browser code or a mobile app.
# shell
BODY='{"domains":["example.co.tz"]}'
TS=$(date +%s)
SIG=$(printf '%s' "$TS:$BODY" | openssl dgst -sha256 -hmac "$API_SECRET" -hex | awk '{print $NF}')
curl -X POST "https://billing.sakurahost.co.tz/modules/addons/sakura_reseller/api.php?endpoint=domain/check" \
-H "Authorization: Bearer $API_KEY" -H "X-Timestamp: $TS" -H "X-Signature: $SIG" \
-H "Content-Type: application/json" -d "$BODY"
// PHP
$body = json_encode(['domains' => ['example.co.tz']]);
$ts = time();
$sig = hash_hmac('sha256', $ts . ':' . $body, $apiSecret);
$ch = curl_init('https://billing.sakurahost.co.tz/modules/addons/sakura_reseller/api.php?endpoint=domain/check');
curl_setopt_array($ch, [CURLOPT_POST => true, CURLOPT_POSTFIELDS => $body, CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Content-Type: application/json', "Authorization: Bearer $apiKey", "X-Timestamp: $ts", "X-Signature: $sig"]]);
$result = json_decode(curl_exec($ch), true);
Responses
Success: {"status":"success","data":{...}}
Error: {"status":"error","message":"..."}
| HTTP | Meaning |
|---|---|
| 200 | Done |
| 400 / 422 | Request or field problem; the message says which field |
| 401 | Authentication failed (key, signature or timestamp) |
| 402 | Wallet balance too low for this action |
| 403 | Not allowed: suspended account, domain limit reached, address not on your allow-list, or the domain is not in your account |
| 404 / 409 | Unknown endpoint / the domain already exists |
| 429 | Too many requests, or too many failed logins (wait 10 minutes) |
| 502 / 503 | The .tz registry returned an error or is unavailable. You are not charged when this happens |
Endpoints
| Endpoint | Body fields | Returns |
|---|---|---|
account/balance | none | balance, currency, tier, domain_limit, domains_used |
pricing/tlds | none | your register / renew / transfer price per extension |
domain/check | domains: array of up to 20 names | results: name → available / registered / unknown |
domain/suggest | query, optional limit | suggested names to check |
domain/register | domain, years (1-10), nameservers (2 to 10), registrant object | registered, expiry, charged |
domain/renew | domain, years | renewed, new expiry, charged |
domain/transfer | domain, auth_code | transfer_initiated, charged (always 0). Transfers are free and keep the domain's current expiry date |
domain/info | domain | status, locked, expiry, created, transfer_pending |
domain/list | none | every domain in your account with status and expiry |
domain/nameservers | domain; add nameservers (array) to change them | current nameservers, or updated |
domain/lock | domain, locked (true / false) | locked |
domain/contacts | domain; add registrant to change it | registrant details, or updated |
domain/eppcode | domain | a new transfer (auth) code |
The registrant object
{
"firstname": "Amina", "lastname": "Juma", "companyname": "Optional Ltd",
"email": "amina@example.com", "phonenumber": "+255.712345678",
"address1": "Samora Avenue 12", "address2": "", "city": "Dar es Salaam",
"state": "Dar es Salaam", "postcode": "11101", "country": "TZ"
}
Required: firstname, lastname, email, phonenumber, address1, city. Phone numbers are written like +255.712345678; a Tanzanian number such as 0712345678 is also accepted.
Example: register a domain
POST ...api.php?endpoint=domain/register
{"domain":"example.co.tz","years":1,
"nameservers":["ns1.yourdns.co.tz","ns2.yourdns.co.tz"],
"registrant":{ ...as above... }}
200 {"status":"success","data":{"domain":"example.co.tz","registered":true,
"expiry":"2027-10-26","charged":25000,"currency":"TZS"}}
4. How charging works
- Registration and renewal are charged from your wallet at your tier's price multiplied by the number of years, before the registry is asked. Transfers in are free.
- If the registry refuses the request, the charge is returned to your wallet straight away and recorded in your transactions. Invalid requests and name-already-taken replies are never charged.
- If your balance is too low you receive HTTP 402 and nothing is registered. Add Funds, then try again.
- If an extension is temporarily unavailable at the registry you receive HTTP 503 and are not charged. Try again later or contact support.
5. Limits and security
- Up to 120 requests a minute per IP address. Fifteen failed logins from one address block it for 10 minutes.
- You can only read or change domains that are in your own reseller account.
- For extra safety we can restrict your account to your server's IP addresses. Ask support and send the addresses.
- If your API Secret may have leaked, contact support immediately and we will issue new credentials.
6. Test with the sandbox
Build and test your integration without spending money. Your service page shows a separate Test API Key and Test API Secret (the key starts with test_). Use them exactly like the live ones: same endpoint, same headers, same signing. The only difference is that nothing real happens.
- No registry is contacted, nothing is charged, no email is sent and nothing is saved. Every answer carries
"sandbox": truenext to"status". - Names starting with
taken(for exampletakenshop.co.tz) show as already registered; names starting withlowfundsreturn the “balance too low” error (402); names starting withunknownreturn “unknown” at check. Any other valid name behaves as available and registers successfully. domain/listreturns two sample domains andaccount/balanceshows a fixed test balance of TZS 1,000,000.- Input is checked like the live API, so missing contact fields, bad name servers and unsupported extensions return the same errors.
When your tests pass, switch to your live key and secret.
7. Support
Email hello@sakuragroup.co.tz or WhatsApp +255 758 309 999. Please include the domain name and the exact message you received.
8. What is new
- 27 October 2026: sandbox test keys; health check at
?endpoint=ping; the reseller portal now shows your API domains, an API Activity page and an Integrations page with downloads. - 26 October 2026: every request is signed (
X-TimestampandX-Signature) and can be limited to your server IPs; one balance for the wallet and your billing account; transfers are free; a failed registration is refunded automatically; emails are sent only when something needs your action.