Premium Cloud Hosting!

Contact Info

Hostnali Webhost Limited

+254 748285257

[email protected]

ORDER NOW
Documentation — Domain Reseller Pro for WHMCS

Documentation

Domain Reseller Pro turns your WHMCS into a domain wholesale platform. This covers installation through to the reseller API.

Requirements

ComponentRequirement
WHMCS8.x
PHP8.1 or newer
PHP extensionscurl, zip, ionCube loader
RegistrarsAt least one registrar module configured and assigned to TLDs
Outbound HTTPSRequired, for licence validation
Reseller platformWHMCS 8.x, or Blesta (beta)

The zip extension is needed to package the registrar modules you give resellers. Without it everything else works, but module generation fails with an explicit message.

Installation

  1. Upload the drpro folder to modules/addons/ in your WHMCS. The result must be modules/addons/drpro/drpro.php.
  2. Go to Setup → Addon Modules, find Domain Reseller Pro and click Activate.
  3. Grant your admin role group access to it.
  4. Open the module and enter your licence key on the Licence tab.

Activation creates the module's own tables and seeds a default reseller group. It does not modify any WHMCS table.

Verifying the upload

A truncated upload is the most common installation problem and it is quick to rule out:

cd /home/user/your-whmcs
find modules/addons/drpro -name '*.php' \
  -exec /opt/cpanel/ea-php82/root/usr/bin/php -l {} \; | grep -v "^No syntax"

Silence means every file parses. Adjust the PHP path to match your server.

Deactivating is safe. It leaves all data intact, because reseller credit, domains and transaction history surviving a misclick matters more than tidiness. To remove the module completely, deactivate and then drop the mod_drpro_* tables.

Licensing

Your licence is tied to one WHMCS installation and validated against its domain, IP and directory. Enter the key on the Licence tab and press Save and verify.

What happens if it fails

An invalid or expired licence stops the module entirely — the admin screens, the reseller API and the reseller area. Your resellers cannot register, transfer or renew. Existing domains are untouched and nothing is deleted.

A network problem is not an expired licence. Each successful check is cached and honoured for several days if the licensing server cannot be reached. Only a genuinely invalid licence, or one that has not verified for the whole grace period, stops anything.

Moving to a new server

The licence checks domain, IP and directory, so any of those changing will invalidate it. Request a reissue before you migrate. The Licence tab's Last exchange panel shows exactly what was sent, which makes a mismatch obvious.

First-run checklist

  1. Check registrar routing — Settings → Registrar routing. Confirm your extensions map to the registrars you expect.
  2. Record your costs — Settings → Pricing → Costs. Nothing else can tell you whether a price is profitable.
  3. Set prices — Settings → Pricing. An extension with no resolvable price is silently excluded from what resellers can buy.
  4. Configure a group — permissions, TLD scope and pricing method.
  5. Create the registrar module for that group.
  6. Create a reseller in sandbox mode and test end to end before anyone spends real money.
  7. Install the client area menu — Settings → General → Client area menu.

Registrar routing

The module contains no registrar-specific code. For every operation it looks up which registrar module your WHMCS has assigned to that extension, under Setup → Products/Services → Domain Pricing, and calls it.

That means a mixed estate is the normal case. Different extensions can route to different registrars, and adding a registrar later requires no change here.

Settings → Registrar routing shows every registrar, whether it is still active, which extensions route to it, and what it can do.

An extension with no registrar cannot be sold. Orders for it would fail after the reseller had been charged, so it is excluded from the catalogue and shown as not sellable on the TLD catalogue screen.

Capability and permissions

Whether a reseller can perform an operation on a given domain is decided by three layers, all of which must allow it:

  1. Registrar capability — what the registrar handling that extension actually implements. Detected automatically; not configurable.
  2. Group permission — what you have enabled for their group.
  3. Reseller permission — any override on that individual reseller.

The first layer is why enabling a permission does not always make it available. Some registrars implement no DNS management at all, so DNS stays unavailable on their extensions however the switches are set.

The API permissions tab shows coverage per operation — how many of the group's extensions support it, and which registrars do not. That column is what to show a prospective reseller before they sign up.

Where DNS is unavailable, resellers use their own nameservers. Setting nameservers is supported everywhere, so a reseller points domains at their own DNS and manages records in their own system. Most prefer that anyway.

Credit and billing

A reseller's balance is their normal WHMCS client credit. Top-ups work through the payment gateways you already run, appear in their client area, and need no extra configuration.

