Skip to main content

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:

  1. Navigate to Transactions > Payments
  2. Select date range
  3. Apply filters as needed
  4. 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โ€‹

  1. Date Range

    • Specific dates
    • Relative ranges (today, yesterday, last 7 days, etc.)
    • Custom date ranges
  2. Status

    • Successful
    • Failed
    • Pending
    • Reversed
    • Expired
  3. Amount

    • Minimum amount
    • Maximum amount
    • Exact amount
    • Amount ranges
  4. Payment Method

    • Credit/Debit cards (by brand)
    • Internet banking
    • Mobile banking
    • E-wallets
    • QR payments
    • Installments
  5. Currency

    • THB (Thai Baht)
    • SGD (Singapore Dollar)
    • JPY (Japanese Yen)
    • USD (US Dollar)
    • And more
  6. Customer

    • Customer ID
    • Email
    • Customer name
  7. Metadata

    • Custom metadata fields
    • Order ID
    • Reference numbers

Using Filters via Dashboardโ€‹

  1. Navigate to Transactions
  2. Click Filters button
  3. Select filter criteria
  4. Click Apply Filters
  5. 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โ€‹

Use the dashboard search to find specific transactions:

  1. By Transaction ID

    • Enter full or partial charge ID
    • Format: chrg_test_xxxxx
  2. By Customer Email

    • Enter customer email address
    • Searches across all customer transactions
  3. By Amount

    • Enter exact amount
    • Specify currency
  4. 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โ€‹

  1. Navigate to Reports > Scheduled Reports

  2. Click "Create Schedule"

  3. 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)
  4. Set Recipients:

    • Add email addresses
    • Configure delivery time
    • Set timezone
  5. 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โ€‹

  1. Navigate to desired report
  2. Apply filters and date range
  3. Click Export button
  4. Select format (CSV, Excel, PDF)
  5. 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:

  1. Verify date range includes transaction date
  2. Check timezone settings
  3. Confirm transaction status matches filter
  4. Ensure API key has correct permissions
  5. 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.

Documentationโ€‹

Toolsโ€‹

Supportโ€‹

Next Stepsโ€‹

  1. Set up scheduled reports

    • Automate daily/weekly/monthly reports
    • Configure email delivery
    • Customize report content
  2. Explore balance reports

    • View settlement details
    • Track account balance
    • Reconcile with bank statements
  3. Integrate with accounting software

    • QuickBooks integration
    • Xero integration
    • Custom integrations