Keagate is a self-hosted, high-performance cryptocurrency payment gateway. Payments can be administered via API for flexibility or with the built-in invoicing client (image below).
Supported currencies: Bitcoin, Ethereum, Dogecoin, Solana, Litecoin, Polygon, Dash, Ripple (coming soon), Tron (coming soon).
Funds go directly to your wallet via a one-time address that is generated for each payment.
The purpose of this installation script is to get Keagate up-and-running quickly in a Linux environment. The CLI will guide you in configuring, managing, and securing the instance.
bash -c "$(curl -sSL https://raw.githubusercontent.com/dilan-dio4/Keagate/main/packages/scripts/keagate.sh)"
Alternate:
curl -o keagate.sh https://raw.githubusercontent.com/dilan-dio4/Keagate/main/packages/scripts/keagate.sh
chmod +x keagate.sh
./keagate.sh
This helper script has been tested on...
...via AWS and Azure.
This script should run successfully on most flavors of Linux with some configuration. Otherwise, use the manual build, as it's fairly straightforward.
localhost:8081
8081
is the default port that Keagate runs on, can be changed via the PORT configuration option.nvm
to manage Node and NPM is recommended# +++ Don't have Node?
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash
nvm install 16
nvm use 16
# ---
npm i -g pnpm
pnpm setup
pnpm -g pm2
git clone https://github.com/dilan-dio4/Keagate
cd Keagate
pnpm i
pnpm run build
# +++ Configure Keagate with:
node packages/scripts/build/configure.js
# --- OR manually (see Configuration section)
pm2 start packages/backend/build/index.js --name Keagate --time
Keagate requires some configuration. This is done via a file called local.json
in /config
, next to default.json
. This file will automatically be used when you start Keagate. Note that parameters in local.json
will overwrite those in default.json
.
There are two methods to configure Keagate, and they can be used in conjunction with each other.
Keagate has a built-in CLI to build configurations in packages/scripts. After you've cloned and built the package. Head to the root Keagate directory and execute the following:
node packages/scripts/build/configure.js
Note โ this CLI is automatically launched in the one-liner installation script.
The CLI will write the config/local.json
file upon completion unless one already exists. In that case, it will write to config/local2.json
and ask that you manually merge your new parameters, as needed.
Create or open the file local.json
in /config
. You can use the provided default.json
file as a reference (your local.json
will override these).
The schema of the Keagate configuration can be seen (in TypeScript) at packages/common/src/config.ts.
To configure a single currency, add an object with the key of the currency's ticker with the following attributes:
Ticker can be one of 'LTC', 'BTC', 'ETH', 'DOGE', 'SOL', 'DASH', or 'MATIC'
. See example.
Key | Description | Required | Default |
---|---|---|---|
ADMIN_PUBLIC_KEY |
Public key (address) of your admin wallet | Yes | null (string) |
ADMIN_PRIVATE_KEY |
Private key of admin wallet. Only needed if you plan on programmatically sending transactions | No | null (string) |
This section details specific configuration parameters that should be handled with extra care. A malicious actor could manipulate the integrity of payments if they had access to these parameters.
There's a built-in script to securely generate and print these values at random:
node packages/scripts/build/setupSeeds.js
# OR
ts-node packages/scripts/src/setupSeeds.ts
# Prints
{
"INVOICE_ENC_KEY": "5036...9cc3",
"SEED": "eb08...3afc",
"KEAGATE_API_KEY": "9fac8f7d...c6568f97",
"IPN_HMAC_SECRET": "e50dd645...ea5baf54"
}
Key | Description | Required | Default |
---|---|---|---|
SEED |
Seed for transactional wallet generator. Must be a 128-bit hex string. Protect this value in production | Yes | null (string) |
KEAGATE_API_KEY |
Api key that will be required in administrative request's keagate-api-key header. Protect this value in production |
No | 'API-KEY' (string) |
INVOICE_ENC_KEY |
Key that will be used to encrypt payment IDs when distributed via invoice. Protect this value in production | Yes | null (string) |
IPN_HMAC_SECRET |
Key of the HMAC signature that is set in the x-keagate-sig header of each POST request when using Instant Payment Notifications. Protect this value in production |
No | null (string) |
Key | Description | Required | Default |
---|---|---|---|
IP_WHITELIST |
List of IP address ["1.1.1.1" , "2.2.2.2",...] to be whitelisted for administrative requests | No | [] (string[]) |
TRANSACTION_TIMEOUT |
Milliseconds by which payments will be valid for. After that, the payment is expired | No | 1200000 [20 Minutes] (number) |
TRANSACTION_MIN_REFRESH_TIME |
Minimum milliseconds by which transactions will idle between refreshes | No | 30000 [30 Seconds] (number) |
TRANSACTION_SLIPPAGE_TOLERANCE |
Percentage of a total payment that is discounted as slippage. Example: a TRANSACTION_SLIPPAGE_TOLERANCE of 0.02 for a 100 SOL payment will be fulfilled at 98 SOL. |
No | 0.02 (number) |
BLOCKBOOK_RETRY_DELAY |
Milliseconds to wait before re-trying a failed Blockbook request. | No | 5000 (number) |
MONGO_CONNECTION_STRING |
Connection string for MongoDB instance including any authentication. | No | 'mongodb://localhost:27017' (string) |
MONGO_KEAGATE_DB |
Mongo database to use for storing/managing payments | No | 'keagate' (string) |
IS_DEV |
For development only. Turn on testnets for given currencies and activate development features | No | false (boolean) |
HOST |
Your domain or IP that Keagate is running on. This is used for aesthetics and has no functional effect on Keagate | No | null (string) |
PORT |
The port that Keagate's backend API will run on | No | 8081 (number) |
Your config/local.json
could look something like:
{
"LTC": {
"ADMIN_PUBLIC_KEY": "MY_WALLET_ADDRESS",
"ADMIN_PRIVATE_KEY": "MY_PRIVATE_KEY"
},
"KEAGATE_API_KEY": "abcd123",
"IP_WHITELIST": ["1.1.1.1","2.2.2.2"]
// ...
}
The workflow for creating & confirming payments in the API-driven method is as follows:
Invoke the createPayment
route. Pass the following parameters in the JSON body:
"LTC"
)getPaymentsByExtraId
)Notify your customer to send the amount to the publicKey returned from createPayment
.
Wait for your customer to send the payment.
getInvoiceStatus
route on a timer from the customer's device to provide real-time updates. Note: this route doesn't return any sensitive information.Confirm and process the payment in your IPN route after receiving a CONFIRMED status of a payment of the same id or extraId.
The workflow for creating & confirming payments with the built-in invoice client is as follows:
Invoke the createPayment
route. Pass the following parameters in the JSON body:
"LTC"
)getPaymentsByExtraId
)Direct users to the URL route provided in the invoiceUrl
attribute returned from createPayment
.
Confirm and process the payment with either method:
Two query parameters are appended to this URL when customers are directed to it from the invoice client:
invoiceUrl
attribute of createPayment
).You must still confirm the payment server-side. This is because a malicious customer could just manually go to this route and set the status to CONFIRMED. On your backend, use getPaymentStatus
to actually validate the status.
Note: you can send either a true database id or invoice_id [which are just encrypted database ids] to getPaymentStatus
. Keagate can figure out which id it is based on the input length.
Once you've validated the payment status via a server-side request from the invoiceCallbackUrl page, you can confirm and process the payment as normal.
To be notified of payment updates in real-time, use instant payment notifications (IPN).
ipnCallbackUrl
attribute of your createPayment requests.Just like that, IPNs are all set up on Keagate. A POST request will be sent to the ipnCallbackUrl
with a JSON object like that of TypeForRequest.
Before using these notifications, the last thing to do is validate all incoming messages via HMAC.
The previously configured IPN_HMAC_SECRET is used as a key in the sha-512 HMAC signature generated for the x-keagate-sig
header of each notification.
Note: be sure to sort the request body alphabetically before generating your HMAC.
Here's a NodeJS example of validating this header in Express.
var crypto = require('crypto')
var express = require('express')
const app = express()
app.use(express.json())
app.post('/ipnCallback', (req, res) => {
// +++ Generate my signature
const hmac = crypto.createHmac('sha512', IPN_HMAC_SECRET)
hmac.update(JSON.stringify(req.body, Object.keys(req.body).sort()))
const signature = hmac.digest('hex')
// ---
if (signature === req.headers['x-keagate-sig']) {
// Good to go!
const id = req.body.id
// ...
} else {
// This notification may be spoofed...
}
});
Development experience and extensibility are the utmost priority of this package.
To get started:
pnpm
globally with npm i -g pnpm
cd Keagate && pnpm i
MONGO_CONNECTION_STRING
attribute in config/local.json
, along with some admin wallet credentials and the other required configuration parameters. For development, the Mongo Atlas free tier works great.pnpm run dev
to start the invoice client and backend.
packages/invoice-client/src
will be automatically reflected on refresh.packages/backend/src
will be reflected automatically via ts-node-dev
.config/local.json
have to be manually refreshed.The backend will run at 127.0.0.1:8081
. You can see your Swagger API docs at http://127.0.0.1/docs
. Also, a test IPN callback server will run at 127.0.0.1:8082/ipnCallback
and a test invoice client redirect static site will be available at http://127.0.0.1/dev-callback-site
.