What happens on an order

  1. The price is resolved for that reseller, extension, action and period.
  2. Their balance and daily spend cap are checked.
  3. A WHMCS order and invoice are created at your reseller price.
  4. The invoice is paid from their credit balance.
  5. The registrar is called.
  6. On success the order is activated and the domain marked active.

Renewals raise an invoice linked to the domain rather than an order, because WHMCS has no native concept of a renewal order.

Domains do not auto-renew through WHMCS. Reseller domains are created with renewal invoicing suppressed, because renewal is charged through the API instead. This is deliberate — otherwise both systems would think they were responsible for renewing.

When credit runs out

Registrations, transfers and renewals are declined. Everything else — DNS, nameservers, contacts, lock, EPP — keeps working, and existing domains are untouched.

Renewals being declined is the one that hurts. A reseller who runs dry loses their customers' domains to expiry. The module emails them when their balance falls below their threshold, when an order is declined for credit, and at 30, 14, 7 and 1 days before a domain expires that their balance cannot cover.

Failure handling

Registrar operations have three possible outcomes, and telling them apart is the difference between refunding correctly and giving domains away.

OutcomeWhat happens
SuccessTransaction settles, order activates, domain goes active.
Confirmed failureThe registrar returned a clear error. Credit is refunded and the order and invoice are cancelled.
AmbiguousA timeout, dropped connection or malformed response. Credit is held, not refunded.

The ambiguous case matters because a registrar that times out has very often completed the registration anyway. Refunding there hands out free domains to anyone who notices. Instead the transaction is parked, and the daily maintenance job asks the registrar what actually happened before settling or refunding.

Transactions awaiting verification are listed under Transactions → Needs verification and flagged on the dashboard.

Reseller groups

A group carries a complete configuration. Most installations run two or three: a restricted entry tier, a standard tier, and one for established partners.

Configuration

SettingEffect
API statusOff blocks all API traffic for the group.
IP address restrictionEnforces each reseller's allowlist.
API request restrictionEnforces each reseller's per-minute rate limit.
Show API documentationIncludes the API reference in generated modules.
Pricing methodCustom prices, or your own WHMCS TLD pricing.
Promotion codeApplied only with WHMCS pricing. Ignored if expired.
Payment collectionAt order, or after the registrar confirms.
Refund on failureRefund to credit, or no refund.
Allow trading beyond balanceLets an order through when credit falls short by up to the allowance. The invoice stays unpaid.
Daily spend capDefault cap for resellers in the group with none of their own.
Charge transfersAt submission, or on completion.
Abandon transfer afterDays before an unresolved transfer is refunded.
Ambiguous registrar resultHold and verify, or refund immediately.
Default registrantEnd client passed through, or the reseller's own details.
TLD availabilityAll sellable extensions, or only those assigned.

Leave "ambiguous result" on hold and verify. Refunding immediately is offered because it is your money, but a registrar timeout usually means the domain registered. The alternative gives domains away.

TLD assignment

With TLD availability set to assigned, a group sells only the extensions listed on its TLDs tab. Use Assign TLDs to add them; the picker shows only what is not already assigned, with search and a registrar filter.

Each assigned extension shows its registrar, feature summary, effective price, your cost and the resulting margin. The $ prices control opens an inline editor for that extension at that group's tier.

Removing an extension stops the group ordering new domains on it. Existing domains are unaffected.

Pricing

Prices resolve through four tiers, in order:

reseller override → group override → base list → your WHMCS TLD pricing

Each price is per extension, per action (register, transfer, renew), per year period and per currency.

The price grid

Settings → Pricing → Price grid. Choose a tier and currency. A cell shows its own value only if set at that tier; inherited prices appear greyed as placeholders.

  • Leave a cell blank to keep inheriting.
  • Type a number to override at that tier.
  • Type - to clear an override and inherit again.

Bulk update

Applies a rule across a selection — all extensions, one registrar's, or a specific list. Bases available are cost plus a markup, cost plus a fixed amount, your WHMCS price plus or minus a percentage, or a flat price. Rounding options include whole numbers, nearest 10/50/100, and .99 endings.

Always preview first. The preview shows what would be written and what would be skipped, and by default refuses to write any price below your recorded cost.

An extension with no resolvable price is not sellable. It is omitted from the catalogue entirely, so a reseller sees nothing rather than an error. If a reseller reports missing extensions, check pricing first.

Costs and margins

WHMCS records what you sell for, never what you pay. Without cost data no margin figure is possible, so this is worth doing before you set a single price.

Recording costs

Settings → Pricing → Costs. Paste them in, one per line:

.com,1200              # all actions, 1 year
.co.ke,900
.co.ke,renew,950       # one action
.net,register,2,2300   # one action, one period

