How it works and daily use
Once the bridge is paired and sync is enabled, it runs by itself. This page explains what it is actually doing, so that when something looks odd you know where to look instead of guessing.
The sync engine in plain languageโ
1. A change raises an eventโ
Every relevant change in WHMCS fires a WHMCS hook: a client is added or edited, a contact is created, an invoice is finalised, a payment lands, an order is placed, a service is provisioned or suspended, a ticket is opened or replied to.
The hook does not make an HTTP call. It writes a small event into an outbox table (mod_perfexbridge_outbox) and returns instantly.
If a WHMCS hook called Perfex directly, a slow or unreachable Perfex server would block a WHMCS admin page or a customer's checkout. Writing to a local table takes a millisecond and can never fail because of somebody else's network. Everything after that happens in the background.
2. The cron drains the queueโ
On every WHMCS system cron tick, the dispatcher takes a batch of due events out of the outbox and POSTs each of them to your Perfex installation over HTTPS.
Each request carries two headers alongside the JSON body: a timestamp, and an HMAC-SHA256 signature computed over that timestamp plus the exact request body, using your shared secret. Perfex recomputes the signature with its own copy of the secret and rejects anything that does not match, or whose timestamp is more than 300 seconds old.
You can force an immediate drain at any time with Run Sync Now on the WHMCS module page.
3. Failures retry, then dead-letterโ
A failed send is not lost, and it is not retried in a tight loop. It is rescheduled with exponential backoff: about 60 seconds after the first failure, then 2 minutes, 4, 8, and so on, capped at 6 hours between attempts.
After 15 attempts, which spans roughly 40 hours, the row is marked dead. Dead rows are never retried automatically and never pruned. They are your dead-letter drawer: the Dead events counter at the top of the WHMCS module page tells you how many there are, and the log row tells you why.
Dead-lettering means the same event failed for nearly two days for the same reason. Almost always the cause is one of four things: a currency missing in Perfex, a secret mismatch, a Free plan blocking a Pro event, or Perfex being offline. Fix the cause and re-queue the work. See Troubleshooting.
4. Pausing does not lose anythingโ
Unticking Enable Sync pauses delivery only. Hooks keep writing events into the outbox, so nothing is dropped while you are paused. Re-enable it and the backlog drains on the next tick, or immediately with Run Sync Now.
5. Echo suppression stops infinite loopsโ
Two-way sync creates an obvious hazard: WHMCS applies a change that came from Perfex, that write fires WHMCS's own hooks, and the change bounces straight back. Left alone, one edit would ping-pong forever.
The bridge prevents this with layered guards, applied on both sides:
- An in-request origin flag, set while the bridge is applying an inbound change, so writes it makes itself are not treated as fresh user edits.
- An entity and reply-ID map lookup, so a ticket reply the bridge just created is recognised rather than re-sent as new.
- A checksum comparison, which turns an event into a no-op when the data already equals the last-synced state.
Each side has its own origin flag, and the checksum acts as a backstop if a flag is ever bypassed. The guards deliberately fail open: if a guard cannot make a decision, one extra harmless send is preferred to a silently dropped update.
6. Housekeepingโ
Both sides run a self-throttled daily prune, at most once every 24 hours:
- delivered outbox rows older than 7 days are deleted;
- log rows older than 90 days are deleted;
- pending and dead rows are never pruned, because pending is undelivered work and dead is your dead-letter drawer.
What syncs, and in which directionโ
WHMCS to Perfex CRMโ
| Data | Free | Pro | What lands in Perfex |
|---|---|---|---|
| ๐ฅ Clients | โ | โ | A Perfex customer, plus a primary contact carrying the client's name and email |
| ๐ค Contacts | โ | โ | Additional contacts under the same Perfex customer |
| ๐๏ธ Client deletion | โ | โ | The Perfex customer is deactivated, not destroyed |
| ๐ Invoices | โ | โ | A Perfex invoice with line items, a tax row, matching totals, status, and the WHMCS invoice number in the admin note |
| ๐ณ Payments and transactions | โ | โ | A payment record against the mirrored invoice, with the gateway and transaction ID. Duplicates are refused |
| ๐ธ Refunds | โ | โ | The Perfex mirror is cancelled and annotated |
| ๐ Orders | โ | โ | A Perfex lead per order, or a note on the customer, or nothing, per Order Sync Target |
| ๐ฆ Services | โ | โ | Rows on the customer's WHMCS tab: product name, domain, status, billing cycle, amount and next due date |
| ๐ Domains | โ | โ | Rows on the same tab: registrar, status, expiry and next due date |
| ๐ซ Tickets and replies | โ | โ | A Perfex ticket under the customer, in the mapped department, with replies and status |
On the Free plan a client's status and notes travel in the payload but are not written into Perfex. Only client deletion acts on the Perfex record, by deactivating the customer.
Perfex CRM to WHMCS (Pro only)โ
| Change made in Perfex | What happens in WHMCS |
|---|---|
| Customer company info edited | The WHMCS client record is updated, subject to the conflict policy |
| Primary contact edited | The WHMCS client identity fields are updated, because the primary contact is the client identity |
| Non-primary contact edited | The matching WHMCS contact is updated |
| Staff replies to a mirrored ticket | The reply appears on the WHMCS ticket, attributed to your Ticket Reply Admin if set, otherwise to the Perfex staff name |
| Ticket status changed | The WHMCS ticket status follows |
Deleting a customer or a record in Perfex does not delete anything in WHMCS. Billing records are preserved regardless of what happens in the CRM. This is deliberate and is not configurable.
Known behaviours worth knowing before you rely on themโ
These are documented decisions, not bugs:
- Tickets created directly in Perfex stay in Perfex. They are never created in WHMCS, because a WHMCS ticket needs a client account and a support department that a CRM-side ticket may not have.
- Ticket status changed through the full Perfex ticket-settings form does not propagate. The single-ticket status dropdown, replies, bulk status changes and auto-close all sync correctly.
- Time logged on a per-ticket Perfex task is not synced back to WHMCS. The task exists for native Perfex timesheet reporting.
- Recurring-invoice cadence is not modelled. WHMCS invoices mirror as plain one-off Perfex invoices.
- Merging two WHMCS clients is not handled. After a merge, remap or remove the map rows for the absorbed client.
- A Perfex staff reply on a synced ticket can produce two customer emails, one from Perfex and one from WHMCS. If your customers live in the WHMCS client portal, disable the Perfex
ticket-replyemail template under Setup > Email Templates > Tickets.
Where the logs areโ
This is the section that saves the most time. People habitually look in the wrong place.
WHMCS side: the module's own pageโ
Go to Addons > Perfex CRM Bridge and scroll to Recent activity.
The bridge does not write to the WHMCS Activity Log under Utilities > Logs. Its own table is rendered as the Recent activity panel on the module page, and that is the only place to look on the WHMCS side.
The table shows the last 50 events, with these columns:
| Column | Meaning |
|---|---|
| Time | When the row was written |
| Dir | out for WHMCS to Perfex, in for Perfex to WHMCS |
| Event | For example client.upsert, invoice.upsert, cron.drain |
| Entity | client, contact, invoice, ticket, and so on |
| WHMCS ID | The record's WHMCS ID |
| Status | Green ok or red error |
| Message | The outcome, or the exact error text |
Just above it, the header line shows Queue pending and Dead events counts. Those two numbers are your health summary: pending should drain to zero within a cron cycle or two, and dead should stay at zero.
Perfex side: two panels on the settings pageโ
Go to Setup > WHMCS Bridge.
Recent inbound events lists what WHMCS has sent to this Perfex installation, with the event type, the WHMCS ID, the Perfex ID it mapped to, a status badge and a message. This is where a rejected request appears as an auth.rejected row, which means a signature or timestamp problem, almost always a secret mismatch. Rejected rows are capped at 10 per minute so a flood cannot fill your disk.
Outbound queue lists Perfex-side changes waiting to be pushed to WHMCS, with:
- pending and dead counts in the panel heading;
- one row per queued change showing the event, entity, status, number of tries, next attempt time and the last error;
- a plain-English explanation instead of a raw error where the cause is known. A 403 from an unlicensed WHMCS reads "Two-way sync requires Pro on the WHMCS side" with an upgrade link, rather than a JSON dump.
Only the latest 20 rows are shown. Delivered rows clear themselves after 7 days; pending and dead rows are kept.
Which log answers which questionโ
| Question | Look here |
|---|---|
| ๐ค Did my WHMCS change leave WHMCS? | WHMCS: Recent activity, direction out |
| ๐ฅ Did Perfex accept it? | Perfex: Recent inbound events |
| ๐ Is my shared secret wrong? | Perfex: auth.rejected rows in Recent inbound events |
| ๐ Did my Perfex edit reach WHMCS? | Perfex: Outbound queue, then WHMCS: Recent activity, direction in |
| โฐ Is the cron running? | WHMCS: the Cron delivering checklist row |
| ๐ Why is two-way sync silent? | Perfex: the WHMCS plan panel. If it says Free, that is your answer |
The backfill wizard (Pro)โ
Live sync only ever handles new activity. If you install the bridge on an established WHMCS installation, your existing clients and invoices are not in Perfex until you backfill them.
The Backfill wizard sits on the WHMCS module page, below the settings form. It queues your existing records onto the same outbox that live sync uses, so they inherit the same signing, retries, backoff and dead-lettering.
Scopesโ
Tick one or more:
| Scope | What it queues |
|---|---|
| Clients + contacts | Every client in range. Contacts ride along with their client automatically |
| Invoices | Every invoice in range |
| Services + domains | Every service and domain in range, populating the Perfex WHMCS tab |
Historical tickets do not sync. Only new ticket activity flows across after the bridge is live. This is a documented limitation, not a configuration problem.
Modesโ
| Mode | Behaviour |
|---|---|
| All history | Every record in the chosen scopes |
| Date range | Only records created inside a YYYY-MM-DD from and to window. An invalid range, for example a "from" later than a "to", is rejected with a clear message and nothing is queued |
| Only new (not yet synced) | Skips records that are already mapped. This is the mode to use for repeat runs |
The 500-entity cap and how to resumeโ
Each run queues at most 500 entities, so a backfill on a large installation cannot flood the queue or stall your cron.
When the cap is hit, the wizard tells you. The routine is:
- Click Queue Backfill. An information banner reports how many were planned, how many were queued, how many errored, and whether the run was truncated.
- Watch the Queue pending counter at the top of the page drain, either on the cron or with Run Sync Now.
- Re-run the wizard in mode Only new (not yet synced).
- Repeat until a run plans nothing new.
There is no risk of duplicates. Already-mapped records are skipped, and an event whose data already matches the Perfex side is answered as a no-op.
Two ordering rules that save you timeโ
A child record whose parent client is not yet in Perfex is answered "not mapped, will retry" and stays in the queue until the parent lands. Usually the queue's own ordering sorts this out. But if you backfill only services or invoices on an installation whose clients were never synced, those events retry for about 40 hours and then dead-letter.
Either tick Clients + contacts in the same run, or backfill clients first.
An invoice in a currency Perfex does not know is rejected and retried, and dead-letters after about 40 hours. Before backfilling invoices, add every currency your WHMCS clients use under Setup > Finance > Currencies in Perfex, using the exact ISO code.
Historical paid invoicesโ
Backfilled invoices that were already paid in WHMCS are settled in Perfex with a synthetic payment record, so they show as Paid rather than Overdue. Re-running a backfill does not create duplicate payments.
Everyday operationโ
Once you are set up there is very little to do. A short weekly glance at the WHMCS module page is enough:
| What to look at | Healthy |
|---|---|
| Setup checklist | All green, with grey on the licence row if you run Free |
| Queue pending | Small, and dropping between cron ticks |
| Dead events | 0 |
| Recent activity | Mostly ok rows |
| Perfex Outbound queue | 0 pending, 0 dead, on Pro two-way installs |
If anything on that list is wrong, Troubleshooting has the cause and the fix.