AI Investments, General Investment and Forex Investment
Three products share the WIN/LOSS/DRAW mechanic and the words "plan" and "duration" — this is which tables, screens, switches, KYC features and routes belong to each, and where they diverge.
This platform sells three separate earn products that look the same from a
distance. All three publish plans, attach durations to them, take a
principal, and settle at maturity as WIN, LOSS or DRAW. Two of them share
the same HTTP route, distinguished only by a type field. None of them shares a
table, a plan, an admin screen, a switch or a cron job with the others.
The cost of confusing them is not cosmetic. Editing a rate on the wrong console does nothing to the positions you were looking at, turning off the wrong switch stops the wrong product, and the admin "mark completed" action behaves differently on each of the three — on one of them it pays the customer, on another it writes a column and pays nothing.
Before you open a screen, decide which of the three the customer's position belongs to. The reliable tells are the route the customer bought it from and the transaction type on the debit:
| The customer bought from | It is | The debit reads |
|---|---|---|
The AI Investment tab inside /trade or /trade/pro |
AI Investments | AI_INVESTMENT |
/investment/plan |
General Investment | INVESTMENT |
/forex/plan |
Forex Investment | FOREX_INVESTMENT |
Staking is a fourth earn product with the same shape again, and it is not on this page.
The comparison
| AI Investments | General Investment | Forex Investment | |
|---|---|---|---|
| Ships as | The ai_investment addon |
Bicrypto core | The forex addon |
| Tables | ai_investment, ai_investment_plan, ai_investment_duration, ai_investment_plan_duration |
investment, investment_plan, investment_duration, investment_plan_duration |
forex_investment, forex_plan, forex_duration, forex_plan_duration |
| Admin console | /admin/ai/investment (Dashboard, Plans, Durations, Investment Logs) |
/admin/finance/investment/plan, /duration, /history — there is no index page |
/admin/forex/plan, /admin/forex/duration, /admin/forex/investment |
| Customer surface | The AI Investment tab in the trade order form; the list is in the Pro workspace Orders panel | /investment, /investment/plan, /investment/portfolio, /investment/[id] |
/forex/plan, /forex/investment, /forex/investment/[id] |
| Purchase endpoint | POST /api/ai/investment/log |
POST /api/finance/investment with type: "general" |
POST /api/forex/investment |
| Enable switch | The ai_investment extension row |
The investment platform setting |
The forex extension row |
| KYC feature id | invest_ai |
invest_general |
invest_forex |
| Settlement job | processAiInvestments, hourly, category ai_investment |
processGeneralInvestments, hourly, category normal |
processForexInvestments, hourly, category forex |
| Principal comes from | The wallet in the market's quote currency, SPOT or ECO |
The wallet named by the plan's currency and walletType |
The customer's LIVE forex account balance |
| Payout goes to | The same wallet | The same wallet | The LIVE forex account — never the wallet |
| Maturity | Computed from createdAt; there is no endDate column |
The endDate column, written at purchase |
The endDate column, written at purchase |
| Plan names a currency | No — the currency comes from the market being traded | Yes, currency + walletType |
Yes, currency + walletType |
| Permission keys | *.ai.investment, *.ai.investment.plan, *.ai.investment.duration |
*.investment, *.investment.plan, *.investment.duration |
*.forex.investment, *.forex.plan, *.forex.duration |
| Ledger rows | AI_INVESTMENT debit, AI_INVESTMENT_ROI credit, REFUND on cancel |
INVESTMENT debit, INVESTMENT_ROI credit, REFUND on cancel |
FOREX_INVESTMENT audit row on purchase only — the payout writes no transaction |
The three permission families are disjoint. A role holding every
*.investment* key can see none of the AI console and none of the forex
console, and vice versa. Grant them separately.
The three enable switches do different jobs
There is no umbrella "investments" control anywhere on this platform.
AI Investments is switched at /admin/system/extension, the ai_investment
row. It is a true master switch: it controls the admin menu entry, the purchase
tab in the trade panel, and whether the hourly settlement task is registered at
all. Turn it off and running investments stop settling for as long as it stays
off. This is covered in full on Configuration surface.
General Investment is switched by a platform setting, not an extension row:
It lives at Admin → System → Settings → Features → Investment. Three things
read it: the purchase endpoint, the customer menu, and the footer's
Products-section Investment link, which disappears along with the menu entry
when you switch it off. Nothing else does — in particular,
processGeneralInvestments does not consult it, so switching the product off
stops new money coming in and leaves existing positions settling normally.
That job is a core job: it is registered unconditionally and appears on
/admin/system/cron as Process General Investments on every install, whether
or not the setting exists. The fresh-install trap where the toggle reads on over
a row that was never written is documented on
General Investment: enable and configure.
Forex Investment is switched at /admin/system/extension, the forex row,
which gates the whole forex addon — accounts, deposits, withdrawals and signals
as well as investments. processForexInvestments is registered under the forex
category and is deregistered with the extension.
POST /api/finance/investment checks the investment setting before it
looks at the type field. With the setting off, a type: "forex" purchase
through that endpoint is refused too — even though the forex addon is enabled and
POST /api/forex/investment keeps working. Neither the forex route nor the AI
route reads the setting at all.
The three KYC features are independent
Each product asserts its own feature id, and the level builder lists them under Investment at Admin → CRM → KYC:
| Feature id | Label in the level builder | Asserted by |
|---|---|---|
invest_ai |
AI Investment Participation | POST /api/ai/investment/log |
invest_general |
Investment Products | POST /api/finance/investment when type is general |
invest_forex |
Forex Investment Plans | POST /api/forex/investment, and POST /api/finance/investment when type is forex |
That last row is the one to read twice. The shared endpoint chooses the feature
from the type it was given, precisely so a level you denied invest_forex
cannot open a forex position through the general product's door.
All three gates are inert unless both kycStatus and kycFeatureEnforcement are
on. kycFeatureEnforcement is off by default, so on a stock platform none of the
three is checked.
The shared routes, and the type field
Two of the three products are served by one pair of endpoints:
type is a BODY field here, not a query parameter.type is a QUERY parameter.The matching reads — GET /api/finance/investment and
GET /api/finance/investment/{id} — also take ?type=. The accepted values are
general and forex, matched case-insensitively. A missing value is refused
with 400 Invalid investment type on all four handlers, but an
unrecognised one is not handled evenly. Only the two writes reject it
cleanly: POST guards with an if (!model) check after its switch, and DELETE
has a default: that throws, both giving that same 400. Neither read does. The
single-investment read's switch has no default:, so ?type=bogus leaves the
model undefined and the query throws a TypeError — a 500, not a 400. The list
read does have a default: on its main switch, but a request carrying a type
and no page parameter never reaches it: that one is answered by the
active-investments branch, whose own switch has no default and fails the same
way. A 500 from either read is therefore usually a typo in type rather than a
platform fault.
Two companions on the same prefix are general-only and take no type at all:
GET /api/finance/investment/plan reads investment_plan, and
GET /api/finance/investment/stats counts investment rows. Neither ever
returns a forex or AI figure.
AI Investments is not on this route family. It has its own prefix,
/api/ai/investment/…, and no type switch. The type field on its purchase
body means something else entirely — it is the wallet type, SPOT or ECO,
which is why an AI investment row carries type = SPOT while a general one
carries no such column at all.
The forex branch of POST /api/finance/investment creates a forex_investment
row, but it debits the customer's wallet — the one matching the plan's
walletType and currency. The forex addon's own route,
POST /api/forex/investment, debits the customer's LIVE forex account.
processForexInvestments settles every forex_investment row into the LIVE
forex account regardless of which door created it. A position opened through the
shared route therefore takes the principal out of the wallet and returns the
payout to the forex account. Cancelling it through
DELETE /api/finance/investment/{id}?type=forex refunds to the wallet, while the
forex console's own status action refunds to the forex account.
No screen in the product calls the shared route with type: "forex" — the forex
pages all post to /api/forex/investment. The branch is reachable only by direct
API calls, including API keys acting as their owner. If you are scripting against
this platform, use the addon's own route for forex.
The forex branch of the shared route also skips checks the addon's own route
runs: it does not consult forex_plan_duration, so any duration can be paired
with any plan; it does not check plan.status, so a withdrawn plan still sells;
it does not require the terms acceptance the forex route demands; and it does not
run the forex fraud detector.
One rule that exists only on the shared route
POST /api/finance/investment refuses a second simultaneously-ACTIVE
investment in the same plan, with 400 Already invested in this plan. This
is enforced in application code, not by a database constraint, and it applies to
both branches of that route.
Neither POST /api/ai/investment/log nor POST /api/forex/investment has any
such rule. A customer can hold any number of concurrent AI investments in one
plan, and any number of forex investments in one plan. If you are sizing your
exposure, note that a plan's maxAmount caps a single ticket on all three
products and nothing caps the book.
Maturity is computed three different ways
This is the divergence that produces "my term is over and nothing happened" tickets, because two of the three products treat a month as 30 days and one treats it as a calendar month.
| Product | Where the maturity date comes from | A MONTH is |
|---|---|---|
| AI Investments | Recomputed on every cron pass from createdAt plus the duration. There is no endDate column on ai_investment |
30 days |
| General Investment | The endDate column, written at purchase by getEndDate. The cron reads the stored value and only falls back to a createdAt calculation for legacy rows with no endDate |
A calendar month — setMonth |
| Forex Investment | The endDate column, written at purchase. The cron reads the stored value, with the same legacy fallback |
30 days through POST /api/forex/investment; a calendar month through the shared route's forex branch |
A 12 MONTH term therefore matures after 360 days on AI Investments and
after a full calendar year on General Investment — five or six days apart on
identical-looking plans.
Two operational consequences:
- A general or forex maturity date can be edited; an AI one cannot. The
general console's edit form on
/admin/finance/investment/historywritesendDateas a plain column, and the cron honours it. AI Investments has no such column, so the only way to move an AI maturity is to settle the investment early from the Investment Logs status action. - All three settle up to an hour late. Every one of the three jobs runs on a 60-minute period, and none of the periods is configurable. A term that ends at 14:05 is paid on the next run. AI Investments additionally settles a customer's matured positions in-line when they open their own list; the other two do not.
Settlement: what is the same, and what is not
The payout arithmetic is identical on all three. With amount as the principal
and roi as the absolute return:
| Result | Credited |
|---|---|
WIN |
amount + roi |
LOSS |
amount - roi, floored at zero |
DRAW |
amount |
A LOSS is therefore not a total loss anywhere in this platform unless the
configured rate reaches 100%. On all three products the customer gets
max(0, principal − roi) back and the forfeited slice is booked as platform
revenue through the same shared helper, which credits it to the oldest Super
Admin's wallet. A WIN books the profit paid out as a platform loss. A DRAW
books nothing. The adminProfit rows are typed AI_INVESTMENT, INVESTMENT and
FOREX_INVESTMENT respectively, and are visible on
/admin/finance/profit.
What differs is where the money lands and what it leaves behind:
- AI Investments credits the wallet as an
AI_INVESTMENT_ROItransaction with reference<id>_roi, resolving the wallet from the original funding transaction first and from(user, type, quote currency)second. - General Investment credits the wallet as an
INVESTMENT_ROItransaction with reference<id>_roi, resolving the wallet from the plan'scurrencyandwalletType. - Forex Investment moves
forexAccount.balancedirectly and writes no transaction row at all. A settled forex investment is invisible in the customer's transaction history and in/admin/finance/transaction; the only records are theforex_investmentrow itself and theadminProfitentry.
The admin status actions are not equivalent
Three consoles, three "set the status" buttons, three different behaviours. This is the single most expensive confusion between the products.
| Console | Setting COMPLETED |
Setting CANCELLED or REJECTED |
|---|---|---|
/admin/ai/investment/log |
Settles it. Pays the derived terms into the wallet and books the platform's side, ignoring whether the term has expired | Refunds the full principal to the wallet |
/admin/finance/investment/history |
Writes the column only. No payout, no transaction, no platform entry | Writes the column only. No refund |
/admin/forex/investment |
Writes the column only. No payout | Refunds the full principal to the LIVE forex account |
On /admin/finance/investment/history, both the status action and the edit form
write status as a plain column. Flipping a running position to COMPLETED
there pays nothing — and because processGeneralInvestments only scans ACTIVE
rows, the cron will never look at it again. The record says the investment
completed while the customer received nothing, and there is no screen that will
now pay them.
The AI console refuses exactly this: its edit form rejects any status change
with a 400 and directs you to the status action, which settles properly. The
general console has no such guard. Read
The investment history desk
before you grant edit.investment to anyone.
Note also that AI completion pays the full profit regardless of how much of the term has elapsed. There is no pro-rating in any of the three products.
/investment is the General Investment product
The routes at /investment, /investment/plan, /investment/portfolio and
/investment/[id] belong to core's General Investment feature and read
/api/finance/investment. They have nothing to do with the AI Investments addon:
a plan created at /admin/ai/investment/plan never appears there, and the admin
shortcut from those pages points at /admin/finance/investment/plan.
/investment/dashboard and /investment/history are redirect stubs kept alive
because emails, notifications and the main menu have linked to them for years;
both land on /investment/portfolio.
The three Help pages in this documentation set — Investment plans,
Investment states and Investment problems — walk customers through
/investment/plan and /investment/portfolio. Those are General Investment
screens. They are filed here for historical reasons and are still correct for
what they describe; they are simply not about the addon whose operator pages you
are reading.
AI Investments has no standalone customer route at all. Its purchase form is
a tab inside the trade workspace and its list is a panel in the Pro workspace.
Any link of the form /ai/investment/<id> — including the one the completion
notification generates — is a 404 in this build, which is covered in
Troubleshooting.
Where to read next
For this addon, continue with Creating plans, Durations and The investment lifecycle, or Admin screens for the consoles.
For the other two products:
The switch, the KYC feature, the cron, the fifteen permission keys and the fresh-install trap that leaves the product off while the toggle reads on.
The debit, the stored maturity date, the payout arithmetic and the cancel refund.
Every field on a general plan, and why deleting a plan or a duration can destroy live positions.
What the forex create route checks, what the hourly cron pays into the forex account, and how to recover a failed settlement.
The forex plan fields and the join table that decides which terms a plan offers.
The four customer-facing general investment routes and the two redirect stubs.