Record cost in the currency you are actually invoiced in. Converting at today's rate would make last month's margin unreproducible.

Reading margins

Settings → Pricing → Margins shows cost, price and margin per extension and action — red below cost, amber under 10%, green above.

Cost means what you pay, not the registry fee. Anything routed through another provider's reseller module already carries their markup. That is exactly where a flat percentage across all extensions quietly earns very little.

Global settings

SettingPurpose
API enabledGlobal kill switch. Off stops every reseller immediately.
Default rate limitRequests per minute for newly created resellers.
Block premium domainsStrongly recommended. Premiums are routed to quotes instead.
Payment method for ordersWhat is recorded on reseller orders and invoices. They are paid from credit regardless.
Low credit thresholdDefault for new resellers, in their currency.
API log retentionDays before logs are pruned by the daily job.
Behind a proxy or CDNEnables reading the real client address from proxy headers.
Trusted proxy addressesProxy headers are believed only from these.
Client area menuInstalls the Domain Reseller Area menu item.

Working behind Cloudflare

Behind a proxy, the address WHMCS sees is the proxy's. An IP allowlist checked against that either locks everyone out or silently permits everything. Enable Behind a proxy or CDN and fill the trusted list — there is a one-click option for Cloudflare's published ranges.

Verify before relying on it. The settings page shows both the detected client address and the raw one. On a proxied request they must differ, and the detected one must be the reseller's real address. Until that is confirmed, leave IP allowlisting off rather than trusting it.

Response templates

Registrars return things like EPP 2302 or Object exists. Without a rule, that text travels through your API into a reseller's WHMCS and out to their customer at checkout — unhelpful, and it exposes a layer they were never meant to see.

Settings → Response templates maps a fragment of the raw error to a sentence you would be happy showing a stranger. Rules can be global or per group, matching on contains, exact text, or a regular expression. A hit counter shows which rules earn their place. Starter templates are available on an empty list.

Creating a reseller

A reseller is an existing WHMCS client plus a reseller record. On the Resellers tab, enter their client ID, choose a group, and click Create & issue key.

The API key is shown once. Only a hash is stored, so it cannot be displayed again.

Their credit balance is their WHMCS client credit, and every domain they sell lives under that client account.

API keys

Keys are shown once and stored hashed. A short prefix is retained so you can identify which key is in use without ever seeing it.

Rotation

Rotating issues a new key and keeps the previous one working for an overlap period — seven days by default. That lets a reseller switch over in their own time rather than during an outage. Both of you can see the old key's prefix, its expiry, and whether it is still being used, which is what tells you it is safe to revoke.

Choose revoke old now only when you believe a key has been exposed. It ends the overlap immediately and anything still using the old key starts failing.

Resellers can rotate their own key from their reseller area, with the same options.

Limits and sandbox

Daily spend cap

Rate limits bound how many requests a reseller can make; they do nothing about how much can be spent. A leaked key can drain a balance as fast as the API answers.

Set a cap per reseller, or a default on their group. Exceeding it declines the order, records it, and emails the reseller — the message says plainly that an unexpected run of orders can mean a compromised key. Zero means no cap.

IP allowlist

Blank allows any address. Otherwise one address or CIDR range per line, IPv4 or IPv6. Resellers can manage their own from their reseller area.

Sandbox mode

A sandbox reseller reaches no registrar and spends no credit, but exercises the entire request path. Availability is deterministic so both branches can be tested:

Domain containsResult
takenregistered
premiumpremium
anything elseavailable

Onboard every reseller in sandbox first. It is the only thing standing between a misconfigured integration and real registrations on your account.

Registrar modules

Each group has its own integration — the branded registrar module its resellers install. Different tiers can ship differently-named modules.

On Groups → Reseller module, set:

FieldNotes
PlatformWHMCS, or Blesta (beta).
Module slugLowercase letters and numbers. Becomes the directory and function prefix. Cannot be changed later.
NameShown in the reseller's registrar list.
API URLMust be reachable from your resellers' servers over HTTPS.
Additional fields fileShips a starting point for extensions that need extra data at registration, such as .us or .ca.
LogoPNG, JPG or GIF up to 512 KB.
DocumentationYour own guide, bundled with the module.

Pick the slug once. WHMCS keys domains to the registrar module name, so changing it later means every reseller reinstalls and every domain loses its registrar association.

Downloading builds the module fresh from the current template every time — there is no separate regenerate step, and you never need to delete an integration to pick up an update.

Reseller area

