MercanPay Blog

How to Accept Crypto Donations in USDT for Nonprofits

How to accept crypto donations as a nonprofit, open source project or creator: a USDT donation flow, why one static address fails, and thanking donors.

Published: October 28, 20266 min readTürkçe oku
How to Accept Crypto Donations in USDT for Nonprofits

Knowing how to accept crypto donations is increasingly useful for nonprofits, open source projects and creators with supporters abroad. A donor anywhere in the world can send USDT in a few minutes, and the donation shows up in your account shortly afterwards. This guide covers how to set up the donation flow, why posting a single wallet address causes trouble, and how to thank donors automatically.

Who accepts crypto donations?

Crypto donations make the most sense for:

  • Open source projects whose contributors and users are spread across countries.
  • Creators such as streamers, writers, podcasters and video makers, whose followers chip in through a "support me" link.
  • Associations and community initiatives with international supporters.
  • Education and culture projects funded by their audience.

Fundraising rules differ by organisation type, activity and country. Before accepting crypto donations, check your registration, permit and reporting obligations with your legal and financial advisers.

Why a single static wallet address isn't enough

Many projects put one USDT address on their website with a "send donations here" note. It looks simple, but it causes problems over time:

  • You can't tell who sent what. Dozens of transfers land on the same address, and matching them to people or campaigns becomes guesswork.
  • Thanking donors is hard. An automatic thank-you email requires matching the payment to a person.
  • Wrong-network mistakes increase. A donor who only sees an address may not know which network to use. See crypto sent to the wrong network.
  • You become a poisoning target. Public, busy addresses attract scammers, as described in address poisoning attacks.
  • Reporting is manual. Totalling a campaign means counting transactions one by one in a block explorer.

How an invoice-based donation flow works

With a payment gateway, every donation gets its own invoice:

  1. The donor picks an amount on your site, for example $10, $25, $50 or $100.
  2. Your server creates a USD-priced invoice for that amount.
  3. The donor chooses TRX or USDT on the payment page and pays by scanning the QR code.
  4. Once the payment is final after 20 block confirmations, a signed webhook reaches your server.
  5. Your system records the donation and sends a thank-you email.

Because each invoice has its own address, payments are never mixed up. The payment page also tells the donor exactly which network to use and how much to send.

Preset amounts instead of a free-form field

MercanPay invoices are created for a set amount, and the payment page has no field where donors type their own. The practical approach is to offer preset amount buttons on your site. You can add an "other amount" field too, in which case your server creates the invoice with whatever the donor entered.

Keep in mind that the minimum invoice is $10, so this setup doesn't suit smaller contributions.

Code example: donation buttons in Python

This Flask example takes the amount from your donation form, creates an invoice and redirects the donor to the payment page:

import os
import uuid
from flask import Flask, request, redirect, abort
from mercanpay import MercanPay

app = Flask(__name__)
zp = MercanPay("https://mercanpay.com", os.environ["MERCANPAY_API_KEY"])

AMOUNTS = {"10", "25", "50", "100"}

@app.post("/donate")
def donate():
    amount = request.form.get("amount", "")
    if amount not in AMOUNTS:
        abort(400)
    invoice = zp.create_invoice(
        price_usd=amount,
        order_id=f"donation-{uuid.uuid4()}",
        description="Thank you for your donation",
        success_url="https://ourproject.org/donate/thanks",
        return_url="https://ourproject.org/donate",
        expires_in_minutes=60,
        metadata={"campaign": "winter-2026", "newsletter": request.form.get("newsletter") == "on"},
    )
    return redirect(invoice["payment_url"])

A few details:

  • Amounts are strings ("25"), never floats.
  • metadata is never shown to the donor and comes back unchanged in the webhook. It's a good place for the campaign name or a newsletter opt-in.
  • order_id must be unique per donation. The full setup is in the Python integration guide.

No website, or only the occasional donation? Create the invoice in the panel and send the link directly, as shown in create your first crypto invoice.

Thank donors from the webhook

Confirm a donation from the signed webhook, not from the browser returning to success_url. When invoice.paid or invoice.overpaid arrives:

  • Record the donation in your database (amount, coin, date, campaign).
  • Store the event id so the same event is never processed twice.
  • Send the donor a thank-you email.

Signature checks are covered in how to verify webhook signatures, and every event type in crypto payment webhook events.

Overpayments are common with donations. If a donor sends more than the chosen amount, the invoice becomes overpaid and the full amount is credited to your balance. That's usually welcome news, so just make sure your records use the paid_amount field.

Tracking campaigns separately

If you run several campaigns at once, say a winter appeal and a server-costs drive, tying each donation to the right campaign makes reporting much easier. Two simple methods work well:

  • order_id prefixes: with prefixes such as winter-2026-… or servers-…, you can tell campaigns apart in the exported list just by looking at the order ID.
  • The metadata field: carry the campaign name in metadata, and when the webhook arrives you can add the donation straight to that campaign's total.

A separate donation page and thank-you message per campaign also shows supporters exactly what they're contributing to.

Transparency and reporting

Transparency is what donors trust. In the panel you can export invoices and balance movements for any date range as CSV, Excel or PDF, which makes campaign totals, board reports and supporter updates easy. See export crypto payment reports, and for record-keeping habits, crypto payment bookkeeping.

A short guide for your donors

Adding this note to your donation page prevents most mistakes:

  • Use the TRON (TRC20) network only.
  • Send the amount shown on the payment page. If you're sending from an exchange, check that the withdrawal fee isn't deducted from it.
  • Network fees are included in the amount shown on the payment page.
  • The payment confirms in about a minute and the page updates by itself.

FAQ

Can donors stay anonymous?

The payment page doesn't ask donors for personal details, and you can make name and email optional on your own form. On-chain, only the sending wallet address is visible.

Can I take monthly donations?

MercanPay has no automatic recurring payments. You can still run monthly giving by sending supporters a new payment link each month, as described in crypto subscription payments.

Do I have to convert donations to fiat?

That's your call. For the general process, see converting USDT to Turkish lira, and ask your adviser about the accounting and tax side.

Which coins can I accept?

TRX and USDT (TRC20) on TRON. Use the tokens field to accept USDT only.

Get started with MercanPay

To accept crypto donations with every gift tracked separately, apply for a merchant account. Describing your activity clearly in the application makes the review easier. Integration details are in the documentation.

#Donations#USDT#Industries#Webhook

Related posts

Start accepting crypto payments in minutes

Accept USDT and TRX (TRC20). Fees from 0.4%, a hosted payment page, API and webhooks.