Payments and Refunds
Process payments, issue refunds, and manage the transaction lifecycle
RevKeen processes payments through your connected payment gateway, handling tokenization, authorization, capture, and refunds. This guide covers the complete payment flow, refund processing, credit notes, and best practices.
Supported Payment Methods
- Credit/Debit Cards -- Visa, Mastercard, American Express, Discover, and more
- ACH Bank Transfer -- Direct bank debits for US customers (lower fees)
- Saved Cards -- Securely stored payment methods for returning customers (email verification + CVV required)
Payment Flow
RevKeen uses tokenization to ensure card data never touches your servers:
- Tokenization -- Customer enters card in secure form; token generated client-side.
- Authorization -- RevKeen verifies the card can be charged for the requested amount.
- Capture -- Funds are captured and transferred (usually immediate).
- Confirmation -- Customer receives receipt, subscription/invoice updated.
Processing Payments via API
Create a One-Time Payment
const payment = await client.payments.create({
customerId: 'cus_xxxxxxxx',
amount: 9900, // $99.00 in cents
currency: 'USD',
paymentMethodToken: 'tok_xxxxxxxx',
description: 'Consulting fee',
metadata: {
orderId: 'order_12345',
},
});
if (payment.data.status === 'succeeded') {
console.log('Payment successful!');
console.log('Transaction ID:', payment.data.transactionId);
}payment = client.payments.create(
customer_id="cus_xxxxxxxx",
amount=9900,
currency="USD",
payment_method_token="tok_xxxxxxxx",
description="Consulting fee",
metadata={
"order_id": "order_12345"
}
)
if payment.data.status == "succeeded":
print("Payment successful!")
print(f"Transaction ID: {payment.data.transaction_id}")Pay an Invoice
// Pay an existing invoice with saved payment method
const result = await client.invoices.pay('inv_xxxxxxxx');
// Or specify a different payment method
const result = await client.invoices.pay('inv_xxxxxxxx', {
paymentMethodId: 'pm_xxxxxxxx',
});
console.log('Invoice paid:', result.data.paidAt);Transaction Statuses
| Status | Description | Funds |
|---|---|---|
pending | Payment initiated, awaiting processing | Held |
succeeded | Payment completed successfully | Captured |
failed | Payment declined or error occurred | None |
requires_action | Additional verification needed (3DS) | Held |
refunded | Full amount returned to customer | Returned |
partially_refunded | Partial amount returned | Partial |
voided | Reversed before settlement | Released |
Handling Declines
When a payment fails, RevKeen provides detailed decline information:
| Category | Common Codes | Recommended Action |
|---|---|---|
| Insufficient Funds | 300, 301 | Ask customer to use different card or try later |
| Card Declined | 200, 204 | Card blocked by issuer -- request new card |
| Invalid Card | 303, 530 | Card number invalid -- re-enter card details |
| Expired Card | 202, 223 | Request updated card information |
| CVV Mismatch | 225 | Re-enter CVV -- potential fraud indicator |
| Limit Exceeded | 402, 521 | Card limit reached -- try smaller amount or different card |
try {
const payment = await client.payments.create({
customerId: 'cus_xxxxxxxx',
amount: 9900,
currency: 'USD',
paymentMethodToken: 'tok_xxxxxxxx',
});
} catch (error) {
if (error.code === 'payment_declined') {
console.log('Decline code:', error.declineCode);
console.log('Message:', error.message);
switch (error.declineCode) {
case '300':
case '301':
return 'Insufficient funds. Please try a different card.';
case '200':
return 'Card declined. Please contact your bank.';
default:
return 'Payment failed. Please try again.';
}
}
}3D Secure (3DS) Authentication
Some payments require additional verification through 3D Secure. RevKeen handles this automatically in the checkout flow:
- Payment initiated -- Gateway determines 3DS is required
- Customer redirected to bank's verification page
- Customer completes verification (password, SMS code, etc.)
- Customer redirected back -- Payment completes
3DS helps reduce fraud and shifts liability to the card issuer. It's required for Strong Customer Authentication (SCA) in the EU.
Reversing Payments: Void vs Refund
RevKeen provides intelligent payment reversal options based on settlement timing. Understanding when to use each method can save you significant processing fees.
How It Works
| Method | Timing | Processing Fees | Customer Impact |
|---|---|---|---|
| Void | Before daily settlement (typically before 8 PM ET) | No fees | Charge never appears on statement |
| Refund | After daily settlement | Original fees not returned | Shows as separate refund transaction |
Settlement Timing and Smart Warnings
RevKeen automatically tracks settlement timing for each payment gateway and provides real-time warnings to help you choose the best reversal method.
Safe to Void -- Settlement is 2+ hours away. Void will succeed with high confidence. This is the recommended option to avoid processing fees.
High-Risk Void Window -- Settlement is within 15 minutes. The batch may have already closed. If void fails, you will need to process a refund instead. The dashboard will show "Attempt Void" with a warning alert.
Settlement Complete -- Transaction has been settled. Void is no longer available. You must process a refund to return funds to the customer.
Smart Reversal Logic: RevKeen automatically determines eligibility based on your gateway's settlement schedule. When you view a payment, you'll see only the available options with clear warnings for high-risk scenarios.
Using the Dashboard
- Navigate to Invoice or Payment -- Go to Invoices, select invoice, click payment row actions menu.
- Choose Reversal Method -- The dialog will show available options based on settlement status. Review settlement timing information and any warnings displayed.
- Confirm and Execute -- Click the action button ("Void Payment", "Attempt Void", or "Process Refund") to execute the reversal.
Important: If a high-risk void fails because settlement already occurred, you will need to manually process a refund. The system cannot automatically fall back to refund due to accounting and tax implications.
Processing Refunds
// Full refund
const refund = await client.refunds.create({
transactionId: 'txn_xxxxxxxx',
});
// Partial refund
const partialRefund = await client.refunds.create({
transactionId: 'txn_xxxxxxxx',
amount: 2500, // Refund $25.00
});
// Refund with reason
const refund = await client.refunds.create({
transactionId: 'txn_xxxxxxxx',
reason: 'Customer request',
});# Full refund
refund = client.refunds.create(
transaction_id="txn_xxxxxxxx"
)
# Partial refund
partial_refund = client.refunds.create(
transaction_id="txn_xxxxxxxx",
amount=2500
)
# Refund with reason
refund = client.refunds.create(
transaction_id="txn_xxxxxxxx",
reason="Customer request"
)Refunds typically take 5-10 business days to appear on the customer's statement. You cannot refund more than the original transaction amount.
Credit Notes
Credit notes provide formal documentation for invoice adjustments, service credits, or refunds. They maintain a complete audit trail and handle complex scenarios like subscription cancellations and tax adjustments.
When to Use Credit Notes
- Invoice Corrections -- Wrong amount charged, billing error, or service not delivered as promised.
- Service Credits -- Goodwill credits, promotional adjustments, or compensation for service issues.
- Subscription Cancellations -- Prorate refunds when canceling subscriptions mid-period.
- Partial Refunds -- Return a portion of the invoice amount while keeping the invoice active.
Credit Note Options
| Credit Method | Effect | Best For |
|---|---|---|
| Refund to Payment Method | Issues credit note and automatically processes refund/void | Customer paid and wants money back |
| Customer Balance | Issues credit note and adds credit to customer account | Customer wants credit toward future purchases |
| Credit Note Only | Issues credit note for record-keeping only | Manual refund outside RevKeen or goodwill gesture |
Intelligent Tax Handling
RevKeen automatically calculates proportional tax adjustments when issuing credit notes:
- Proportional Tax Credits -- Tax amounts are automatically calculated proportionally to the credited amount. For example, crediting 50% of an invoice also credits 50% of the tax.
- Penny-Perfect Chain Handling -- When issuing multiple credit notes against the same invoice, the final credit note automatically "sweeps" any remaining fractional pennies of tax. This prevents 1-2 cent discrepancies that can occur with rounding in credit note chains.
- Tax Provider Sync -- Credit notes automatically sync with your tax provider (Quaderno, TaxJar, etc.) to maintain accurate tax records and compliance reports.
Subscription Cancellation Protection
When issuing a credit note with subscription cancellation, RevKeen implements a safety guard: if you select "Refund to Payment Method" with subscription cancellation, the subscription will only cancel if the refund succeeds. This prevents scenarios where a customer loses access but didn't receive their refund due to gateway errors or expired payment methods.
If the refund fails, a warning is logged and the subscription remains active. You can then manually process the refund and cancel separately.
Creating Credit Notes
// Issue credit note with automatic refund
const creditNote = await client.creditNotes.create({
invoiceId: 'inv_xxxxxxxx',
amount: 5000, // $50.00 in cents
reason: 'Service not delivered',
creditMethod: 'refund_to_payment_method',
cancelSubscription: true,
});
// Issue credit note with customer balance
const creditNote = await client.creditNotes.create({
invoiceId: 'inv_xxxxxxxx',
amount: 5000,
reason: 'Goodwill credit',
creditMethod: 'customer_balance',
});
// Credit note only (no financial movement)
const creditNote = await client.creditNotes.create({
invoiceId: 'inv_xxxxxxxx',
amount: 5000,
reason: 'Manual adjustment',
creditMethod: 'none',
});Audit Trail: All credit notes include reason codes, creator information, timestamp, and links to associated refunds/voids. They appear on customer statements and integrate with your accounting system for complete financial reconciliation.
Payment Webhooks
Listen for payment events to keep your systems in sync:
| Event | Trigger |
|---|---|
payment.succeeded | Payment completed successfully |
payment.failed | Payment was declined |
payment.refunded | Refund processed |
payment.captured | Authorized payment captured |
payment.disputed | Chargeback received |
payment.requires_action | Additional customer action needed |
void.succeeded | Pre-settlement void completed |
void.failed | Void failed (transaction already settled) |
credit_note.created | Credit note issued against invoice |
credit_note.voided | Credit note canceled or voided |
Best Practices
- Always Use Idempotency Keys -- Include an idempotency key with payment requests to prevent duplicate charges on retries.
- Handle Webhooks -- Don't rely solely on API responses. Use webhooks for reliable payment status updates.
- Store Transaction IDs -- Always store the transaction ID from successful payments for refunds and support inquiries.
- Graceful Error Handling -- Show user-friendly error messages and provide clear next steps when payments fail.
- Descriptive Statement Descriptors -- Use descriptive statement descriptors so customers recognize charges on their bank statements and reduce chargebacks.
Related
- Dunning -- Automatic failed payment recovery
- Disputes -- Handle chargebacks and disputes
- Subscriptions -- Recurring billing guide