At index.php?m=drpro in your client area, resellers get:

  • Overview — balance, active domains, 30-day spend, expiring soon
  • Domains — searchable, with editable customer references
  • Pricing — their price list with per-extension features
  • Transactions — their charges in plain language
  • Quotes — request and accept premium or restore pricing
  • API access — key prefix, rotation, IP allowlist, limits
  • Downloads — their branded module, with update notices

Install the menu item from Settings → General → Client area menu. It appears under Domains, only for clients who hold a reseller account.

Importing domains

A client who bought domains directly and later became a reseller still has those domains under their account, invoiced at retail and invisible to the API. Importing links them to the reseller record.

Available from Resellers → import domains, or by the reseller themselves from their Domains page.

Importing changes how a domain is billed. WHMCS stops invoicing it; renewal then happens only when the reseller calls the API and is charged from credit. Usually cheaper for them, but it means an imported domain will not renew on its own.

Nothing at the registrar is touched — no transfer, no renewal, no modification. Domains already claimed by another reseller are excluded rather than moved.

Unlink on the admin Domains tab reverses it and restores WHMCS invoicing. The recurring amount is deliberately not restored, because there is no safe value to guess — set it manually.

Offboarding

When a reseller leaves, their customers' domains are still live under your account. Resellers → offboard gives three deliberate steps:

  1. Prepare transfer out — unlocks every active domain and retrieves its EPP code, so the reseller can move them elsewhere. Output is a copyable CSV.
  2. Release — marks the domains as released in this module. Local bookkeeping only.
  3. Close account — disables API access. Reversible from the reseller list.

The screen warns if credit is still on the account or transactions are still open, since both strand money.

Quoted orders

Premium registrations and expired-domain restores cost far more than list price and vary per domain, so they are priced individually rather than sold from the price list.

  1. The reseller requests a quote, from their reseller area or the API.
  2. You price it against real cost on Transactions → Quotes, setting how long it stays valid.
  3. They are emailed, and accept it.
  4. Credit is charged at the quoted price and the operation runs.

Nothing is charged until acceptance, and the price is fixed at what was quoted rather than re-derived. Quotes expire, because premium pricing moves — an expired one must be re-requested.

Price premiums as a fixed uplift, not a percentage. A percentage on a large premium produces a very large number.

Reports

Dashboard covers revenue and orders over a chosen window, active domains, reseller counts, credit held on account, a twelve-month revenue trend, top resellers, mix by extension and registrar, and expiry buckets.

Dashboard → Income statistics adds revenue and gross margin by reseller, extension and operation.

Revenue counts settled, paid transactions only. Held money is taken but not yet earned, refunds never count, and unpaid transactions appear as debt rather than sales. Margin is reported only across revenue with a recorded cost, and states what proportion that covers.

Renewal revenue is the number that compounds. A book that is mostly registrations has not started earning yet.

Maintenance

A daily job runs with the WHMCS cron and:

  • verifies ambiguous transactions against the registrar and settles or refunds them
  • syncs pending transfers, refunding any abandoned past the configured window
  • expires stale quotes
  • warns resellers about expiries their balance cannot cover
  • prunes API logs and expired overlap keys

Settings → General → Run maintenance now does the same work immediately, which is useful when testing.

API overview

Resellers using the generated WHMCS module never need this — the module calls the API for them. It is here for anyone building their own integration.

https://your-whmcs.com/modules/addons/drpro/api.php?endpoint=domains/register

Every response uses the same envelope:

{
  "success": true,
  "data": { },
  "error": null,
  "credits": 12450.00
}

credits is the live balance, returned on every response so a reseller can watch it without a second call.

Authentication

X-API-Key: drpro_xxxxxxxx_...

Optionally restricted by IP allowlist and rate limited per minute. Both are enforced only if the reseller's group has them enabled.

Idempotency

register, transfer and renew accept an Idempotency-Key header, and it should always be sent.

Idempotency-Key: your-order-reference

If a connection drops after a domain has been registered, retrying with the same key returns the original response rather than registering and charging again. The replayed response carries "replayed": true.

Keys are scoped per reseller, so they can safely use their own order numbers.

Endpoints

Catalogue

MethodEndpointPurpose
GETversionModule version
GETcreditsBalance and currency
GETtldsExtensions and pricing
GETcapabilitiesAvailable operations per extension
GETavailability&domain=…Availability check
GETsuggestions&term=…Domain suggestions

Ordering

