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, install 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 purchase code for Payment Gateway (product ID
61043226), from your MashDiv dashboard - 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
- The Payment Gateway card — click it to open the product page
- Its switch stays disabled until the licence is activated
-
Activate the licence — go to Admin → System → Extension Manager (the page heading is Add-ons & Integrations). On the Extensions tab, or through the search box, find the Payment Gateway card — product ID
61043226— and click it. Until its licence is activated the card reads Activate and its switch is disabled with the tooltip Activate license first.On the product page press Activate License. Paste the purchase code from your MashDiv dashboard, optionally a Notification Email for update notices, and press Activate License. The screen confirms License Activated! and sends you back to the product page a couple of seconds later. Activation works even on a platform whose own licence is mid-renewal. If the server has no outbound HTTPS, the License File tab on the same screen takes the licence certificate downloaded from your MashDiv dashboard instead — place it as
license.txtin the/licfolder at the project root first.- Paste the purchase code here
- Activate License — then wait for the redirect back to the product page
- The offline route, for a server with no outbound HTTPS
-
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 at the project root:
pnpm updatorThat is the finalise chain — stop, dependencies, schema, seed data, frontend build, start. 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 3, 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. Nothing under
/api/gatewayor/api/admin/gatewayresponds until it is on, and the Gateway menu item does not appear for users. Turning it off later is the same switch; it leaves the licence in place, so switching back on needs no reactivation. -
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
- Open the Wallets tab
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 Admin → 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 gateway's Enabled switch 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
The routes are live
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 is
switched off or the backend has not been restarted since you enabled it.
The public settings endpoint returns your wallet map
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.
The menu appears
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 Admin → Extensions and needs access.gateway.merchant.
The cron category exists
Admin → System → Cron should list Process Gateway Payouts, Retry Failed Gateway Webhooks and Expire Lapsed Gateway Payments, all idle rather than failed.
A test payment completes end to end
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.