0.1.0First release

Crypto payments on your own server.

Turmite is a free, self-hosted payment gateway. Customers pay to addresses that your keys control. Your shop gets a signed webhook when the payment is complete.

curl -fsSL https://turmite.com/install.sh | sudo sh
  • MIT license
  • No fees
  • Works with JavaScript off

Nine networks. Native coins, USDC and USDT.

Tickers and networks
  • BitcoinBTC
  • MoneroXMR
  • EthereumETH USDC USDT
  • BaseETH USDC
  • PolygonPOL USDC USDT
  • BNB Smart ChainBNB USDC USDT
  • TronTRX USDT
  • SolanaSOL USDC USDT
  • TONTON
01 How a payment works

From checkout to cold wallet.

  1. 01

    Checkout

    Your shop creates a payment through the API. The customer opens the checkout page.

  2. 02

    Deposit address

    Each payment gets its own address. The checkout shows the amount and a QR code.

  3. 03

    Confirmations

    The worker watches the chain on your own nodes and counts confirmations.

  4. 04

    Webhook

    Your shop gets a signed webhook for each status. Ship when the status is finished.

  5. 05

    Cold wallet

    A later sweep moves the funds to your cold wallet. On Bitcoin and Monero they arrive there directly.

02 Checkout

A checkout that works with JavaScript off.

The payment page is plain HTML and CSS. A small frame reloads the status every four seconds. The motion is pure CSS and stops when the visitor asks for reduced motion.

  • Strict CSP. No third-party requests, fonts or scripts.
  • Your store name, logo, accent colour and light or dark theme.
  • QR code as inline SVG. Countdown to expiry in CSS.
  • A return button to your shop when the payment is complete.

Checkout pages

03 Integrate

Create a payment. Verify the webhook.

One request creates a payment and its deposit address. Each status change reaches your shop as a signed request. Code for Node, PHP, Python, Go and Ruby is in the webhook docs.

POST /v1/payment
curl https://pay.example.com/v1/payment \
  -H "x-api-key: $TM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "price_amount": 25,
    "price_currency": "usd",
    "pay_currency": "btc",
    "order_id": "ORDER-1001",
    "order_description": "Order 1001",
    "ipn_callback_url": "https://shop.example.com/turmite/ipn"
  }'
201 Created
{
  "payment_id": "5524759814",
  "payment_status": "waiting",
  "pay_address": "bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh",
  "pay_amount": 0.00041235,
  "pay_currency": "btc"
}
webhook.js
import crypto from 'node:crypto';
import express from 'express';

function verify(raw, headers, secret) {
  const ts = String(headers['x-turmite-timestamp'] ?? '');
  const sig = String(headers['x-turmite-signature'] ?? '');
  if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false;
  const mac = crypto.createHmac('sha256', secret)
    .update(`${ts}.`).update(raw).digest('hex');
  const want = Buffer.from(`v1=${mac}`);
  const got = Buffer.from(sig);
  return got.length === want.length && crypto.timingSafeEqual(got, want);
}

const app = express();
app.post('/turmite/ipn', express.raw({ type: 'application/json' }), (req, res) => {
  if (!verify(req.body, req.headers, process.env.TM_IPN_SECRET)) {
    return res.sendStatus(401);
  }
  const payment = JSON.parse(req.body);
  if (payment.payment_status === 'finished') markPaid(payment.order_id);
  res.sendStatus(200);
});
04 Migrate

Point your shop at your own server.

Turmite keeps the paths, fields, statuses and IPN signature of the common hosted-gateway API. Change the base URL, the API key and the IPN secret. The rest of your code stays the same.

  • Same endpoints under /v1/, same payment object.
  • IPN signed with HMAC-SHA512 over the key-sorted JSON body.
  • Set the signature header name to the one your code reads.

Migration checklist

05 Custody

Keys stay off the server where the chain allows it.

The api process faces the internet and holds no private key. Only the worker can decrypt hot keys and the deposit seed. It opens no port.

  • Watch-only

    Bitcoin

    Turmite derives addresses from your BIP84 account xpub. Payments go straight to your wallet. The server holds no Bitcoin key.

    A server compromise cannot spend.

  • View key

    Monero

    Turmite reads incoming payments with your address and private view key. Payments go straight to your wallet.

    A server compromise cannot spend.

  • Deposit contract

    Ethereum, Base, Polygon, BNB Smart Chain

    Each payment gets a CREATE2 contract. It can only send to the cold wallet fixed in your factory.

    A server compromise cannot redirect deposits.

  • Swept

    Tron, Solana, TON

    Each payment gets its own key from the deposit seed. The worker sweeps the funds to your cold wallet.

    Unswept deposits are at risk until the sweep.

Security model

06 Pay with any coin

One wallet. More than 200 coins.

Connect your own Trocador API key. The customer pays in any coin that Trocador lists. The exchange sends your coin to the payment's deposit address.

  • Turmite credits only what arrives on chain at the deposit address.
  • A project with one stablecoin wallet can accept Bitcoin and Monero.
  • You choose the markup and the minimum KYC rating of the exchanges.

Pay with any coin

root@pay:~

$ curl -fsSL https://turmite.com/install.sh | sudo sh -s -- --site-url https://pay.example.com

  1. Mode: mainnet (real funds) or testnet [mainnet]:
  2. Hot-wallet passphrase (12+ characters):
  3. Wrote /data/.env and /data/secrets.
  4. Turmite 0.1.0 is running at https://pay.example.com
07 Self-host

One command on a Linux server.

The script installs a Docker Compose stack with PostgreSQL and Caddy for TLS. Then you create the root user in the browser and turn on two-factor.

  • One Rust binary. Two roles: api and worker.
  • Your own RPC nodes, with failover, set in the dashboard.
  • JSON logs, a /healthz endpoint and daily update checks.

Install on a server

08 Open source

A community project.

Turmite is MIT licensed. There is no hosted service, no fee and no account. Read the code, open an issue or send a pull request.