MethodEndpoint
POSTdomains/register
POSTdomains/transfer
POSTdomains/renew
{
  "domain": "example.co.ke",
  "years": 1,
  "nameservers": ["ns1.example.com", "ns2.example.com"],
  "end_client_ref": "your-customer-id",
  "id_protection": false,
  "additional_fields": {},
  "registrant": {
    "firstname": "Jane", "lastname": "Doe",
    "companyname": "",
    "email": "[email protected]",
    "address1": "1 Example Road", "address2": "",
    "city": "Nairobi", "state": "Nairobi",
    "postcode": "00100", "country": "KE",
    "phonenumber": "700000000",
    "fullphonenumber": "+254.700000000"
  },
  "admin": { }, "tech": { }, "billing": { }
}

The registrant is the reseller's customer, and those details go to WHOIS. Admin, tech and billing default to the registrant if omitted. Transfers additionally take epp_code.

Managing

MethodEndpoint
GETdomains — list
GETdomains/{domain}
PUTdomains/{domain} — set customer reference
GET PUTdomains/{domain}/nameservers
GET PUTdomains/{domain}/contacts
GETdomains/{domain}/epp
GET PUTdomains/{domain}/lock
GET PUTdomains/{domain}/dns
GET PUTdomains/{domain}/email-forwarding
PUTdomains/{domain}/idprotection
POST PUT DELdomains/{domain}/private-nameservers
GETdomains/{domain}/sync
GETdomains/{domain}/transfer-sync

Management operations are free. They still depend on the registrar for that extension supporting them — check capabilities.

Quotes

MethodEndpoint
POSTquotes — request
GETquotes — list
GETquotes/{id}
POSTquotes/{id}/accept

Errors

HTTPTypeMeaning
401invalid_credentialsBad or missing key
402insufficient_creditBalance will not cover it
402spend_limit_reachedDaily cap reached; resets at midnight
403ip_deniedAddress not permitted
403account_suspendedAccount not active
404not_foundUnknown endpoint or resource
422invalid_requestMissing or malformed input
429rate_limitedToo many requests
502registrar_unverifiedAmbiguous registrar result
503service_unavailableProvider licence not valid

Never retry a 502 with a new idempotency key. The domain may well have been registered. Credit is held, not spent, and the daily job resolves it within 24 hours. Retrying with a fresh key can produce two domains and two charges.

Reseller install guide

What to send a reseller alongside their module and key:

  1. Upload the module folder to modules/registrars/ in their WHMCS. The directory name must match exactly — Linux is case-sensitive, and two copies differing only in case will fatal with a redeclaration error.
  2. Setup → Products/Services → Domain Registrars, find the module, Activate.
  3. Enter the API key.
  4. Setup → Products/Services → Domain Pricing, assign the extensions to buy through you. Extensions left pointing at their own registrars are unaffected, so adoption does not have to be all or nothing.

Enabling Debug Logging in the module configuration writes failures to Utilities → Logs → Module Log, which is the fastest way to diagnose their side.

Upgrading

Replace the contents of modules/addons/drpro/ and visit the module page once — schema changes apply automatically.

Do not overwrite lib/LicenseKey.php if you have customised it. Updates do not include it, so a normal extract cannot clobber it.

Do resellers need to reinstall?

Only when the generated registrar module itself changes, which is versioned separately. The Resellers list shows what each of them is running, and their reseller area tells them when they are behind. Everything else — API, billing, pricing, permissions, admin screens — takes effect immediately with nothing for them to do.

Troubleshooting

A reseller sees no extensions

Almost always pricing. An extension with no resolvable price is excluded from the catalogue entirely. Check the group's TLD scope too.

An operation returns "not available for this domain"

One of the three permission layers is refusing. Check the group's API permissions, and the coverage column — the registrar for that extension may not implement it at all.

"Not linked to your reseller account"

The domain exists in the reseller's system but not in yours. If they registered it with you before becoming a reseller, import it.

Registrar call fails with an undefined function

Some registrar modules expect WHMCS's legacy globals. The module loads them, but a registrar calling something unusual can still fail. The API log records the exact message.

A transaction is stuck awaiting verification

Expected after an ambiguous result. Run maintenance from Settings → General to resolve it immediately rather than waiting for the daily job.

Diagnosing anything else

The API log tab records every request with its response and status, with an errors-only filter. Contact details are stripped before anything is written, so it is safe to browse and safe to keep.

Data and privacy

Registrant contact details are passed to the registrar and not retained. Only the domain, an opaque customer reference supplied by the reseller, and billing records are kept.

Contact blocks are stripped from both requests and responses before anything is written to the API log, so those logs hold no customer personal data. Retention is configurable and pruned daily.

You are a processor, not a controller. Your reseller is the controller for their customers' data. A data processing addendum is worth having ready — any EU or UK company evaluating you as a supplier will ask for one before they buy.