Install and enable
Activating the Forex Investment addon — the licence flow, the seven tables it creates, the 36 permission keys, the four KYC gates, the hourly settlement cron and a smoke test that proves the whole chain works.
Activation is short. The work is what comes after it: a freshly enabled install
has no plans, no durations and no accounts, and a customer who reaches /forex
sees an empty product. Work through this page in order and finish with the
smoke test — it is the only thing that proves settlement actually runs on your
box.
Before you start
- Bicrypto core installed and running — see Installing Bicrypto
- Your CodeCanyon username and the licence code for item 36668679
- Shell access to the app server, for
pnpm updator - The cron process alive — check
/admin/system/cronshows jobs running - At least one currency your customers already hold in a FIAT or SPOT wallet
There is no Ecosystem prerequisite and no ScyllaDB prerequisite. This addon uses core's users, wallets, transactions, notifications, KYC and permissions and nothing else.
Activation
-
Open Admin → System → Extensions — the screen is at
/admin/system/extension. -
Activate — click the Forex entry, enter your CodeCanyon username and licence code, and confirm. The platform verifies the purchase before enabling anything.
-
Install the latest version — choose it from the version list and wait for the install to finish.
-
Enable it — toggle the extension on. This is the product's only on/off switch; there is no separate settings screen and no
.envvariable. -
Run the updator — from the project root:
pnpm updator -
Confirm the surfaces appear —
Forex Broker & Investmentsshows up under Admin → Extensions → Investment Products, and the user area answers at/forex.
What activation creates
Seven tables:
| Table | Holds |
|---|---|
forex_plan |
The investment plans — currency, limits, profit percentage, default result |
forex_duration |
Terms: an integer plus HOUR, DAY, WEEK or MONTH |
forex_plan_duration |
Which durations each plan offers. A plan with no rows here can never be invested in |
forex_investment |
One row per investment, with its principal, result and end date |
forex_account |
DEMO and LIVE accounts: broker, MetaTrader version, balance, leverage, withdrawal caps |
forex_signal |
Signals — a title, an image and a status |
forex_account_signal |
Which accounts see which signals |
Deposits and withdrawals do not get their own table. They live in core's
transaction table under the types FOREX_DEPOSIT and FOREX_WITHDRAW, and
each investment also writes an audit row of type FOREX_INVESTMENT. That is
why the deposit and withdrawal screens are gated on this addon's permissions
but read a core model.
If you build from source, run pnpm types:generate once the tables exist.
Permissions
Thirty-six keys ship with the platform's permission seeder. Assign them to the
roles that should administer the addon at /admin/crm/role.
| Screen | Route | Access | View / Create / Edit / Delete |
|---|---|---|---|
| Dashboard | /admin/forex |
access.forex |
— |
| Accounts | /admin/forex/account |
access.forex.account |
*.forex.account |
| Plans | /admin/forex/plan |
access.forex.plan |
*.forex.plan |
| Durations | /admin/forex/duration |
access.forex.duration |
*.forex.duration |
| Investments | /admin/forex/investment |
access.forex.investment |
*.forex.investment |
| Signals | /admin/forex/signal |
access.forex.signal |
*.forex.signal |
| Deposits | /admin/forex/deposit |
access.forex.deposit |
*.forex.deposit |
| Withdrawals | /admin/forex/withdraw |
access.forex.withdraw |
*.forex.withdraw |
* expands to view, create, edit and delete — so the accounts screen
uses view.forex.account, create.forex.account, edit.forex.account and
delete.forex.account.
The Forex Broker & Investments item in the admin extensions menu checks
access.forex.account, not access.forex. An operator granted only
access.forex can load the dashboard by URL but will not see the menu entry.
Grant both.
Two behaviours worth knowing about the admin API:
- Approving a withdrawal and reversing a deposit both need
edit—edit.forex.withdrawandedit.forex.depositrespectively. A read-only finance role cannot clear either queue. - Recovering a cancelled investment needs
edit.forex.investment. It is not a Super-Admin-only action, despite having behaved that way in older builds.
Nothing under /api/forex — the customer-facing half — carries a permission.
Every route there is scoped to the caller's own records. Who may use the
product is decided by KYC features instead.
KYC gates
Four verification features are enforced by this addon, configured per level
under Admin → CRM → Compliance & Verification → Verification Levels
(/admin/crm/kyc).
| Feature | Refuses |
|---|---|
deposit_forex |
Funding a forex account |
withdraw_forex |
Withdrawing from a forex account |
invest_forex |
Opening an investment |
create_forex_account |
Provisioning a new LIVE account |
All four are checked server-side. A customer whose verification level does not carry the feature is refused even if they call the API directly. This applies only on installs with verification enforcement switched on — with it off the platform is never stricter than the screens allow.
create_forex_account is deliberately not fatal to the rest of the page. A
customer who is not cleared to open a new live account still gets their demo
account and every account they already hold, so tightening your levels never
locks an existing customer out of their own balance.
view_forex and trade_forex exist in the platform's feature list but are not
checked by any route in this addon — trade_forex belongs to the
Forex & Multi-Asset Trading terminal.
The settlement cron
One job does all the settling. Find it at /admin/system/cron under the
forex category.
| Job | Every | Does |
|---|---|---|
processForexInvestments |
1 hour | Finds every ACTIVE investment whose end date has passed, settles it, and pays the result into the customer's LIVE forex account |
Nothing else in the product settles an investment. If the cron process is not
running, investments pass their end date and stay ACTIVE indefinitely — the
principal has already left the customer's forex account and nothing returns it.
Customers notice this within hours of your first short-duration plan maturing.
Check lastRun and lastRunError on that job before investigating anything
else about a missing payout.
The hourly period is also the resolution of the product. An investment on a one-hour duration settles on the next tick after its end date, not at the second it matures. Plan your shortest duration accordingly.
Smoke test
Do this on a staging install, or with a test user, before you announce anything. It exercises every part of the chain in about five minutes.
-
Create a duration —
/admin/forex/duration, add1 HOUR. -
Create a plan —
/admin/forex/plan. Give it a name, pick a wallet type and currency your test user actually holds, set min profit1, max profit20, profit percentage10, default resultWIN, minimum amount10, maximum amount1000. Attach the1 HOURduration. Set its status to active — plans are created disabled. -
Sign in as the test user and open
/forex/dashboard— a DEMO and a LIVE account are provisioned on first visit. -
Deposit — from the LIVE account card, deposit an amount you hold in the matching wallet. This settles instantly; the forex account balance should change on the spot.
-
Invest —
/forex/plan, open your plan, choose the 1-hour duration, accept the terms and invest. The forex account balance drops by the principal. -
Force settlement — rather than waiting, open
/admin/system/cron, findprocessForexInvestmentsand run it manually once the end date has passed. -
Check the payout — the investment reads
COMPLETED/WINat/admin/forex/investment, and the customer's forex account is back up by principal plus 10%. -
Withdraw — submit a withdrawal as the customer, then approve it at
/admin/forex/withdraw. The wallet is credited only at that point.
If step 7 does not happen, the cause is almost always one of: the cron is not running, the plan's duration was never linked, or the plan's currency does not match what the account was funded with. All three are covered in Troubleshooting.
Upgrading an existing install
Run pnpm updator, then read this. Several behaviours around money changed and
none of them are optional.
An account is locked to one currency and one wallet type the first time it is funded, and every later movement must agree. An existing account whose balance was built from more than one currency will refuse movements in anything but the first currency it is used with after upgrading. That is intentional — a mixed balance has no correct interpretation — but settle such accounts before you upgrade if you have any.
A matured investment used to pay straight into the spot wallet, which bypassed the approval every forex withdrawal requires. Payouts now return to the forex account the principal came from, and the customer withdraws them through the normal queue. Expect your withdrawal queue to get busier.
Forex deposits settle instantly, so there has never been anything to approve. The screen now reverses a completed deposit: the forex account gives back what it was credited, and the wallet is made whole for the amount and the fee. The amount is not editable.
Every duration on the platform used to be accepted against every plan. Because a plan's profit is a flat percentage that does not scale with time, that let a customer take a 30-day plan's full return in one hour. Check that each plan has the durations you intend attached — a plan with none can no longer be invested in at all.
Every screen showed the plan's profit percentage; settlement used the
separate default profit field, which defaults to 0. A plan advertised at
15% whose default profit was left alone paid exactly nothing on every win.
Settlement now uses the percentage the customer was quoted. If you compensated
for the old behaviour by inflating default profit, undo it.
The daily and monthly caps shared one anchor and the daily rollover overwrote it, so the monthly counter only reset after thirty consecutive days with no withdrawals. Active customers hit the monthly cap and were then locked out permanently. The two windows are tracked separately now — customers who were stuck will be able to withdraw again on upgrade.
forex_investment cascades from both tables at the database level, so deleting
a duration used to physically remove every investment on it — principal,
history and all. Deletion is now refused while active investments reference the
row. Cancel or settle them first; cancelling refunds.
If you deploy with DB_SYNC=none, run the backend once with sync enabled so
the new columns land — the account currency binding and the second withdrawal
anchor are both new columns on forex_account.