ROTLD Manager for WHMCS
This guide walks an administrator through installing, configuring and operating ROTLD Manager, the WHMCS module that integrates the Romanian National Top-Level Domain registry (ROTLD) into a billing system: cart, client area, admin panel, cron and email. Every screen referenced below ships in the module; nothing in this guide is roadmap.
1. About the module
ROTLD Manager is a pair of WHMCS plugins:
- A registrar module at
modules/registrars/rotld/that implements WHMCS’s domain lifecycle interface (rotld_RegisterDomain,rotld_RenewDomain,rotld_TransferDomain,rotld_GetContactDetails,rotld_SaveContactDetails,rotld_SaveNameservers, etc.). - An admin addon at
modules/addons/rotld_manager/that adds a 12-tab admin console for transactions, ad-hoc domain operations, saved registrants, registry messages, health check, TLD onboarding and email-template customisation.
Together with a handful of hook files under includes/hooks/rotld_*.php, they cover the full .ro lifecycle:
- Two-phase registration (reserve at order time, activate on payment) so the registrar balance is debited only when the customer actually pays.
- ROTLD-native registrant model (person types, CNP / CIF, J-number, correction window).
- Self-service DNSSEC, nameservers and glue records in the client area.
- Audit log of every API call with fees, balance after, registrant snapshot and full registry response.
- Daily registry poll with a single grouped digest email to admins.
- Branded post-registration confirmation email with EPP authcode and registrant details.
2. Installation
The module is delivered as a single archive that mirrors the WHMCS document root. After unpacking, the bundle merges into your install with no build step.
Back up your WHMCS files and database before installing any module. The activation hook creates database tables and the Theme Installer touches files under templates/twenty-one/ and includes/hooks/.
2.1 Copy the module files
Unzip the archive. Upload the contents of the whmcs/ folder into your WHMCS document root, preserving the folder structure. Existing files with the same names should be overwritten except lang/overrides/english.php and lang/overrides/romanian.php, see section 2.2.
# inside your WHMCS root modules/ registrars/rotld/ # the registrar module rotld.php # registrar entry points hooks.php # cart validation & transfer status lib/ApiClient.php # thin curl wrapper, Digest auth lib/Lang.php # in-module i18n helper lang/english.php # canonical English strings lang/romanian.php # Romanian translation theme-payload/ # Twenty-One template overlays addons/rotld_manager/ # the admin addon (12 tabs) widgets/RotldBalance.php # dashboard widget: balance widgets/RotldTransactions.php # dashboard widget: transactions includes/hooks/ rotld_reserve_on_invoice.php # reserve at order, activate at payment rotld_email.php # branded confirmation email rotld_dnssec.php # client-area DNSSEC AJAX endpoints rotld_ns_ajax.php # client-area nameserver AJAX endpoints rotld_daily_poll.php # daily registry poll digest rotld_registrant_sync.php # keep saved registrants in sync rotld_template_vars.php # cart i18n + template vars lang/ overrides/english.php # .ro additional-field labels overrides/romanian.php # (CNP, Registration Number, Type)
The bundled client-area templates and theme hooks live inside the registrar module under modules/registrars/rotld/theme-payload/. They are deployed to the active theme automatically by the addon’s Theme Installer in step 2.5.
2.2 Language overrides
The bundled lang/overrides/english.php and lang/overrides/romanian.php register the $_LANG[...] keys the order form uses to label the .ro additional fields. The bundled copies register three key shapes per field so the lookup resolves regardless of which dist of additionalfields.php your install uses:
CamelCase$_LANG['CNPFiscalCode'], the WHMCS 8 dist style.lowercase$_LANG['cnpfiscalcode'] and $_LANG['cnporfiscalcode'], the WHMCS 9 dist shapes.legacy$_LANG['rotldcnpfiscalcode'], the older prefix used by custom installs.Do not overwrite it. Open the bundled copies and append their $_LANG[...] lines to your existing file instead. The bundled copies only contain ROTLD strings, so a straight append is safe.
From v1.0.41 onwards the module also injects these labels at runtime via the hook includes/hooks/rotld_template_vars.php. From v1.0.43 the hook stamps all three key shapes on every cart.php request, so any cart template (configuredomains, nexus_cart, custom) resolves the localised label even when WHMCS does not auto-load lang/overrides/<lang>.php for the request. The override file is still bundled as a fallback.
2.3 File permissions
Set ownership of every uploaded file to your web server user (typically www-data on Debian / Ubuntu or apache on RHEL / Alma) and make sure they are readable. No file inside the module needs write permission.
# Example, adjust paths and user for your environment cd /var/www/whmcs chown -R www-data:www-data modules/registrars/rotld chown -R www-data:www-data modules/addons/rotld_manager chown www-data:www-data modules/widgets/RotldBalance.php chown www-data:www-data modules/widgets/RotldTransactions.php chown www-data:www-data includes/hooks/rotld_*.php chown www-data:www-data lang/overrides/*.php find modules/registrars/rotld modules/addons/rotld_manager -type f -exec chmod 644 {} \;
2.4 Activate the registrar module
- Open the WHMCS admin and go to Setup → Products / Services → Domain Registrars.
- Find ROTLD in the list and click Activate.
- Click Configure and fill in the registrar configuration form. The fields are documented in detail in section 3.1.
- Save changes. The credentials are stored AES-encrypted in
tblregistrars.
2.5 Activate the admin addon
- Go to Setup → Addon Modules.
- Find “ROTLD Manager” and click Activate. The activation hook creates the addon tables (
mod_rotld_transactions,mod_rotld_registrants,mod_rotld_poll_log,mod_rotld_email_template,mod_rotld_digest_template) and seeds the default templates. - Grant access to the admin roles that should see the addon.
- Open the addon at least once at Addons → ROTLD Manager. On first run the Theme Installer panel deploys the bundled client-area templates (
modules/registrars/rotld/theme-payload/twenty-one/) and three theme hooks (rotld_sidebar.php,rotld_template_vars.php,rotld_action_cards.php) into your active theme and intoincludes/hooks/. Use the panel to confirm or revert the deployment.
2.6 Enable the dashboard widgets
The archive ships two admin dashboard widgets:
- ROTLD Balance: current registrar balance with last-fetch timestamp.
- ROTLD Transactions: latest registry operations, click-through to the full audit log.
- Click your avatar in the top-right of the WHMCS admin and pick Edit Dashboard.
- Enable ROTLD Balance and ROTLD Transactions from the widget list. Drag them where you want them on the dashboard.
2.7 Set up the registrar in TLD pricing
- Go to Setup → Products / Services → Domain Pricing.
- For every .ro entry you offer, set the Auto Registration registrar to
rotld. - Save.
Bulk-enabling extensions and setting prices in a single matrix is also possible from the addon’s Setup TLDs wizard, documented in section 3.2.
Periodic tasks (poll messages, contact sync, etc.) are handled by the standard WHMCS daily cron. No additional cron entry is required once the addon is active.
3. Configuration
The first time you open Addon Modules → ROTLD Manager, the Setup TLDs tab walks you through a three-step onboarding flow. Each step shows a green / orange status badge so you always know what is done and what is pending.
3.1 Registrar credentials and options
The registrar configuration form at Setup → Products / Services → Domain Registrars → ROTLD → Configure exposes the full set of settings the module needs. Production and sandbox credentials live side-by-side: a single Test Mode toggle switches every call from production to the sandbox endpoint and back without losing either set of credentials. All secret fields are stored AES-encrypted in tblregistrars by WHMCS’s built-in EncryptPassword primitive.
Production RegidProduction PasswordProduction Api UrlTest RegidTest PasswordTest Api Urlhttps://rotest.ro.Test ModeAuto Renew With TransferReserve domain on orderAuto-manage Lookup ProviderClient Edit Window in hoursLicense Key- Open Setup → Products / Services → Domain Registrars.
- Find ROTLD in the list and click Configure.
- Paste your production credentials (Regid, Password, Api Url). If you have sandbox credentials too, paste them in the Test fields.
- Pick your toggles: leave Test Mode on while you exercise the flow against the sandbox, leave Reserve on order on, leave Auto-manage Lookup Provider on unless you have a specific reason to override.
- Enter your License Key and click Save Changes.
- Verify connectivity: open Addons → ROTLD Manager → Status and click Check Status. You should see the registrar name, server time and the list of methods you are authorised to call.
3.2 Enable TLDs and set pricing
From Addon Modules → ROTLD Manager → Setup TLDs, you can bulk-enable every .ro extension and set register / renew / transfer prices per currency, per year, in a single matrix, instead of stepping through WHMCS’s System Settings → Domain Pricing screen TLD by TLD.
Supported extensions:
.ro·.com.ro·.net.ro·.org.ro·.info.ro.biz.ro·.tm.ro·.nom.ro·.nt.ro·.store.ro.www.ro·.arts.ro·.firm.ro·.rec.ro
For each enabled TLD you also choose:
- DNS management: whether WHMCS’s DNS panel is offered for domains under this extension.
- Per-currency pricing: register / renew / transfer prices for years 1 through 10.
If your storefront already runs WHMCS’s default WhmcsDomains lookup provider, the wizard offers to switch it to Registrar and pin it to ROTLD for .ro lookups. Without this, the live availability check on the storefront falls back to WHMCS’s generic check, which doesn’t recognise the .ro reservation flow.
3.3 Install the storefront theme overlays
The third step copies the Twenty-One theme overlays (action cards row, ROTLD-aware sidebar, registrant block, DNSSEC card, glue-record forms) into templates/twenty-one/. The originals are not modified; the overlays sit alongside the stock files.
- Click Install Theme on the Setup TLDs step 3 panel.
- Verify by visiting the storefront: log in as a test customer, open the domain details page for any .ro domain and confirm the six-card action row appears above the overview.
- If you customise Twenty-One yourself, the overlays live in
templates/twenty-one/rotld/and are{include}-d from the main overlay files. You can edit them freely; the installer never overwrites your changes unless you click Reapply.
3.4 Upgrading from an earlier version
Upgrades are file replacements. Credentials, transaction history, saved registrants and email templates live in the database and are untouched. Open Addons → ROTLD Manager once after the upload so the Theme Installer can refresh the client-area payload to the version shipped with this release.
rotld_action_cards.php. Re-apply the Theme Installer at Addons → ROTLD Manager → Customization → Twenty-One Theme Integration → Re-apply so the new hook lands in includes/hooks/. Backups of prior copies are taken automatically.ns_modify.tpl prefix-input fix.rotld_template_vars.php hook.tblregistrars are unchanged. Client-area i18n extended to cart and three client-area pages. Re-apply the Theme Installer so the new translation hooks land in the active theme.Every upgrade preserves your data: credentials live in tblregistrars, transactions in mod_rotld_transactions, registrants in mod_rotld_registrants, and edited templates in mod_rotld_email_template / mod_rotld_digest_template. None of these tables are dropped or recreated by any release.
4. Client area
For .ro domains, the WHMCS client area is augmented in five places:
- An action cards row above the domain overview.
- A reordered, ROTLD-aware sidebar.
- A protected-information block on the contact information page (with the live correction-window countdown).
- Dedicated DNSSEC, glue-record and lookup cards.
- An EPP-code page with explicit deep-links to the rotld.ro portal.
4.1 Action cards row
Six colour-coded shortcuts appear above the domain overview: Overview, Auto Renew, Update Registrant, Nameservers, DNSSEC / DS Records, Get EPP Code.
If the target tab pane already exists on the current page, the card activates it inline without a reload; otherwise it navigates to the right page with the matching #tab… URL hash. The current card is highlighted as active.
4.2 Auto renew
The Auto Renew tab shows a green or red badge with the current state and a toggle to flip it. WHMCS handles the actual billing. The module only forwards the domain-renew call to ROTLD when the renewal invoice is paid. Renewal periods of 1–10 years are supported; the storefront only offers the periods that are priced in the active TLD configuration.
4.3 Update Registrant: correction window aware
The Update Registrant tab is split in two zones:
- Editable anytime: phone (with country dial-code split), email, address, city, postal code, state / county, country.
- Protected fields: full name, person type, CNP / fiscal code, registration number (J-number for companies). These are editable only inside the registry’s 24-hour correction window. After it closes, the panel switches to read-only and tells the customer to contact support before the 72-hour ROTLD window expires too.
The correction window is for fixing minor mistakes: a misspelt name, a wrong digit in the CNP. It is not a tool for changing the registrant. Changing the registrant is a separate registry operation called a trade, executed from the admin panel only.
4.4 Nameservers, lookup and glue records
The Nameservers tab includes three independent panels:
- Modify Nameservers: radio toggle between “use default ROTLD nameservers” and “use custom” (ns1 through ns5).
- Nameserver Lookup: enter any FQDN, get IPv4 / IPv6 addresses, status flags, registration date and how many domains use it.
- Private Nameservers / Glue Records: three styled cards for register, modify and delete, with hard validation (at least one IP, FQDN must match the current domain) and registry-side error surfacing.
4.5 DNSSEC self-service
The DNSSEC card lists every DS record currently published at ROTLD for this domain, with a delete button on each row. Below the list, a collapsible Add DS Record form takes four fields:
Key tagAlgorithmDigest typeDigestRegistry-side errors (invalid digest, mismatched DNSKEY, …) are surfaced inline next to the form so the customer can correct the input without leaving the page.
4.6 Get EPP code
ROTLD does not expose the EPP / Auth-Code over the REST API. The module surfaces this fact with two information boxes:
- Registrar Transfer Code: needed when the customer wants to move the domain to a different registrar. Linked to
https://www.rotld.ro/domadminwith explicit instructions. - Registrant Transfer Code: needed for a trade (change of registrant). Same external link, different context.
5. Admin panel
The admin addon is accessed from Addon Modules → ROTLD Manager in the WHMCS admin. A horizontal tab bar exposes the following sections, in order:
5.1 Transaction History
The default landing tab. Every operation the module ever performed against the ROTLD API lives here, append-only.
Stat cards at the top show counts and total fees per operation type. Operations recognised by the UI:
register reserve activate renew transfer trade contact-correct contact-update dnssec-add dnssec-remove nameserver-add
Below the stats, a filter row lets you narrow by domain (partial match), operation, and date range (from / to). The table itself paginates at 25 rows and includes:
- Domain column: clickable through to the WHMCS admin domain editor when the domain ID resolves.
- User column: either a customer link or a purple
ADMINbadge for admin-initiated operations. - Period, Fee (red), Balance after (green), Expiry, Date columns.
- A Details button that opens a rich modal with the full registrant snapshot, nameservers, domain password (if captured), and the raw API response.
5.2 Domain Operations
An ad-hoc console for running a single domain operation outside the customer billing flow. Pick a sub-action and fill the corresponding form. Every result lands as a row in the transactions table.
infoeppcoderenewtradedomain-trade with the new CID. The resulting Trade ID is stored against the row.trade_infotrade_confirmtrade_cancel5.3 Saved Registrants
A CRUD store of reusable registrant profiles. Each profile holds name, person type, phone (with country dial code split), email, full address, CNP / fiscal code, optional registration number, optional preferred domain password and the ROTLD CID once synced.
Use them to:
- Pre-populate the trade and register forms from a dropdown.
- Avoid creating duplicate ROTLD contacts for repeat customers.
- Bulk-prepare contacts ahead of a migration: create the records first, then click Sync to ROTLD to push each one to the registry and capture the CID.
5.4 Register a domain from the admin
Bypass the customer cart entirely. The Register Domain tab takes a domain name, a saved-registrant selector, a period (1–10 years) and an optional domain password.
The workflow:
- Check availability via
domain-check. - If available, create the contact via
contact-create(one CID per domain, ROTLD’s requirement). - Call
domain-registerordomain-reservebased on which button is clicked. - Log the operation with a registrant snapshot and the admin name as actor.
5.5 Domain Trade
Dedicated context for trade workflows. Mirrors the same form as Domain Operations trade, but isolated for clarity when you’re processing trade requests in bulk.
5.6 Registry poll & messages
Lists every message ever fetched from the ROTLD poll queue: expirations, transfer confirmations, transfer rejections, trade confirmations, trade rejections, deletions. Each row has a type tag, timestamp, the original domain (when applicable), the message body and the full JSON payload behind a View button.
5.7 Status & health check
One-click verification of registry connectivity. Internally calls the ROTLD hello command and displays:
- Environment: production (blue badge) or test (orange badge).
- REGID & REGNAME.
- Server time as reported by ROTLD.
- Round-trip latency.
- Authorised methods: the full list of API commands your registrar account is allowed to call.
Use this tab before opening a support ticket against the registry. If the hello call fails, the issue is networking or credentials, not the module.
5.8 Email templates & theme
Two editors and a theme installer share this tab:
- Registration confirmation email: sent immediately after a successful .ro registration. Placeholders for registrant name, person type, CNP, expiry date, EPP authcode, ROTLD CID and assigned nameservers.
- Registry messages digest email: sent once a day after the poll cron, summarising any new messages from the registry.
- Twenty-One theme installer: status badge (Installed / Partial / Not installed), Install, Reapply and Restore buttons.
Both editors are dual-pane: GrapesJS WYSIWYG on the left for content editors, CodeMirror on the right for technical users. Preview renders the email with sample data; Test send emails it to the currently logged-in admin.
6. Automation & hooks
Most of the module’s value lives in the hooks. They fire on standard WHMCS events. No separate scheduler.
6.1 Reserve-on-invoice → Activate-on-payment
The flagship automation. Splits .ro registration into two phases so the registrar balance is debited only when the customer actually pays.
reservation=1The reserve hook registers on three triggers (OrderAdded, InvoiceCreation, InvoiceCreationPreEmail) for redundancy. An idempotency check via mod_rotld_transactions.operation = 'reserve' guarantees the actual API call fires exactly once.
On payment, rotld_RegisterDomain first calls rotld_maybeActivateReserved:
- If a later activate or register row exists, returns idempotent success.
- If a reserve row exists, calls
domain-activate(no contact-create needed, since the reservation already locked the registrant). - If no reserve row exists (reserve hook failed earlier, or the toggle is off), falls through to the classic
domain-registerflow.
The activation branch is never gated on the reserve_on_order toggle. Once a reservation exists at ROTLD, payment must always activate it; otherwise the next register attempt would fail with “domain exists” and create a duplicate contact.
6.2 Branded post-registration email
Implemented in includes/hooks/rotld_email.php with multiple triggers (AfterRegistrarRegistration, PostModuleRegisterDomain, EmailPreSend) for redundancy. The EmailPreSend path suppresses the stock WHMCS “Domain Registration Confirmation” so customers never receive two messages for the same event.
Content includes registrant details (name, CNP, address), expiration date, ROTLD CID, the domain password (EPP authcode) and the assigned nameservers, pulled from the transaction row written during registration.
6.3 Daily registry poll digest
rotld_daily_poll.php hooks into DailyCronJob, with no separate cron entry needed. Each run:
- Fetches every unread message from the ROTLD poll queue.
- Stores them in
mod_rotld_poll_log, deduplicated by message ID. - Acknowledges them at ROTLD so they don’t re-trigger tomorrow.
- Composes a single digest email grouped by message type and sends it to admins.
If you need a faster cadence (for transfer-heavy registrars), there is an opt-in PreCronJob trigger commented out at the top of the file that polls every WHMCS pre-cron run (typically every 5 minutes).
6.4 Registrant auto-sync
Whenever a customer registers a .ro domain (AfterRegistrarRegistration) or edits their client profile (ClientEdit), rotld_registrant_sync.php updates the corresponding row in mod_rotld_registrants with the latest data. CNP / Tax ID / Fiscal Code / CUI / CIF act as the unique key.
6.5 Cart-side validation
The registrar’s own hooks.php registers ShoppingCartValidateDomainsConfig. This rejects checkout submissions where:
- Person type is p (private) but no CNP is provided.
- Person type is c (commercial) but neither CNP nor Registration Number is provided.
The cart then displays an inline error against the offending domain row and the customer can correct without losing their other configuration.
7. Tips
- Run a dry registration on
rotest.rofirst. SetApi_Urlto the test endpoint, place a test order, watch a reserve row appear, mark the invoice paid, watch the activate row land. Then flip back to production. - Customise the confirmation email before your first live registration. The default English template is sane, but adding your company name in the header and a CTA back to the client area saves customers an extra hop.
- Pre-create saved registrants for your top customers. One CID per domain at ROTLD means every new domain you register from the admin needs a registrant. Pre-populating the dropdown cuts data entry to a few seconds.
- Use the transaction filter as an audit tool. Looking up “who renewed what last month and how much did it cost” is a single date-range filter away. No SQL, no spreadsheets.
- Don’t enable the 5-minute poll cycle unless you need it. The default daily poll keeps the admin inbox tidy and is enough for most registrars. Increase frequency only if you actively process trades or transfers on tight timelines.
- If you customise the Twenty-One theme yourself, keep the overlays in
templates/twenty-one/rotld/separate from your main edits, so module updates don’t fight your branding.
8. Common problems
-
Status → Check Status returns “Authentication failed”
YourRegid,PasswordorApi_Urlis wrong, or one of them was saved with stray whitespace. Re-paste all three from your ROTLD onboarding pack at System Settings → Domain Registrars → ROTLD → Configure. WHMCS encrypts them at save time, so “peeking” afterwards isn’t possible. Re-enter to be sure. -
Order placed, invoice paid, but the domain stays Pending
The reserve hook failed silently at order time (ROTLD downtime, network blip), and the activate-on-payment branch is finding no reserve row to flip. Open Utilities → Logs → Module Log and filter by domain. If you see a Reserve Domain (on invoice) error, retry from Addon Modules → ROTLD Manager → Domain Operations with sub-actioninfoto check registry-side state, then issue a manualregisterfor the customer. -
Customer can’t edit the protected fields
The 24-hour customer correction window has closed. The panel correctly shows the fields read-only with a notice pointing to support. If still inside the 72-hour ROTLD support window, the admin can runcontact-correctfrom Domain Operations. Outside both windows, the only option is a domain trade. -
The action cards row doesn’t appear on the storefront
The Twenty-One theme overlays aren’t installed, or your customised theme overrides the{include}calls. Open Setup TLDs → Step 3 and click Reapply. If you maintain a fork of Twenty-One, port the{include file="rotld/action_cards.tpl"}directive from the stock overlay into your version at the top ofclientareadomaindetails.tpl. -
DNSSEC “Add DS record” returns an “invalid digest” error from the registry
The digest doesn’t correspond to a DNSKEY currently published in the zone, or the digest type and digest length don’t match (e.g. SHA-256 selected with a 40-char SHA-1 digest pasted in). Verify withdig DNSKEY example.ro +short, recompute the DS withldns-key2dsordnssec-dsfromkey, then re-submit. The form’s client-side hex check catches typos but cannot verify the cryptographic match. -
Daily poll digest email never arrives
WHMCS daily cron isn’t firing, or your transactional email setup is broken. Verify the WHMCS cron has run today (Utilities → Logs → Activity Log). If yes, force a manual poll from ROTLD Manager → Poll → Run now and see if a digest lands. If the digest sends to the admin but the customer-facing post-registration email doesn’t, the issue is WHMCS email config, not the module. -
“Domain already exists” error on activation
A reservation expired between order and payment, but areserverow is still in the transactions table, so the module tries to activate something that no longer exists at the registry. Use Domain Operations →infoto confirm the registry-side state. If the reservation has lapsed, register the domain fresh from Domain Operations →register. The new operation logs as a separate row; the old reserve stays for audit. -
Saved registrant shows “Not synced”
The registrant has never been pushed to ROTLD. It’s only stored locally. Click the green “Sync to ROTLD” button on the row. The module issues acontact-create, stores the resulting CID and the badge turns into the actual CID. Required before you can use that registrant for a register or trade. -
EPP code page just shows a link to rotld.ro
This is intentional. ROTLD does not expose the EPP / Auth-Code over the REST API. Direct the customer tohttps://www.rotld.ro/domadmin, where they can sign in with their CID and retrieve the code. The page text already includes this guidance in both EN and RO. -
Setup TLDs “Apply prices” saves but the storefront still shows old prices
WHMCS caches the domain pricing matrix; the new rows are in the database but the storefront is reading the cached version. Visit Utilities → System Cleanup → Empty Template Cache, then hard-refresh the storefront page in an incognito window. The new prices will appear in the next cart load.