Crypto Payroll Integration with Accounting
A company pays salaries in cryptocurrency — it's convenient for distributed teams, but creates accounting complexity: each payroll payment is a taxable transaction for the company, and receiving crypto by an employee requires proper tax withholding in their jurisdiction.
Taxation of Crypto Salaries
On the company side: paying salary in crypto = selling cryptocurrency by company + paying salary. If a company holds BTC purchased at $20,000 and pays salary when BTC is worth $50,000 — a capital gain of $30,000 arises at payment time.
On the employee side: receiving crypto salary is taxed as ordinary income at fair market value at time of receipt. Subsequent sale of crypto — capital gain/loss from the value at time of receipt.
Accounting Integration
interface CryptoPayrollTransaction {
employeeId: string;
payPeriod: { from: Date; to: Date };
fiatEquivalent: number; // USD salary amount
asset: string; // BTC, ETH, USDC
cryptoAmount: number; // calculated at payment time
exchangeRateAtPayment: number; // rate at payment time
txHash: string;
costBasisForCompany: number; // price company paid for this crypto
capitalGain: number; // difference for company
taxWithheld: number; // withheld tax (if company is withholding agent)
}
class CryptoPayrollService {
async processPayroll(employeeId: string, fiatAmount: number, asset: string): Promise<void> {
// Get current rate
const rate = await this.priceService.getCurrentPrice(asset, "USD");
const cryptoAmount = fiatAmount / rate;
// Cost basis for company
const companyBasis = await this.inventoryService.getCostBasis(asset, cryptoAmount);
const capitalGain = (rate - companyBasis.costPerUnit) * cryptoAmount;
// Payment via Bitwage / Request Finance / Deel
const tx = await this.paymentProvider.sendPayment({
recipient: employee.cryptoAddress,
asset,
amount: cryptoAmount,
});
// Accounting entry
await this.accounting.recordPayrollEntry({
debit: { account: "Salary Expense", amount: fiatAmount },
credit: { account: "Crypto Asset", amount: cryptoAmount, valueUSD: fiatAmount },
capitalGain: capitalGain > 0 ? capitalGain : 0,
capitalLoss: capitalGain < 0 ? Math.abs(capitalGain) : 0,
});
// Xero / QuickBooks integration
await this.exportToAccounting(tx, { fiatAmount, cryptoAmount, rate, capitalGain });
}
}
Xero and QuickBooks Integration
// Xero API: record payroll as Manual Journal
async function createXeroPayrollEntry(payroll: CryptoPayrollTransaction) {
const xeroEntry = {
journalDate: payroll.payPeriod.to.toISOString().split("T")[0],
lineAmountTypes: "NoTax",
journalLines: [
{
description: `Crypto salary - ${payroll.employeeId}`,
accountCode: "477", // Wages & Salaries
lineAmount: payroll.fiatEquivalent,
},
{
description: `Crypto asset disposal - ${payroll.asset}`,
accountCode: "090", // Crypto Asset account
lineAmount: -payroll.fiatEquivalent,
},
payroll.capitalGain !== 0 && {
description: "Capital gain/loss on crypto disposal",
accountCode: payroll.capitalGain > 0 ? "260" : "261",
lineAmount: Math.abs(payroll.capitalGain),
},
].filter(Boolean),
};
return xeroClient.accounting.createManualJournals({ manualJournals: [xeroEntry] });
}
Crypto Payroll Providers
| Provider | Features | Integration |
|---|---|---|
| Bitwage | Bitcoin payroll, direct fiat conversion | API + webhook |
| Request Finance | Multi-chain, ERC-20 support | API |
| Deel | Global payroll with crypto option | API |
| Tresio | Treasury + payroll | API |
Crypto payroll integration with Xero/QuickBooks, automatic capital gain calculation and tax entries — 2-3 weeks development.







