There are three viable approaches to accepting crypto payments as a freelancer, ranging from zero-setup manual wallets to fully automated invoicing with webhooks. Each has different trade-offs in setup complexity, control, and client experience. Here's the complete technical breakdown.
Option 1: Manual Wallet Addresses
The simplest approach. Share your wallet address on your invoice. Client sends the agreed amount directly. You confirm receipt on-chain before delivering work.
- ▸✅ Zero setup, zero fees, full self-custody
- ▸✅ Works immediately with any crypto wallet you already have
- ▸❌ Manual tracking required — no automatic payment confirmation emails
- ▸❌ Higher friction for clients who haven't used crypto wallets before
Option 2: Coinbase Commerce
Coinbase Commerce generates a unique hosted payment link per invoice. Clients get a familiar checkout interface. You get automatic confirmation emails and a dashboard to track payment status.
const Client = require('coinbase-commerce-node').Client;
const Checkout = require('coinbase-commerce-node').Checkout;
Client.init(process.env.COINBASE_COMMERCE_API_KEY);
async function createInvoice(projectName, amount, invoiceId) {
const checkoutData = {
name: projectName,
description: `Invoice #${invoiceId}`,
pricing_type: 'fixed_price',
local_price: {
amount: amount.toString(),
currency: 'USD',
},
metadata: { invoice_id: invoiceId },
requested_info: ['email'],
};
const checkout = await Checkout.create(checkoutData);
return checkout.hosted_url; // Send this URL to your client
}Option 3: BTCPay Server (Self-Hosted)
BTCPay Server is the most powerful option for freelancers who want zero platform dependency. It's open-source, self-hosted, KYC-free, and charges no fees beyond the blockchain transaction fee.
# Deploy BTCPay Server on your VPS with Docker
git clone https://github.com/btcpayserver/btcpayserver-docker
cd btcpayserver-docker
export BTCPAY_HOST="pay.yourdomain.com"
export NBITCOIN_NETWORK="mainnet"
export BTCPAYGEN_CRYPTO1="btc"
export BTCPAYGEN_CRYPTO2="eth"
export BTCPAYGEN_ADDITIONAL_FRAGMENTS="opt-add-lightning"
. ./btcpay-setup.sh -iAutomated Payment Confirmation with Webhooks
// Express.js webhook handler for Coinbase Commerce
const express = require('express');
const { Webhook } = require('coinbase-commerce-node');
app.post('/webhook/payment', express.raw({ type: 'application/json' }), (req, res) => {
const signature = req.headers['x-cc-webhook-signature'];
try {
const event = Webhook.verifyEventBody(
req.body,
signature,
process.env.WEBHOOK_SECRET
);
if (event.type === 'charge:confirmed') {
const invoiceId = event.data.metadata.invoice_id;
// Mark invoice paid, trigger project delivery workflow
markInvoicePaid(invoiceId);
}
res.sendStatus(200);
} catch (err) {
console.error('Invalid webhook signature:', err);
res.status(400).send('Invalid signature');
}
});Currency Conversion Strategy
Our recommendation: accept in USDT on TRC-20 (Tron network — fees under $1) and convert to your local fiat currency weekly via a centralized exchange (Binance, Kraken, Coinbase). This eliminates daily volatility exposure while keeping total transaction costs under 1%.
Accounting and Tax Records
- ▸Export a transaction CSV from each wallet monthly
- ▸Record USD fair market value at the time of each receipt (CoinGecko historical prices API)
- ▸Use Koinly or CoinTracker for automated reconciliation with tax-ready reports
- ▸Keep transaction records for 7 years (standard tax record retention in most jurisdictions)
- ▸Consult a tax professional familiar with crypto — the rules vary significantly by country
