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
- The purchase code for Forex Broker & Investments — product ID 36668679 — from your MashDiv dashboard
- 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
- The Forex Broker & Investments card — click it to open the product page. The Forex & Multi-Asset Trading card beside it is the separate terminal product
- Its switch stays disabled, reading Activate license first, until the licence is activated
-
Open the Extension Manager — Admin → System → Extension Manager (
/admin/system/extension), heading Add-ons & Integrations. On the Extensions tab, or by searching for Forex, find Forex Broker & Investments and click the card — not the Forex & Multi-Asset Trading card next to it, which is the separate terminal product. Until the licence is activated the switch on the card is disabled and reads Activate license first. -
Activate the licence — on the product page press Activate License. Paste the purchase code from your MashDiv dashboard, optionally an email address for update notifications, and press Activate License. The screen confirms License Activated! and returns you to the product page a couple of seconds later. If the server has no outbound access, the License File tab on the same screen takes the licence certificate downloaded from your MashDiv dashboard instead, placed as
license.txtin thelicfolder at the project root.- Paste the purchase code here
- Activate License — then wait for the redirect back to the product page
- License File — the offline route, for a server with no outbound HTTPS
- The product's name and Product ID — 36668679 for this one
-
Install the release — back on the product page, now licensed, the Overview tab has a release panel. If it offers Install v…, press it; if it says Up to date on a product you have only just licensed, press Check for Updates once, then install whatever it offers. The Releases tab holds the notes for the version you are being offered — read them first.
Install downloads the release, verifies it and extracts it over the project root. It runs no migrations, builds nothing and restarts nothing, so finish it from a shell on the server:
pnpm updatorThat is the finalise chain — stop, dependencies, schema, seed data, frontend build, start — and it is what creates the seven tables below and the addon's routes. If the panel still says Up to date after the check there is nothing to download; go straight to the next step.
- Check for Updates, then Install v… when it is offered
- Releases — the notes for the version you are about to install
- The Enabled switch — step 4, not yet
-
Switch it on — turn the Enabled switch on, in the product page heading or on the card in the Extension Manager, which is usable now that the licence is verified. This is the product's only on/off switch; there is no separate settings screen and no
.envvariable. It takes effect without a restart: the admin screens and/forexappear at once, and the scheduler picks upprocessForexInvestmentson its next re-sync, within a minute. -
Confirm the surfaces appear —
Forex Broker & Investmentsshows up under Admin → Extensions → Investment Products, the user area answers at/forex, and/admin/system/cronlistsprocessForexInvestmentsunder theforexcategory.
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
Press Install v… on the product page's Overview tab in the Extension Manager, run pnpm updator, then read this. Several behaviours around money changed and
none of them are optional.
Forex accounts are single-currency now
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.
Investment payouts land in the forex account
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.
The admin deposit screen is a reversal screen
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.
A plan's duration must be one the plan offers
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.
Settlement pays the advertised percentage
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.
Withdrawal limits actually reset
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.
Deleting a plan or duration is refused while it is in use
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.