Skip to content
For digital goods

Sell digital goods for crypto

Licence keys, accounts, downloads and game items, paid in Litecoin, USDT, Bitcoin or any coin we take. A signed webhook tells your store when to deliver.

CoinsFlow is a crypto payment gateway for stores that sell things delivered over the internet: keys, accounts, downloads, game items. Your store makes an invoice, the buyer pays it in Litecoin, USDT, Bitcoin or another coin we take, and a signed webhook tells your store to hand the product over. Small payments are fine: the fee is 0.5% of each one, and nothing else.

How it works

  1. A buyer checks out. Your store makes an invoice with POST /v1/invoices: the price in dollars, and the product and the customer in metadata, which the buyer never sees.
  2. The buyer is sent to the invoice's paymentUrl. With no coin named, they pick one there: Litecoin, Bitcoin, Ether, BNB, USDT or USDC. The page shows the address, the exact amount, a QR code and a countdown.
  3. When it is paid, invoice.paid reaches your webhook: on Litecoin at the first confirmation, about 2.5 minutes; with USDT on BNB Smart Chain in about 15 seconds.
  4. Your store delivers, once per invoice: it issues the key, unlocks the download, or adds the item to the buyer's account.
  5. The money is in your balance. Withdraw it to your own wallet, by hand or automatically.

A $6 licence key, in numbers

Price$6.00, in the coin the buyer picks, at the current price
PaidLitecoin: 1 confirmation, about 2.5 minutes. USDT on BNB Smart Chain: about 15 seconds. Bitcoin: about 10 minutes
Our fee$0.03 (0.5%), taken when the payment is credited. A $2 item pays $0.01
Buyer’s network feeLitecoin: usually a fraction of a cent. BNB Smart Chain: cents or less, paid in BNB. Bitcoin: what the network charges that day
In your balanceabout $5.97 worth of the coin

The invoice

POST /v1/invoices
{
  "priceAmount": "6.00",
  "orderId": "order-8812",
  "description": "Editor Pro, 1-year licence",
  "metadata": { "sku": "editor-pro-1y", "customer": "c_19f3" }
}

Send an Idempotency-Key with it, such as your order id: a retried request gets the same invoice back instead of making a second one. metadata comes back in every webhook. The amount in the coin follows the dollar price once an hour until it is paid, so send the buyer the link rather than a number. Every field is in the API docs.

The webhook delivers, once

POST /webhooks/coinsflow
import express from "express";

// Your products, by the sku the store put in metadata. Nothing else is ever delivered.
const PRODUCTS = {
  "editor-pro-1y": () => issueKey("editor-pro", 365), // your licence server
  "pack-starter": () => grantItems("starter"),         // your game's inventory
};
const app = express();

app.post("/webhooks/coinsflow", express.raw({ type: "application/json" }), async (req, res) => {
  if (!Buffer.isBuffer(req.body) || !verified(req.get("CoinsFlow-Signature"), req.body)) return res.sendStatus(400);
  const event = JSON.parse(req.body.toString("utf8"));
  if (event.type !== "invoice.paid") return res.sendStatus(200);
  if (event.test && !process.env.TESTING) return res.sendStatus(200); // test events only while you test
  const { id, orderId, metadata } = event.data;
  const deliver = PRODUCTS[metadata?.sku];
  if (!deliver) return res.sendStatus(200); // not one of the store's invoices
  try {
    if (!(await delivered(id))) { // your database: one delivery per invoice id, however often this is told
      const item = await deliver();
      await handOver(metadata.customer, orderId, item); // an email, a download page, the customer's account
      await markDelivered(id, item);
    }
    res.sendStatus(200);
  } catch {
    res.sendStatus(500); // CoinsFlow sends it again later
  }
});

app.listen(3000);

verified() is the signature check from the docs, over the raw body. Deliver by the invoice id, never by the order id alone: the same event can arrive again, and after a chain reorganisation an invoice can become paid a second time. Your endpoint must be an https:// address on the public internet; a store that cannot take requests can ask GET /v1/invoices/{id} instead. For an expensive item, wait for invoice.settled, when the network can no longer take the payment back.

Second payments and late ones

Every address we issue is watched for good. A buyer who pays a second time to a paid invoice, or pays after it expired, is not lost: the money is credited to you, and invoice.payment says so. A payment that is short by more than 0.5% makes the invoice underpaid, and the buyer can top it up to the same address; what comes after the invoice expired is credited with paidLate: true. You decide what to deliver in each case; the refund policy says what buyers are told.

What may be sold here

Sell what is yours to sell: keys, accounts, downloads and game items you own the rights to. Our terms (section 6) say what you may not do with the Service:

  • Use the Service for anything illegal where you or your customers are, including fraud, money laundering, sanctions evasion, or the sale of illegal goods or services.
  • Try to break, overload or reverse-engineer the Service, or access accounts or data that are not yours.
  • Resell access to the API as your own payment service without our written agreement.

We may ask for information about you, your business and your customers to meet our legal obligations. We may suspend an account that breaks these terms or that we reasonably believe is being used for fraud; suspension stops new invoices and API access but does not take your balance. A store for a game server has its own rules as well: see Minecraft server stores.

Test it first

Make the invoice with "test": true, then press the buttons on its payment page, or call POST /v1/invoices/{id}/simulate with paid, underpaid, overpaid or expired. Your store gets the same webhooks, marked "test": true, and no money moves. The code above acts on them only while TESTING is set, so a test never hands a product to a real customer.

Questions

Does the buyer need an account?

No. They open the payment page and pay from any wallet or exchange that can send the coin. The page shows a fresh address, the exact amount and a QR code. A buyer who holds the coin in a CoinsFlow balance can pay from it with Pay with CoinsFlow, and the invoice is final at once.

How do I deliver the product?

From your own store, when invoice.paid arrives: issue the key or the item, hand it over, and write down the invoice id so a repeated event never delivers twice. CoinsFlow does not store or send your products; it tells you, signed, that the money is in.

How small can a payment be?

As small as the coin’s own smallest amount: 0.0001 LTC, 0.01 USDT or USDC, 0.00001 BTC, 0.000005 ETH, 0.00002 BNB. A dollar price below the smallest amount of every coin it offers is refused with below_minimum. The fee is 0.5% whatever the size, with no fee per invoice and no monthly fee.

What if the buyer pays too little, or late?

If less arrives, invoice.underpaid says how much is missing: the buyer can send the rest to the same address, or you accept what came with POST /v1/invoices/{id}/accept. A payment that arrives after the invoice expired is still credited to you, with paidLate: true, and you decide whether to deliver.

Are there chargebacks?

No. A confirmed crypto payment cannot be reversed by the buyer or their bank. A refund is yours to decide: withdraw to the address the buyer gives you, from the dashboard or with POST /v1/withdrawals, for the usual withdrawal fee. Our 0.5% is not returned.

Should I wait for settled on a big order?

For a small item, invoice.paid is enough: on Litecoin it comes at the first confirmation. For an expensive one, deliver on invoice.settled, when the network can no longer reverse the payment; on Litecoin that is 2 to 12 confirmations by size, on BNB Smart Chain about 15 seconds after paid.

Can I test the store without money?

Yes. Make the invoice with "test": true and simulate the payment, from the API or with the buttons on its payment page. Your webhook gets the same events, marked "test": true, and no money moves. A merchant can make 500 test invoices a day.