Skip to content
For donations and tips

Accept crypto donations

A pay-what-you-want invoice in Litecoin, Bitcoin, USDT or any coin we take. The donor needs no account. 0.5% per payment.

CoinsFlow is a crypto payment gateway creators, streamers and open-source projects can take donations through. A pay-what-you-want invoice has no price: the donor opens it, picks Litecoin, Bitcoin, USDT or another coin we take, and sends what they like. A signed webhook tells you when it is paid, and the money is in your balance to withdraw.

Two ways to take a donation

  1. No code. In the dashboard, press New invoice, choose Any coin they choose and leave the price empty: the form says Pay what you want. Add a description the donor sees, create it, and send the link under Share with the customer. One invoice is one donation; make another for the next donor.
  2. A Donate button. Your page has a button that calls POST /v1/invoices with openAmount: true and sends the donor to the new invoice's paymentUrl. Every click gets a fresh invoice, so the page always says pay what you want.

Either way the donor sees a fresh address, a QR code, the coins to pick from and the smallest amount that counts. Pasted into a chat, the link shows a preview that says what it is for.

A $10 donation, in numbers

Amountwhatever the donor sends: there is no price. The page shows the smallest amount of the coin that counts
Say the donor sends$10 worth of Litecoin
Seenseconds after it is sent: invoice.detected
Paidat 1 confirmation, about 2.5 minutes: invoice.paid, with amountPaid and its dollar value, usdValue
Our fee$0.05 (0.5%), taken in LTC when it is credited
Donor’s network feeusually a fraction of a cent, paid by the donor on top
In your balanceabout $9.95 worth of LTC, withdrawable at once

The Donate button

POST /v1/invoices
import express from "express";

const app = express();
app.use(express.urlencoded({ extended: false }));

// <form method="post" action="/donate"> with an optional "name" field and a Donate button, on your page.
app.post("/donate", async (req, res) => {
  const name = String(req.body.name ?? "").trim().slice(0, 40);
  const r = await fetch("https://api.coinsflow.app/v1/invoices", {
    method: "POST",
    headers: { Authorization: `Bearer ${process.env.COINSFLOW_API_KEY}`, "Content-Type": "application/json" },
    body: JSON.stringify({
      openAmount: true, // pay what you want, in the coin the donor picks
      description: "Support the channel",
      ttlSeconds: 604800, // a week to pay
      metadata: { source: "bio", ...(name ? { name } : {}) },
    }),
  });
  if (!r.ok) return res.status(503).send("Donations are not available right now. Try again in a minute.");
  const invoice = await r.json();
  res.redirect(303, invoice.paymentUrl);
});

app.listen(3000);

An invoice stays open for 3 to 7 days (ttlSeconds) and up to 10,000 may wait at once, so make them when someone presses the button, not when a crawler follows a link. metadata is never shown to the donor and comes back in every webhook. Every field is in the API docs.

The webhook says thank you

POST /webhooks/coinsflow
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, amountPaid, asset, usdValue, metadata } = event.data;
  try {
    if (!(await thanked(id))) { // your database: one thank-you per invoice
      const who = metadata?.name || "Someone";
      const worth = usdValue ? ` (about $${usdValue})` : "";
      await showOnStream(`${who} sent ${amountPaid} ${asset}${worth}. Thank you!`); // your overlay, chat bot or page
      await markThanked(id);
    }
    res.sendStatus(200);
  } catch {
    res.sendStatus(500); // CoinsFlow sends it again later
  }
});

verified() is the signature check from the docs, over the raw body. Add the endpoint in the dashboard, under Developers, with invoice.paid ticked; it must be an https:// address on the public internet. A pay-what-you-want invoice is paid by any confirmed payment: on Litecoin at the first confirmation, about 2.5 minutes after the donor sends, and with USDT on BNB Smart Chain in about 15 seconds. usdValue is the donation's worth in dollars when it was paid.

Getting the money out

Donations are credited to your CoinsFlow balance, in the coin they came in. Withdraw to your own wallet from the dashboard, with the fee shown before you confirm, or set an automatic withdrawal: the balance is sent to your address when it reaches an amount, or every day or week. On Litecoin and Bitcoin a donation is withdrawable as soon as it is paid.

Test it first

Make the invoice with "test": true, then press the buttons on its payment page, or call POST /v1/invoices/{id}/simulate. You get 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 thanks anyone on stream.

Questions

Does the donor need an account?

No. They open the page, pick a coin, and send any amount from any wallet or exchange to the address shown. A donor who holds the coin in a CoinsFlow balance can pay from it with Pay with CoinsFlow, typing the amount, and it is final at once.

Can I put one payment link in my bio?

A payment link is one invoice, for one payment: once it is paid the page says so, and after 3 to 7 days it expires. For a link many people use, a small page with a Donate button makes a fresh invoice per click, as above. For one donor, make a pay-what-you-want invoice in the dashboard and send them its link. Money that still reaches a paid invoice’s address is not lost: it is credited to you, and invoice.payment tells you.

Can the donor pick the coin?

Yes. With no chain or asset named, the payment page offers Litecoin, Bitcoin, Ether, BNB, USDT and USDC; the donor picks one and sends as much of it as they like. Name a coin, and the page asks for that one.

Is there a minimum?

None that you set. The payment page shows the smallest amount of each coin that counts as a payment, such as 0.0001 LTC or 0.01 USDT, so a donor knows what is too small to send. The fee is 0.5% of whatever arrives.

How do I thank a donor by name?

Ask for a name on your own page before the button, and put it in metadata: it comes back in invoice.paid, with amountPaid, the coin and usdValue, the gift’s worth in dollars when it was paid. The payment page itself has no fields of its own.

Does the donor see my wallet address?

No. Each invoice has a fresh address of ours. Donations are credited to your CoinsFlow balance, and you withdraw them to your own wallet, by hand or automatically.

What does it cost?

0.5% of each donation, taken when it is credited. No monthly fee, and no fee for making invoices. A withdrawal pays a fee in the coin that covers its network cost, shown before you confirm; the smallest Litecoin withdrawal is 0.0001 LTC.

Can I try it without money?

Yes. Make the invoice with "test": true, then press the buttons on its payment page or call POST /v1/invoices/{id}/simulate. The same signed webhooks arrive, marked "test": true, and no money moves.