Transaction and Payment Reports
Transaction reports provide detailed insights into all payment activity in your Omise account. Access comprehensive data on charges, refunds, disputes, and transfers for accounting, reconciliation, and business analysis.
Overviewโ
Transaction reporting features include:
- Real-time Data: View transactions as they occur
- Comprehensive Filtering: Filter by status, amount, date, payment method, and more
- Advanced Search: Find specific transactions quickly
- Bulk Export: Download transaction data in multiple formats
- Scheduled Reports: Automate report generation and delivery
- API Access: Retrieve transaction data programmatically
- Reconciliation Tools: Match payments with bank settlements
- Dispute Tracking: Monitor chargebacks and disputes
Report Typesโ
1. Payment Reportsโ
Payment reports show all successfully completed payments:
Available Fieldsโ
- Transaction ID
- Customer information
- Amount and currency
- Payment method
- Card details (last 4 digits, brand)
- Status
- Creation date
- Settlement date
- Reference numbers
- Description/metadata
Accessing Payment Reportsโ
Via Dashboard:
- Navigate to Transactions > Payments
- Select date range
- Apply filters as needed
- Click Export to download
Via API:
// Node.js - Retrieve payment reports
const omise = require('omise')({
secretKey: 'skey_test_xxxxx'
});
async function getPaymentReport(fromDate, toDate) {
try {
const charges = await omise.charges.list({
from: fromDate,
to: toDate,
paid: true, // Only successful payments
limit: 100,
order: 'reverse_chronological'
});
// Format report data
const report = charges.data.map(charge => ({
id: charge.id,
amount: charge.amount / 100,
currency: charge.currency.toUpperCase(),
customer: charge.customer || 'Guest',
card_brand: charge.card?.brand || 'N/A',
card_last4: charge.card?.last_digits || 'N/A',
status: charge.status,
created: new Date(charge.created * 1000).toISOString(),
description: charge.description || ''
}));
return {
total: charges.total,
payments: report
};
} catch (error) {
console.error('Error fetching payment report:', error);
throw error;
}
}
// Generate report for last 30 days
const toDate = new Date();
const fromDate = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000);
getPaymentReport(fromDate.toISOString(), toDate.toISOString())
.then(report => {
console.log(`Total payments: ${report.total}`);
console.log(JSON.stringify(report, null, 2));
});
# Python - Generate payment report
import omise
from datetime import datetime, timedelta
import csv
omise.api_secret = 'skey_test_xxxxx'
def generate_payment_report(from_date, to_date, output_file='payments.csv'):
"""Generate payment report and export to CSV."""
# Fetch successful charges
charges = omise.Charge.list(
from_date=from_date.isoformat(),
to_date=to_date.isoformat(),
paid=True,
limit=100,
order='reverse_chronological'
)
# Prepare data for export
payment_data = []
for charge in charges.data:
payment_data.append({
'Transaction ID': charge.id,
'Amount': charge.amount / 100,
'Currency': charge.currency.upper(),
'Customer': charge.customer or 'Guest',
'Card Brand': charge.card.brand if charge.card else 'N/A',
'Card Last 4': charge.card.last_digits if charge.card else 'N/A',
'Status': charge.status,
'Created': datetime.fromtimestamp(charge.created).isoformat(),
'Description': charge.description or ''
})
# Export to CSV
if payment_data:
with open(output_file, 'w', newline='') as csvfile:
writer = csv.DictWriter(csvfile, fieldnames=payment_data[0].keys())
writer.writeheader()
writer.writerows(payment_data)
print(f'Report exported to {output_file}')
print(f'Total payments: {len(payment_data)}')
return payment_data
# Generate report for last month
to_date = datetime.now()
from_date = to_date - timedelta(days=30)
report = generate_payment_report(from_date, to_date)
# Ruby - Payment report with grouping
require 'omise'
require 'csv'
require 'date'
Omise.api_key = 'skey_test_xxxxx'
def generate_grouped_payment_report(from_date, to_date)
# Fetch successful payments
charges = Omise::Charge.list({
from: from_date.iso8601,
to: to_date.iso8601,
paid: true,
limit: 100,
order: 'reverse_chronological'
})
# Group by payment method
grouped_data = charges.data.group_by { |c| c.card&.brand || 'Other' }
report = {
period: "#{from_date.to_date} to #{to_date.to_date}",
total_payments: charges.total,
by_payment_method: {}
}
grouped_data.each do |method, payments|
total_amount = payments.sum(&:amount)
report[:by_payment_method][method] = {
count: payments.length,
total_amount: total_amount / 100.0,
average_amount: (total_amount / payments.length / 100.0).round(2)
}
end
report
end
# Generate report
from_date = DateTime.now - 30
to_date = DateTime.now
report = generate_grouped_payment_report(from_date, to_date)
puts JSON.pretty_generate(report)
<?php
// PHP - Payment report with metrics
require_once 'vendor/autoload.php';
define('OMISE_SECRET_KEY', 'skey_test_xxxxx');
function generatePaymentReportWithMetrics($fromDate, $toDate) {
// Fetch successful charges
$charges = OmiseCharge::retrieve([
'from' => $fromDate->format(DateTime::ATOM),
'to' => $toDate->format(DateTime::ATOM),
'paid' => true,
'limit' => 100,
'order' => 'reverse_chronological'
]);
$payments = $charges['data'];
// Calculate metrics
$totalAmount = 0;
$currencies = [];
$paymentMethods = [];
foreach ($payments as $payment) {
$totalAmount += $payment['amount'];
$currency = strtoupper($payment['currency']);
$currencies[$currency] = ($currencies[$currency] ?? 0) + $payment['amount'];
$method = $payment['card']['brand'] ?? 'Other';
$paymentMethods[$method] = ($paymentMethods[$method] ?? 0) + 1;
}
$report = [
'period' => [
'from' => $fromDate->format('Y-m-d'),
'to' => $toDate->format('Y-m-d')
],
'summary' => [
'total_payments' => count($payments),
'total_amount' => $totalAmount / 100,
'average_amount' => $payments ? ($totalAmount / count($payments) / 100) : 0
],
'by_currency' => array_map(function($amount) {
return $amount / 100;
}, $currencies),
'by_payment_method' => $paymentMethods,
'payments' => array_map(function($payment) {
return [
'id' => $payment['id'],
'amount' => $payment['amount'] / 100,
'currency' => strtoupper($payment['currency']),
'card' => [
'brand' => $payment['card']['brand'] ?? null,
'last4' => $payment['card']['last_digits'] ?? null
],
'created' => date('c', $payment['created'])
];
}, $payments)
];
return $report;
}
// Generate report
$toDate = new DateTime();
$fromDate = (new DateTime())->modify('-30 days');
$report = generatePaymentReportWithMetrics($fromDate, $toDate);
echo json_encode($report, JSON_PRETTY_PRINT);
?>
// Go - Comprehensive payment report
package main
import (
"encoding/json"
"fmt"
"time"
"github.com/omise/omise-go"
"github.com/omise/omise-go/operations"
)
type PaymentReport struct {
Period Period `json:"period"`
Summary Summary `json:"summary"`
Payments []PaymentDetail `json:"payments"`
}
type Period struct {
From string `json:"from"`
To string `json:"to"`
}
type Summary struct {
TotalPayments int `json:"total_payments"`
TotalAmount float64 `json:"total_amount"`
AverageAmount float64 `json:"average_amount"`
}
type PaymentDetail struct {
ID string `json:"id"`
Amount float64 `json:"amount"`
Currency string `json:"currency"`
CardBrand string `json:"card_brand"`
CardLast4 string `json:"card_last4"`
Created time.Time `json:"created"`
Description string `json:"description"`
}
func generatePaymentReport(from, to time.Time) (*PaymentReport, error) {
client, err := omise.NewClient("pkey_test_xxxxx", "skey_test_xxxxx")
if err != nil {
return nil, err
}
// Fetch successful charges
charges := &omise.ChargeList{}
err = client.Do(charges, &operations.ListCharges{
ListParams: operations.ListParams{
From: from,
To: to,
Limit: 100,
Order: omise.ReverseChronological,
},
})
if err != nil {
return nil, err
}
// Filter paid charges and build report
var totalAmount int64
var payments []PaymentDetail
for _, charge := range charges.Data {
if charge.Paid {
totalAmount += charge.Amount
cardBrand := "N/A"
cardLast4 := "N/A"
if charge.Card != nil {
cardBrand = charge.Card.Brand
cardLast4 = charge.Card.LastDigits
}
payments = append(payments, PaymentDetail{
ID: charge.ID,
Amount: float64(charge.Amount) / 100,
Currency: charge.Currency,
CardBrand: cardBrand,
CardLast4: cardLast4,
Created: charge.Created.Time(),
Description: charge.Description,
})
}
}
// Calculate summary
avgAmount := 0.0
if len(payments) > 0 {
avgAmount = float64(totalAmount) / float64(len(payments)) / 100
}
report := &PaymentReport{
Period: Period{
From: from.Format("2006-01-02"),
To: to.Format("2006-01-02"),
},
Summary: Summary{
TotalPayments: len(payments),
TotalAmount: float64(totalAmount) / 100,
AverageAmount: avgAmount,
},
Payments: payments,
}
return report, nil
}
func main() {
to := time.Now()
from := to.AddDate(0, 0, -30)
report, err := generatePaymentReport(from, to)
if err != nil {
panic(err)
}
jsonData, _ := json.MarshalIndent(report, "", " ")
fmt.Println(string(jsonData))
}
2. Charge Reportsโ
Charge reports include all charge attempts, both successful and failed:
Key Featuresโ
- View all charge attempts
- Identify failed payments
- Analyze failure reasons
- Track retry attempts
- Monitor authorization issues
Failure Analysisโ
// Node.js - Analyze failed charges
const omise = require('omise')({
secretKey: 'skey_test_xxxxx'
});
async function analyzeFailedCharges(fromDate, toDate) {
const charges = await omise.charges.list({
from: fromDate,
to: toDate,
limit: 100
});
const failedCharges = charges.data.filter(c => !c.paid);
// Group by failure reason
const failureReasons = {};
failedCharges.forEach(charge => {
const reason = charge.failure_code || 'unknown';
if (!failureReasons[reason]) {
failureReasons[reason] = {
count: 0,
total_amount: 0,
examples: []
};
}
failureReasons[reason].count++;
failureReasons[reason].total_amount += charge.amount;
if (failureReasons[reason].examples.length < 3) {
failureReasons[reason].examples.push(charge.id);
}
});
return {
total_failed: failedCharges.length,
total_attempted: charges.total,
failure_rate: (failedCharges.length / charges.total * 100).toFixed(2) + '%',
failure_reasons: failureReasons
};
}
// Analyze failures
const toDate = new Date();
const fromDate = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000);
analyzeFailedCharges(fromDate.toISOString(), toDate.toISOString())
.then(analysis => console.log(JSON.stringify(analysis, null, 2)));
3. Refund Reportsโ
Track all refund transactions and their impact on revenue:
# Python - Comprehensive refund report
import omise
from datetime import datetime, timedelta
from collections import defaultdict
omise.api_secret = 'skey_test_xxxxx'
def generate_refund_report(from_date, to_date):
"""Generate detailed refund report with analytics."""
# Fetch all charges with refunds
charges = omise.Charge.list(
from_date=from_date.isoformat(),
to_date=to_date.isoformat(),
limit=100
)
refund_stats = {
'total_refunds': 0,
'total_amount': 0,
'full_refunds': 0,
'partial_refunds': 0,
'by_reason': defaultdict(lambda: {'count': 0, 'amount': 0}),
'refunds': []
}
for charge in charges.data:
if charge.refunded_amount > 0:
# Fetch refund details
refunds = omise.Refund.list(charge_id=charge.id)
for refund in refunds.data:
refund_stats['total_refunds'] += 1
refund_stats['total_amount'] += refund.amount
# Categorize refund type
if refund.amount == charge.amount:
refund_stats['full_refunds'] += 1
else:
refund_stats['partial_refunds'] += 1
# Group by reason (from metadata)
reason = refund.metadata.get('reason', 'Not specified')
refund_stats['by_reason'][reason]['count'] += 1
refund_stats['by_reason'][reason]['amount'] += refund.amount
refund_stats['refunds'].append({
'refund_id': refund.id,
'charge_id': charge.id,
'amount': refund.amount / 100,
'currency': charge.currency.upper(),
'type': 'full' if refund.amount == charge.amount else 'partial',
'created': datetime.fromtimestamp(refund.created).isoformat(),
'reason': reason
})
# Calculate percentages
if refund_stats['total_refunds'] > 0:
refund_stats['average_refund'] = (
refund_stats['total_amount'] / refund_stats['total_refunds'] / 100
)
return refund_stats
# Generate report
to_date = datetime.now()
from_date = to_date - timedelta(days=30)
report = generate_refund_report(from_date, to_date)
print(f"Total Refunds: {report['total_refunds']}")
print(f"Total Amount: {report['total_amount'] / 100}")
print(f"Full Refunds: {report['full_refunds']}")
print(f"Partial Refunds: {report['partial_refunds']}")
Filter Optionsโ
Available Filtersโ
-
Date Range
- Specific dates
- Relative ranges (today, yesterday, last 7 days, etc.)
- Custom date ranges
-
Status
- Successful
- Failed
- Pending
- Reversed
- Expired
-
Amount
- Minimum amount
- Maximum amount
- Exact amount
- Amount ranges
-
Payment Method
- Credit/Debit cards (by brand)
- Internet banking
- Mobile banking
- E-wallets
- QR payments
- Installments
-
Currency
- THB (Thai Baht)
- SGD (Singapore Dollar)
- JPY (Japanese Yen)
- USD (US Dollar)
- And more
-
Customer
- Customer ID
- Customer name
-
Metadata
- Custom metadata fields
- Order ID
- Reference numbers
Using Filters via Dashboardโ
- Navigate to Transactions
- Click Filters button
- Select filter criteria
- Click Apply Filters
- Save filter combinations for reuse
Using Filters via APIโ
// Node.js - Advanced filtering
const omise = require('omise')({
secretKey: 'skey_test_xxxxx'
});
async function getFilteredTransactions(filters) {
const params = {
limit: 100,
order: 'reverse_chronological'
};
// Apply date filters
if (filters.from) params.from = filters.from;
if (filters.to) params.to = filters.to;
// Apply status filter
if (filters.status === 'successful') params.paid = true;
if (filters.status === 'failed') params.paid = false;
// Fetch charges
const charges = await omise.charges.list(params);
// Apply additional filters (amount, payment method, etc.)
let filteredCharges = charges.data;
if (filters.minAmount) {
filteredCharges = filteredCharges.filter(
c => c.amount >= filters.minAmount * 100
);
}
if (filters.maxAmount) {
filteredCharges = filteredCharges.filter(
c => c.amount <= filters.maxAmount * 100
);
}
if (filters.cardBrand) {
filteredCharges = filteredCharges.filter(
c => c.card?.brand === filters.cardBrand
);
}
if (filters.currency) {
filteredCharges = filteredCharges.filter(
c => c.currency === filters.currency.toLowerCase()
);
}
return {
total: filteredCharges.length,
data: filteredCharges
};
}
// Example: Find all successful Visa transactions over 1000 THB in last 30 days
const filters = {
from: new Date(Date.now() - 30 * 24 * 60 * 60 * 1000).toISOString(),
to: new Date().toISOString(),
status: 'successful',
cardBrand: 'Visa',
minAmount: 1000,
currency: 'thb'
};
getFilteredTransactions(filters)
.then(result => {
console.log(`Found ${result.total} transactions matching filters`);
result.data.forEach(charge => {
console.log(`${charge.id}: ${charge.amount / 100} ${charge.currency.toUpperCase()}`);
});
});
Searching Transactionsโ
Quick Searchโ
Use the dashboard search to find specific transactions:
-
By Transaction ID
- Enter full or partial charge ID
- Format:
chrg_test_xxxxx
-
By Customer Email
- Enter customer email address
- Searches across all customer transactions
-
By Amount
- Enter exact amount
- Specify currency
-
By Card Last 4 Digits
- Enter last 4 digits
- Optionally specify card brand
Advanced Search via APIโ
# Ruby - Advanced transaction search
require 'omise'
Omise.api_key = 'skey_test_xxxxx'
class TransactionSearch
def initialize
@charges = []
end
def search(criteria)
# Fetch charges based on criteria
params = build_search_params(criteria)
result = Omise::Charge.list(params)
@charges = result.data
apply_filters(criteria)
end
private
def build_search_params(criteria)
params = { limit: 100 }
params[:from] = criteria[:from] if criteria[:from]
params[:to] = criteria[:to] if criteria[:to]
params[:customer] = criteria[:customer_id] if criteria[:customer_id]
params
end
def apply_filters(criteria)
# Filter by card last 4 digits
if criteria[:card_last4]
@charges = @charges.select do |charge|
charge.card&.last_digits == criteria[:card_last4]
end
end
# Filter by amount range
if criteria[:min_amount]
@charges = @charges.select { |c| c.amount >= criteria[:min_amount] * 100 }
end
if criteria[:max_amount]
@charges = @charges.select { |c| c.amount <= criteria[:max_amount] * 100 }
end
# Filter by metadata
if criteria[:metadata]
@charges = @charges.select do |charge|
criteria[:metadata].all? do |key, value|
charge.metadata[key.to_s] == value
end
end
end
@charges
end
end
# Example: Search for transactions
searcher = TransactionSearch.new
results = searcher.search({
from: (DateTime.now - 30).iso8601,
to: DateTime.now.iso8601,
card_last4: '4242',
min_amount: 100,
max_amount: 5000,
metadata: { order_type: 'subscription' }
})
puts "Found #{results.length} matching transactions"
results.each do |charge|
puts "#{charge.id}: #{charge.amount / 100.0} #{charge.currency.upcase}"
end
Report Schedulingโ
Setting Up Scheduled Reportsโ
-
Navigate to Reports > Scheduled Reports
-
Click "Create Schedule"
-
Configure Report:
- Report type (Payments, Charges, Refunds)
- Frequency (Daily, Weekly, Monthly)
- Date range (Last 24 hours, Last 7 days, etc.)
- Filters and conditions
- Export format (CSV, PDF, Excel)
-
Set Recipients:
- Add email addresses
- Configure delivery time
- Set timezone
-
Save Schedule
Automated Report Deliveryโ
// Node.js - Custom report scheduling with email
const omise = require('omise')({ secretKey: 'skey_test_xxxxx' });
const nodemailer = require('nodemailer');
const cron = require('node-cron');
const fs = require('fs');
const { Parser } = require('json2csv');
// Email configuration
const transporter = nodemailer.createTransport({
host: 'smtp.example.com',
port: 587,
secure: false,
auth: {
user: 'reports@example.com',
pass: 'password'
}
});
async function generateAndEmailReport() {
try {
// Generate report for yesterday
const yesterday = new Date(Date.now() - 24 * 60 * 60 * 1000);
const today = new Date();
const charges = await omise.charges.list({
from: yesterday.toISOString(),
to: today.toISOString(),
paid: true,
limit: 100
});
// Format data for CSV
const reportData = charges.data.map(charge => ({
'Transaction ID': charge.id,
'Amount': charge.amount / 100,
'Currency': charge.currency.toUpperCase(),
'Card Brand': charge.card?.brand || 'N/A',
'Status': charge.status,
'Created': new Date(charge.created * 1000).toISOString(),
'Description': charge.description || ''
}));
// Convert to CSV
const json2csvParser = new Parser();
const csv = json2csvParser.parse(reportData);
// Save to file
const filename = `daily-report-${yesterday.toISOString().split('T')[0]}.csv`;
fs.writeFileSync(filename, csv);
// Send email
await transporter.sendMail({
from: '"Omise Reports" <reports@example.com>',
to: 'accounting@example.com, manager@example.com',
subject: `Daily Payment Report - ${yesterday.toISOString().split('T')[0]}`,
text: `Please find attached the daily payment report.\n\nSummary:\n- Total Transactions: ${charges.total}\n- Total Amount: ${reportData.reduce((sum, r) => sum + r.Amount, 0)} THB`,
attachments: [{
filename: filename,
path: filename
}]
});
console.log(`Report sent successfully: ${filename}`);
// Clean up file
fs.unlinkSync(filename);
} catch (error) {
console.error('Error generating report:', error);
}
}
// Schedule daily report at 8:00 AM
cron.schedule('0 8 * * *', () => {
console.log('Running scheduled report...');
generateAndEmailReport();
});
console.log('Report scheduler started');
Export Optionsโ
Export Formatsโ
1. CSV (Comma-Separated Values)โ
- Best for: Excel, Google Sheets, data analysis
- Size: Small file size
- Compatibility: Universal
2. Excel (XLSX)โ
- Best for: Advanced Excel features, formatting
- Size: Medium file size
- Compatibility: Microsoft Excel, Google Sheets
3. PDFโ
- Best for: Printing, sharing, archiving
- Size: Larger file size
- Compatibility: Universal viewing
Exporting via Dashboardโ
- Navigate to desired report
- Apply filters and date range
- Click Export button
- Select format (CSV, Excel, PDF)
- Download starts automatically
Exporting via APIโ
<?php
// PHP - Export transactions to multiple formats
require_once 'vendor/autoload.php';
define('OMISE_SECRET_KEY', 'skey_test_xxxxx');
class TransactionExporter {
public function exportToCSV($charges, $filename) {
$fp = fopen($filename, 'w');
// Write header
fputcsv($fp, [
'Transaction ID',
'Amount',
'Currency',
'Card Brand',
'Card Last 4',
'Status',
'Created',
'Description'
]);
// Write data
foreach ($charges as $charge) {
fputcsv($fp, [
$charge['id'],
$charge['amount'] / 100,
strtoupper($charge['currency']),
$charge['card']['brand'] ?? 'N/A',
$charge['card']['last_digits'] ?? 'N/A',
$charge['status'],
date('Y-m-d H:i:s', $charge['created']),
$charge['description'] ?? ''
]);
}
fclose($fp);
echo "Exported to CSV: $filename\n";
}
public function exportToJSON($charges, $filename) {
$data = array_map(function($charge) {
return [
'id' => $charge['id'],
'amount' => $charge['amount'] / 100,
'currency' => strtoupper($charge['currency']),
'card' => [
'brand' => $charge['card']['brand'] ?? null,
'last4' => $charge['card']['last_digits'] ?? null
],
'status' => $charge['status'],
'created' => date('c', $charge['created']),
'description' => $charge['description'] ?? ''
];
}, $charges);
file_put_contents($filename, json_encode($data, JSON_PRETTY_PRINT));
echo "Exported to JSON: $filename\n";
}
public function exportToHTML($charges, $filename) {
$html = '<!DOCTYPE html>
<html>
<head>
<title>Transaction Report</title>
<style>
table { border-collapse: collapse; width: 100%; }
th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
th { background-color: #4CAF50; color: white; }
tr:nth-child(even) { background-color: #f2f2f2; }
</style>
</head>
<body>
<h1>Transaction Report</h1>
<table>
<tr>
<th>Transaction ID</th>
<th>Amount</th>
<th>Currency</th>
<th>Card Brand</th>
<th>Status</th>
<th>Date</th>
</tr>';
foreach ($charges as $charge) {
$html .= sprintf(
'<tr>
<td>%s</td>
<td>%.2f</td>
<td>%s</td>
<td>%s</td>
<td>%s</td>
<td>%s</td>
</tr>',
htmlspecialchars($charge['id']),
$charge['amount'] / 100,
strtoupper($charge['currency']),
htmlspecialchars($charge['card']['brand'] ?? 'N/A'),
htmlspecialchars($charge['status']),
date('Y-m-d H:i:s', $charge['created'])
);
}
$html .= '
</table>
</body>
</html>';
file_put_contents($filename, $html);
echo "Exported to HTML: $filename\n";
}
}
// Fetch transactions
$charges = OmiseCharge::retrieve([
'from' => date('c', strtotime('-30 days')),
'to' => date('c'),
'limit' => 100
]);
// Export to multiple formats
$exporter = new TransactionExporter();
$exporter->exportToCSV($charges['data'], 'transactions.csv');
$exporter->exportToJSON($charges['data'], 'transactions.json');
$exporter->exportToHTML($charges['data'], 'transactions.html');
?>
Common Use Casesโ
1. Accounting and Bookkeepingโ
# Python - Generate accounting report
import omise
from datetime import datetime, timedelta
from decimal import Decimal
omise.api_secret = 'skey_test_xxxxx'
def generate_accounting_report(year, month):
"""Generate monthly accounting report."""
# Calculate date range
from_date = datetime(year, month, 1)
if month == 12:
to_date = datetime(year + 1, 1, 1) - timedelta(seconds=1)
else:
to_date = datetime(year, month + 1, 1) - timedelta(seconds=1)
# Fetch transactions
charges = omise.Charge.list(
from_date=from_date.isoformat(),
to_date=to_date.isoformat(),
paid=True,
limit=100
)
# Calculate accounting metrics
gross_revenue = Decimal(0)
fees = Decimal(0)
refunds = Decimal(0)
for charge in charges.data:
amount = Decimal(charge.amount) / 100
fee = Decimal(charge.fee or 0) / 100
refunded = Decimal(charge.refunded_amount) / 100
gross_revenue += amount
fees += fee
refunds += refunded
net_revenue = gross_revenue - fees - refunds
report = {
'period': f'{year}-{month:02d}',
'gross_revenue': float(gross_revenue),
'payment_fees': float(fees),
'refunds': float(refunds),
'net_revenue': float(net_revenue),
'transaction_count': len(charges.data)
}
return report
# Generate report for current month
now = datetime.now()
report = generate_accounting_report(now.year, now.month)
print("Accounting Report")
print("=" * 50)
print(f"Period: {report['period']}")
print(f"Gross Revenue: {report['gross_revenue']:.2f}")
print(f"Payment Fees: {report['payment_fees']:.2f}")
print(f"Refunds: {report['refunds']:.2f}")
print(f"Net Revenue: {report['net_revenue']:.2f}")
print(f"Transactions: {report['transaction_count']}")
2. Reconciliationโ
// Node.js - Bank reconciliation tool
const omise = require('omise')({
secretKey: 'skey_test_xxxxx'
});
async function reconcileWithBankStatement(bankTransactions, settlementDate) {
try {
// Fetch Omise settlements
const transfers = await omise.transfers.list({
from: settlementDate,
to: new Date(settlementDate.getTime() + 24 * 60 * 60 * 1000).toISOString(),
limit: 100
});
const reconciliation = {
matched: [],
omise_only: [],
bank_only: [],
discrepancies: []
};
// Create lookup map for bank transactions
const bankMap = new Map();
bankTransactions.forEach(tx => {
bankMap.set(tx.reference, tx);
});
// Match Omise transfers with bank transactions
transfers.data.forEach(transfer => {
const bankTx = bankMap.get(transfer.id);
if (bankTx) {
const omiseAmount = transfer.amount / 100;
const bankAmount = parseFloat(bankTx.amount);
if (Math.abs(omiseAmount - bankAmount) < 0.01) {
reconciliation.matched.push({
reference: transfer.id,
amount: omiseAmount,
date: new Date(transfer.created * 1000)
});
} else {
reconciliation.discrepancies.push({
reference: transfer.id,
omise_amount: omiseAmount,
bank_amount: bankAmount,
difference: bankAmount - omiseAmount
});
}
bankMap.delete(transfer.id);
} else {
reconciliation.omise_only.push({
reference: transfer.id,
amount: transfer.amount / 100,
status: transfer.status
});
}
});
// Remaining bank transactions not in Omise
bankMap.forEach((tx, ref) => {
reconciliation.bank_only.push({
reference: ref,
amount: parseFloat(tx.amount),
date: tx.date
});
});
return reconciliation;
} catch (error) {
console.error('Reconciliation error:', error);
throw error;
}
}
// Example usage
const bankData = [
{ reference: 'trsf_test_123', amount: '9850.00', date: '2024-01-15' },
{ reference: 'trsf_test_124', amount: '15200.00', date: '2024-01-15' }
];
reconcileWithBankStatement(bankData, new Date('2024-01-15'))
.then(result => {
console.log('Reconciliation Results:');
console.log(`Matched: ${result.matched.length}`);
console.log(`Omise Only: ${result.omise_only.length}`);
console.log(`Bank Only: ${result.bank_only.length}`);
console.log(`Discrepancies: ${result.discrepancies.length}`);
if (result.discrepancies.length > 0) {
console.log('\nDiscrepancies:');
result.discrepancies.forEach(d => {
console.log(`${d.reference}: Difference of ${d.difference}`);
});
}
});
3. Analytics and Business Intelligenceโ
// Go - Advanced analytics report
package main
import (
"encoding/json"
"fmt"
"time"
"github.com/omise/omise-go"
"github.com/omise/omise-go/operations"
)
type AnalyticsReport struct {
Period string `json:"period"`
Revenue RevenueMetrics `json:"revenue"`
Transactions TransactionMetrics `json:"transactions"`
PaymentMethods map[string]int `json:"payment_methods"`
TopCustomers []CustomerMetrics `json:"top_customers"`
}
type RevenueMetrics struct {
Total float64 `json:"total"`
Average float64 `json:"average"`
Median float64 `json:"median"`
Growth float64 `json:"growth_percentage"`
}
type TransactionMetrics struct {
Total int `json:"total"`
Successful int `json:"successful"`
Failed int `json:"failed"`
SuccessRate float64 `json:"success_rate"`
}
type CustomerMetrics struct {
CustomerID string `json:"customer_id"`
TransactionCount int `json:"transaction_count"`
TotalSpent float64 `json:"total_spent"`
}
func generateAnalyticsReport(from, to time.Time) (*AnalyticsReport, error) {
client, err := omise.NewClient("pkey_test_xxxxx", "skey_test_xxxxx")
if err != nil {
return nil, err
}
// Fetch charges
charges := &omise.ChargeList{}
err = client.Do(charges, &operations.ListCharges{
ListParams: operations.ListParams{
From: from,
To: to,
Limit: 100,
},
})
if err != nil {
return nil, err
}
// Calculate metrics
var totalRevenue int64
var successfulCount int
paymentMethods := make(map[string]int)
customerSpending := make(map[string]*CustomerMetrics)
for _, charge := range charges.Data {
if charge.Paid {
successfulCount++
totalRevenue += charge.Amount
// Track payment methods
if charge.Card != nil {
paymentMethods[charge.Card.Brand]++
}
// Track customer spending
if charge.Customer != "" {
if _, exists := customerSpending[charge.Customer]; !exists {
customerSpending[charge.Customer] = &CustomerMetrics{
CustomerID: charge.Customer,
}
}
customerSpending[charge.Customer].TransactionCount++
customerSpending[charge.Customer].TotalSpent += float64(charge.Amount) / 100
}
}
}
// Calculate success rate
successRate := 0.0
if charges.Total > 0 {
successRate = float64(successfulCount) / float64(charges.Total) * 100
}
// Get top 5 customers
topCustomers := make([]CustomerMetrics, 0)
for _, metrics := range customerSpending {
topCustomers = append(topCustomers, *metrics)
}
// Sort by total spent (simplified - use proper sorting in production)
report := &AnalyticsReport{
Period: fmt.Sprintf("%s to %s", from.Format("2006-01-02"), to.Format("2006-01-02")),
Revenue: RevenueMetrics{
Total: float64(totalRevenue) / 100,
Average: float64(totalRevenue) / float64(successfulCount) / 100,
},
Transactions: TransactionMetrics{
Total: charges.Total,
Successful: successfulCount,
Failed: charges.Total - successfulCount,
SuccessRate: successRate,
},
PaymentMethods: paymentMethods,
TopCustomers: topCustomers[:min(5, len(topCustomers))],
}
return report, nil
}
func min(a, b int) int {
if a < b {
return a
}
return b
}
func main() {
to := time.Now()
from := to.AddDate(0, -1, 0) // Last month
report, err := generateAnalyticsReport(from, to)
if err != nil {
panic(err)
}
jsonData, _ := json.MarshalIndent(report, "", " ")
fmt.Println(string(jsonData))
}
4. Compliance Reportingโ
# Ruby - Compliance and audit report
require 'omise'
require 'csv'
require 'digest'
Omise.api_key = 'skey_test_xxxxx'
class ComplianceReport
def initialize(from_date, to_date)
@from_date = from_date
@to_date = to_date
@charges = []
@refunds = []
end
def generate
fetch_data
{
report_metadata: generate_metadata,
transaction_summary: generate_summary,
detailed_transactions: generate_detailed_list,
refund_summary: generate_refund_summary,
data_integrity: verify_data_integrity
}
end
private
def fetch_data
# Fetch charges
charges_list = Omise::Charge.list({
from: @from_date.iso8601,
to: @to_date.iso8601,
limit: 100
})
@charges = charges_list.data
# Fetch refunds for each charge
@charges.each do |charge|
if charge.refunded_amount > 0
refunds = Omise::Refund.list(charge_id: charge.id)
@refunds.concat(refunds.data)
end
end
end
def generate_metadata
{
report_date: DateTime.now.iso8601,
period_start: @from_date.iso8601,
period_end: @to_date.iso8601,
report_id: generate_report_id,
total_records: @charges.length
}
end
def generate_summary
successful = @charges.select(&:paid)
failed = @charges.reject(&:paid)
{
total_transactions: @charges.length,
successful_transactions: successful.length,
failed_transactions: failed.length,
total_amount: successful.sum(&:amount) / 100.0,
total_refunded: @refunds.sum(&:amount) / 100.0,
net_amount: (successful.sum(&:amount) - @refunds.sum(&:amount)) / 100.0
}
end
def generate_detailed_list
@charges.map do |charge|
{
transaction_id: charge.id,
timestamp: Time.at(charge.created).utc.iso8601,
amount: charge.amount / 100.0,
currency: charge.currency.upcase,
status: charge.status,
payment_method: charge.card&.brand || 'Other',
card_last4: charge.card&.last_digits,
customer_id: charge.customer || 'Guest',
ip_address: charge.ip || 'N/A',
refunded: charge.refunded,
refunded_amount: charge.refunded_amount / 100.0
}
end
end
def generate_refund_summary
{
total_refunds: @refunds.length,
total_amount: @refunds.sum(&:amount) / 100.0,
by_charge: @refunds.group_by(&:charge).transform_values do |refunds|
{
count: refunds.length,
amount: refunds.sum(&:amount) / 100.0
}
end
}
end
def verify_data_integrity
# Calculate checksum of transaction data
data_string = @charges.map(&:id).sort.join
checksum = Digest::SHA256.hexdigest(data_string)
{
checksum: checksum,
verified: true,
record_count: @charges.length
}
end
def generate_report_id
timestamp = DateTime.now.strftime('%Y%m%d%H%M%S')
hash = Digest::SHA256.hexdigest("#{@from_date}#{@to_date}#{timestamp}")[0..7]
"RPT-#{timestamp}-#{hash}"
end
end
# Generate compliance report
from_date = DateTime.now - 30
to_date = DateTime.now
report = ComplianceReport.new(from_date, to_date).generate
puts JSON.pretty_generate(report)
Best Practicesโ
1. Data Managementโ
- Regularly export and archive transaction data
- Implement data retention policies
- Use version control for report templates
- Document custom report logic
2. Performance Optimizationโ
- Use pagination for large datasets
- Cache frequently accessed reports
- Schedule heavy reports during off-peak hours
- Use appropriate date ranges
3. Securityโ
- Limit API key permissions
- Encrypt exported data
- Use secure file transfer methods
- Implement access controls
- Audit report access regularly
4. Accuracyโ
- Verify timezone settings
- Double-check filter criteria
- Reconcile regularly with bank statements
- Document any manual adjustments
- Maintain audit trails
Troubleshootingโ
Export Timeoutsโ
Problem: Large exports timing out
Solution:
// Node.js - Paginated export for large datasets
async function exportLargeDataset(fromDate, toDate, outputFile) {
const fs = require('fs');
const writeStream = fs.createWriteStream(outputFile);
// Write CSV header
writeStream.write('Transaction ID,Amount,Currency,Status,Date\n');
let offset = 0;
const limit = 100;
let hasMore = true;
while (hasMore) {
const charges = await omise.charges.list({
from: fromDate,
to: toDate,
limit: limit,
offset: offset
});
charges.data.forEach(charge => {
writeStream.write(
`${charge.id},${charge.amount/100},${charge.currency},${charge.status},${new Date(charge.created*1000).toISOString()}\n`
);
});
offset += limit;
hasMore = charges.data.length === limit;
console.log(`Exported ${offset} records...`);
}
writeStream.end();
console.log(`Export complete: ${outputFile}`);
}
Missing Transactionsโ
Problem: Expected transactions not showing in reports
Checklist:
- Verify date range includes transaction date
- Check timezone settings
- Confirm transaction status matches filter
- Ensure API key has correct permissions
- Check if transaction is in test vs. live mode
Data Discrepanciesโ
Problem: Report totals don't match expectations
Solution:
- Verify all filters are correctly applied
- Check for partial refunds
- Confirm currency conversions
- Review fee calculations
- Compare with settlement reports
FAQโ
Q1: How long are transaction reports retained?
A: Omise retains transaction data for 7 years. You can access and export data from any point within this period. We recommend regular exports for your own archival purposes.
Q2: Can I generate reports for specific payment methods?
A: Yes, you can filter reports by payment method including credit cards (by brand), internet banking, mobile banking, e-wallets, and QR payments. Use the payment method filter in the dashboard or the API's filter parameters.
Q3: How do I handle multi-currency reporting?
A: Reports show amounts in the original transaction currency. For consolidated reporting across currencies, you can:
- Export data and apply custom conversion rates
- Use the API to fetch exchange rates at transaction time
- Generate separate reports per currency
- Use third-party business intelligence tools
Q4: What's the maximum number of transactions I can export at once?
A: Dashboard exports are limited to 10,000 transactions per file. For larger exports, use the API with pagination to retrieve all transactions programmatically.
Q5: Can I schedule different reports for different team members?
A: Yes, you can create multiple scheduled reports with different recipients. Each report can have its own filters, frequency, and format. Configure this in the Scheduled Reports section.
Q6: How do I include custom metadata in reports?
A: Custom metadata is included in detailed report exports. In the dashboard, enable the metadata column in the column selector. Via API, metadata is included in the charge object by default.
Q7: What's the difference between transaction date and settlement date?
A: Transaction date is when a payment was processed. Settlement date is when funds are transferred to your bank account (typically 3-7 business days later depending on your agreement).
Q8: Can I create custom report templates?
A: While the dashboard provides standard templates, you can create custom reports using the API. Export data programmatically and format it according to your specific requirements. Many merchants build custom reporting dashboards integrated with their accounting systems.
Related Resourcesโ
Documentationโ
- Dashboard Overview - Dashboard navigation and features
- Balance Reports - Settlement and balance reporting
- Charges API - Charge API reference
- Refunds API - Refund API reference
Toolsโ
- API Playground - Test report queries
- Export Templates - Custom export formats
- Report Scheduler - Automated reports
Supportโ
- Knowledge Base - Common questions
- Contact Support - Get help
Next Stepsโ
-
- Automate daily/weekly/monthly reports
- Configure email delivery
- Customize report content
-
- View settlement details
- Track account balance
- Reconcile with bank statements
-
Integrate with accounting software
- QuickBooks integration
- Xero integration
- Custom integrations