Install and enable
Licence the Payment Gateway extension, switch it on, set the environment variable that makes checkout URLs reachable, configure the wallet types that gate every payment, and verify the three cron jobs.
The gateway ships as an extension of an already-working Bicrypto install. There is no separate installer and no database migration you run by hand — the models are auto-synced with the rest of the schema on boot. What you do here is licence it, switch it on, and set the four things that are wrong by default.
Do the core install first. If the platform is not already serving traffic over HTTPS with a working cron process, nothing on this page will help.
Before you start
- A running Bicrypto install (frontend, backend and cron all up)
- Your CodeCanyon purchase code for item 61043226
- Outbound HTTPS to
updates.mashdiv.comfrom the app server - Shell access to run
pnpm updatorand restart PM2 - The Ecosystem addon, only if you intend to accept
ECOpayments
Steps
-
Activate the licence — in the admin panel, open Extensions, find Payment Gateway, and activate it with your purchase code. The activation endpoint (
/api/admin/system/extension) is licence-exempt, so this works even on a platform whose own licence is mid-renewal. -
Install the files — if you bought the addon after your last update, its files are not on disk yet. Download the release and run the updator from the project root.
pnpm updator -
Enable the extension row — flip the switch next to Payment Gateway in the Extensions list. This writes
status = trueon theextensionrow whoseproductIdis61043226and clears the settings cache. Nothing under/api/gatewayor/api/admin/gatewayresponds until it is on. -
Restart the backend and cron — routes are registered at boot.
pnpm restart -
Set
APP_PUBLIC_URL— see below. This is the step most installs miss. -
Configure allowed wallet types — see below. Until you do, every payment is rejected.
-
Grant the permissions — the admin screens and endpoints are gated by twelve
*.gateway.*keys. Assign them to whichever role staffs the queues.
APP_PUBLIC_URL is not optional here
The checkout URL returned by the payment API is built as
${APP_PUBLIC_URL}/${APP_DEFAULT_LOCALE}/gateway/checkout/pi_…. APP_PUBLIC_URL
ships empty in .env.example, and the fallback is http://localhost:3000.
The API returns 201 Created, the merchant's integration redirects the buyer,
and the buyer's browser tries to open a page on their own machine. Nothing
errors on your side. The merchant reports that "checkout is broken" and there is
no log line to find.
APP_PUBLIC_URL="https://exchange.example.com"APP_DEFAULT_LOCALE is not in .env.example at all. It defaults to en. If
your install runs on a different default locale, set it explicitly or every
checkout link will carry an /en/ prefix your router has to redirect.
Restart the backend after editing .env — it is read once at boot.
Allowed wallet types gate everything
gatewayAllowedWalletTypes is a JSON map of wallet type to
{ enabled, currencies }. Its default is an empty object, and an empty map
means no wallet type is enabled, which means:
POST /api/gateway/v1/payment/createfails with "Wallet type FIAT is not enabled for payments".- The checkout page offers the buyer no wallets to pay from.
- New merchants are created with the fallback
["FIAT"]/["USD"], which the platform check then rejects anyway.
Configure it under Extensions → Payment Gateway → Settings → Wallets before
you tell anyone the gateway is live. Enable each wallet type you want and list
the exact currency codes under it. The check is a literal includes() against
an upper-cased code, so usd and USD are not the same thing and a currency
that is enabled for FIAT is not enabled for SPOT.
A payment is checked twice: against the merchant's own allowedCurrencies /
allowedWalletTypes columns, and against this platform-wide map. A currency
present in one and absent from the other is rejected, with a different error
message each way — "not supported by this merchant" versus "not enabled for
payments". That wording is the fastest way to tell which list is short.
The three cron jobs
The gateway registers three jobs in the gateway category. They run in the cron
worker, not the API process.
| Job | Every | What breaks without it |
|---|---|---|
processGatewayPayouts |
60 min | No payout record is ever created. pending balances grow forever and no merchant can be paid. |
processGatewayWebhookRetries |
60 s | A merchant endpoint that is down for one minute loses the event permanently. |
processGatewayPaymentExpiry |
5 min | Abandoned sessions sit at PENDING forever and payment.expired never fires. |
Check them under Admin → System → Cron. If the whole category is missing, the extension row is off or the cron worker is not running.
processGatewayPayouts reads gatewayEnabled and skips the entire run when it
is off — while payments keep completing and crediting pending. Turning the
gateway "off" does not stop money arriving; it stops money leaving.
Permissions to assign
Twelve keys are seeded. Nothing grants them automatically except Super Admin.
| Key | Gates |
|---|---|
access.gateway.merchant |
The admin dashboard and merchant screen |
view.gateway.merchant |
Merchant list and detail |
edit.gateway.merchant |
Status, verification and merchant edits |
delete.gateway.merchant |
Deleting a merchant |
access.gateway.payment · view.gateway.payment |
Payment screens |
manage.gateway.payment |
Issuing an admin refund |
view.gateway.payout |
Payout list and detail |
edit.gateway.payout |
Approving and rejecting payouts |
view.gateway.refund |
The refund list endpoint |
access.gateway.settings · view.gateway.settings |
The settings screen |
Two notes that matter when you build a role:
- The payout screen has no page-level permission file. The
/admin/gateway/payoutpage itself is not gated; its data endpoints are (view.gateway.payout), so a staff member without them sees an empty screen rather than a 403. - Saving settings needs
edit.settings, notedit.gateway.settings. The settings screen writes through the core settings endpoint.edit.gateway.settingsguards a second, parallel endpoint the UI does not use. Give the role both if you want the screen to work.
See Permissions for how a key is derived and the places it has to exist.
Verify the install
From the app server:
curl -s -o /dev/null -w "%{http_code}\n" https://exchange.example.com/api/gateway/settings200 means the extension is enabled and licensed. 503 means the route
registered but the licence check failed. A 404 means the extension row is off
or the backend has not been restarted since you enabled it.
curl -s https://exchange.example.com/api/gateway/settingsThe response should include gatewayAllowedWalletTypes with at least one
enabled type and a non-empty currency list. {} or a missing key means step 6
was not done.
Signed in as a normal user, Gateway should appear in the main navigation and
/gateway should render the landing page. In the admin panel, Payment
Gateway appears under Extensions and needs access.gateway.merchant.
Admin → System → Cron should list Process Gateway Payouts, Retry Failed Gateway Webhooks and Expire Lapsed Gateway Payments, all idle rather than failed.
Register a merchant, approve and verify it, then use its sk_test_ key to
create a payment and open the returned checkoutUrl in a browser as a second
user with a funded wallet. A test-mode payment debits nothing and credits
nothing, but it exercises the wallet selection, the exchange-rate check and the
webhook path.
What is not installed for you
- No demo merchant, no seed data. The
gateway_*tables start empty. - No default currency configuration. The wallet map is
{}. - No reverse proxy change. The gateway lives under
/api, which your proxy already forwards. - No WooCommerce plugin on disk anywhere public. Merchants download it from
/gateway/integration, which zips it out of the backend source tree at request time. If your deployment strips non-TypeScript files frombackend/src, that download 500s with an explicit message telling you the plugins directory is missing.
Next: Merchant onboarding.