calcom/cal.diy · warning · Error
BTCPay Server does not support automatic refunds for Bitcoin
Error message
BTCPay Server does not support automatic refunds for Bitcoin payments
What it means
`PaymentService.refund()` is intentionally not implemented for BTCPay and always throws this Error. Bitcoin payments cannot be automatically reversed through BTCPay Server's API, so the contract method is a deliberate no-op that signals unsupported behavior rather than silently failing.
Source
Thrown at packages/app-store/btcpayserver/lib/PaymentService.ts:158
isPaid: false,
attendee: { name: bookerName, email: bookerEmail },
},
}
),
});
if (!paymentData) throw new Error("Failed to store Payment data");
return paymentData;
} catch (error) {
log.error("BTCPay server: Payment could not be created", bookingId, safeStringify(error));
throw new Error(ErrorCode.PaymentCreationFailure);
}
}
async update(): Promise<Payment> {
throw new Error("Method not implemented.");
}
async refund(): Promise<Payment> {
throw new Error("BTCPay Server does not support automatic refunds for Bitcoin payments");
}
async collectCard(
_payment: Pick<Prisma.PaymentUncheckedCreateInput, "amount" | "currency">,
_bookingId: number,
_bookerEmail: string,
_paymentOption: PaymentOption
): Promise<Payment> {
throw new Error("Method not implemented");
}
chargeCard(
_payment: Pick<Prisma.PaymentUncheckedCreateInput, "amount" | "currency">,
_bookingId: number
): Promise<Payment> {
throw new Error("Method not implemented.");
}
View on GitHub (pinned to 176037d0af)
Solutions
- Before calling `refund()`, check the payment app's capability flag (or `instanceof`/slug check) and skip/branch for BTCPay.
- Surface a user-facing message that BTCPay/Bitcoin refunds must be handled manually on-chain.
- In a generic refund dispatcher, catch this Error and mark the refund as `manual_action_required` rather than failing the workflow.
- Add a `supportsRefund` capability on the payment adapter interface so callers can detect this without try/catch.
Example fix
// before
await paymentService.refund();
// after
if (paymentService.appSlug === "btcpayserver") {
await markRefundRequiresManualAction(paymentId);
} else {
await paymentService.refund();
} Defensive patterns
Strategy: type-guard
Validate before calling
const supportsRefund = (slug: string) => slug !== "btcpayserver";
if (!supportsRefund(paymentAppSlug)) {
await markRefundRequiresManualAction(paymentId);
return;
} Type guard
function supportsAutoRefund(appSlug: string): boolean {
return appSlug !== "btcpayserver";
} Try / catch
try {
await paymentService.refund();
} catch (e) {
if (e instanceof Error && /does not support automatic refunds/.test(e.message)) {
await markRefundRequiresManualAction(paymentId);
return;
}
throw e;
} Prevention
- Add a `supportsRefund` capability to the payment adapter interface.
- Branch refund workflows on adapter capability before calling refund().
- Hide auto-refund UI for BTCPay/Bitcoin payments.
- Document manual refund steps for Bitcoin payments in ops runbooks.
When it happens
Trigger: Any code path that calls `.refund()` on the BTCPay payment adapter — e.g. a booking cancellation flow that automatically refunds payments, or a generic refund API endpoint that doesn't filter by payment method capability.
Common situations: A cancellation/refund workflow added without checking each payment app's refund support; a generic admin tool iterating over payment adapters and invoking refund uniformly; UI button that doesn't hide for Bitcoin payments.
Related errors
- Cal.diy: payment not found
- Cal.diy: credentials not found
- PaymentCreationFailure
- Payment with uid ${uid} not found
- Booking with uid ${uid} not found
AI-assisted analysis of calcom/cal.diy@176037d0af (2026-08-12).
Data as JSON: /api/errors/f670764555148cf4.
Report an issue: GitHub.