Batch Processing Integration Guide
Upload a CSV file to CommBank's SFTP service to process multiple payments in a single batch — ideal for recurring billing, bulk supplier payments, and scheduled transaction runs.
What you'll need:
- SFTP credentials from Connected Payments (hostname, username, password or SSH key, directory path)
sharedSecret- Your shared secret for generating thehashedUserNameauthentication fieldcustomerID- Your Connected Payments hierarchy ID- Existing card tokens for processing payments — see Tokenisation
IP whitelisting is required prior to using SFTP. Contact [email protected] to obtain access and request whitelisting if you haven't already.
Code samples: Code samples within this document are provided for reference purposes only and are not intended for production use.
How it works
Flow:
- Prepare a CSV file with your transactions following the naming and field rules below
- Generate
hashedUserNameusing your shared secret (HMAC-SHA256) - Upload the file to your assigned SFTP directory
- The batch service picks it up, validates it, and processes each row
- Results (approved/declined per transaction) appear in the Connected Payments dashboard
Quick start
Step 1: Name your file
Filenames must follow this exact pattern — files that don't match are rejected.
[customerID]-[yyyymmdd]-[suffix].csv
| Component | Description | Example |
|---|---|---|
customerID | Your CommBank hierarchy ID | demoMerchant |
yyyymmdd | Processing date | 20260531 |
suffix | Unique batch reference | batchDemo |
Your assembled filename will look like this:
demoMerchant-20260531-batchDemo.csv
Rules:
- The full filename must be unique — never reuse a filename
- The suffix must be unique per customer — duplicate suffixes are rejected
- The date cannot be in the past — use today or a future date
- Future dates are valid — the file queues and processes on that date
Step 2: Generate hashedUserName
hashedUserName is an HMAC-SHA256 digest of your batch username using your shared secret. Calculate it once and reuse the same value on every row in the file.
Server-side only — Never expose sharedSecret in client code or CSV files stored in insecure locations.
Node.js
const crypto = require("crypto");
const hashedUserName = crypto
.createHmac("sha256", process.env.BATCH_SHARED_SECRET)
.update("your-batch-username")
.digest("hex");
PHP
$hashedUserName = hash_hmac(
'sha256',
'your-batch-username',
getenv('BATCH_SHARED_SECRET')
);
Python
import hmac, hashlib, os
hashed_username = hmac.new(
os.environ['BATCH_SHARED_SECRET'].encode(),
'your-batch-username'.encode(),
hashlib.sha256
).hexdigest()
C#
using System.Security.Cryptography;
using System.Text;
using (var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(Environment.GetEnvironmentVariable("BATCH_SHARED_SECRET"))))
{
byte[] hash = hmac.ComputeHash(Encoding.UTF8.GetBytes("your-batch-username"));
string hashedUserName = BitConverter.ToString(hash).Replace("-", "").ToLower();
}
Step 3: Build your CSV
Every CSV requires a header row followed by one data row per transaction. Use stored card tokens for all batch processing.
cardToken,merchReference,amount,txnType,hashedUserName
token_abc123xyz,SUB-001,9900,1,abc123def456...
token_def456uvw,SUB-002,9900,1,abc123def456...
Required fields:
| Field | Description | Format | Example |
|---|---|---|---|
cardToken | Stored card token or alias | Token string | token_abc123xyz |
merchReference | Unique reference per transaction | Alphanumeric | SUB-001 |
amount | Amount in cents | Integer | 9900 (= $99.00) |
txnType | Transaction type (numeric) | Integer | 1 (Purchase) |
hashedUserName | HMAC-SHA256 of your batch username | Hex string | abc123def456... |
Optional fields:
| Field | Description | Required when |
|---|---|---|
cardHolderName | Cardholder name | Optional but recommended |
txnId | Original transaction ID | Required for refund and complete |
metadata.* | Custom key-value data (e.g. metadata.invoice) | Never required |
For merchReference, each row must have a unique value — duplicates will be rejected. Use a format like INV-{id} or SUB-{customerId}-{date} to guarantee uniqueness.
Step 4: Upload via SFTP
Connect to the SFTP server using the credentials provided by Connected Payments and place the file in your assigned directory.
Command line (Linux / macOS)
sftp [email protected]
cd /path/to/batch/directory
put demoMerchant-20260531-batchDemo.csv
quit
Node.js (automated)
const Client = require("ssh2-sftp-client");
const sftp = new Client();
await sftp.connect({
host: "sftp-host.com",
port: 22,
username: process.env.SFTP_USER,
password: process.env.SFTP_PASSWORD,
});
await sftp.put(
"demoMerchant-20260531-batchDemo.csv",
"/batch/dir/demoMerchant-20260531-batchDemo.csv",
);
await sftp.end();
Python (automated)
import paramiko, os
transport = paramiko.Transport(('sftp-host.com', 22))
transport.connect(
username=os.environ['SFTP_USER'],
password=os.environ['SFTP_PASSWORD']
)
sftp = paramiko.SFTPClient.from_transport(transport)
sftp.put('demoMerchant-20260531-batchDemo.csv', '/batch/dir/demoMerchant-20260531-batchDemo.csv')
sftp.close()
transport.close()
PHP (automated)
$connection = ssh2_connect('sftp-host.com', 22);
ssh2_auth_password($connection, getenv('SFTP_USER'), getenv('SFTP_PASSWORD'));
$sftp = ssh2_sftp($connection);
$localFile = 'demoMerchant-20260531-batchDemo.csv';
$remotePath = '/batch/dir/demoMerchant-20260531-batchDemo.csv';
$stream = fopen("ssh2.sftp://{$sftp}{$remotePath}", 'w');
fwrite($stream, file_get_contents($localFile));
fclose($stream);
GUI clients such as FileZilla or WinSCP also work — connect on port 22 using the SFTP protocol and drag the file to your directory.
Step 5: Check results
Log in to the Connected Payments dashboard, navigate to Batch Processing or Transactions, and filter by your batch reference. Each transaction row will show its status (Approved / Declined), response code, and transaction ID.
Complete examples
- Recurring Billing (Tokens)
- Refund Batch
- With Metadata
View full Node.js implementation — Automated recurring batch
const crypto = require("crypto");
const Client = require("ssh2-sftp-client");
const fs = require("fs");
const CONFIG = {
customerID: "demoMerchant",
batchUsername: "your-batch-username",
sharedSecret: process.env.BATCH_SHARED_SECRET,
sftpHost: "sftp-host.com",
sftpUser: process.env.SFTP_USER,
sftpPassword: process.env.SFTP_PASSWORD,
sftpDir: "/batch/dir/",
};
// Step 1: Generate hashedUserName
const hashedUserName = crypto
.createHmac("sha256", CONFIG.sharedSecret)
.update(CONFIG.batchUsername)
.digest("hex");
// Step 2: Build CSV from subscription data
function buildBatchCSV(subscriptions) {
const header = "cardToken,merchReference,amount,txnType,hashedUserName";
const rows = subscriptions.map(
(sub) => `${sub.token},${sub.reference},${sub.amount},1,${hashedUserName}`,
);
return [header, ...rows].join("\n");
}
// Step 3: Generate filename
const today = new Date().toISOString().slice(0, 10).replace(/-/g, "");
const suffix = `recurring-${Date.now()}`;
const filename = `${CONFIG.customerID}-${today}-${suffix}.csv`;
// Step 4: Write and upload
async function processBatch(subscriptions) {
const csv = buildBatchCSV(subscriptions);
fs.writeFileSync(filename, csv);
const sftp = new Client();
await sftp.connect({
host: CONFIG.sftpHost,
port: 22,
username: CONFIG.sftpUser,
password: CONFIG.sftpPassword,
});
await sftp.put(filename, `${CONFIG.sftpDir}${filename}`);
await sftp.end();
console.log(`Batch uploaded: ${filename}`);
}
// Example usage
processBatch([
{ token: "token_abc123xyz", reference: "SUB-001", amount: 9900 },
{ token: "token_def456uvw", reference: "SUB-002", amount: 9900 },
]);
View full Python implementation — Automated recurring batch
import hmac
import hashlib
import csv
import os
import paramiko
from datetime import datetime
CONFIG = {
'customer_id': 'demoMerchant',
'batch_username': 'your-batch-username',
'shared_secret': os.environ['BATCH_SHARED_SECRET'],
'sftp_host': 'sftp-host.com',
'sftp_user': os.environ['SFTP_USER'],
'sftp_password': os.environ['SFTP_PASSWORD'],
'sftp_dir': '/batch/dir/'
}
# Step 1: Generate hashedUserName
hashed_username = hmac.new(
CONFIG['shared_secret'].encode(),
CONFIG['batch_username'].encode(),
hashlib.sha256
).hexdigest()
# Step 2: Build CSV
def build_batch_csv(subscriptions, filename):
with open(filename, 'w', newline='') as f:
writer = csv.writer(f)
writer.writerow(['cardToken', 'merchReference', 'amount', 'txnType', 'hashedUserName'])
for sub in subscriptions:
writer.writerow([sub['token'], sub['reference'], sub['amount'], 1, hashed_username])
# Step 3: Generate filename
today = datetime.now().strftime('%Y%m%d')
suffix = f'recurring-{int(datetime.now().timestamp())}'
filename = f"{CONFIG['customer_id']}-{today}-{suffix}.csv"
# Step 4: Write and upload
def process_batch(subscriptions):
build_batch_csv(subscriptions, filename)
transport = paramiko.Transport((CONFIG['sftp_host'], 22))
transport.connect(username=CONFIG['sftp_user'], password=CONFIG['sftp_password'])
sftp = paramiko.SFTPClient.from_transport(transport)
sftp.put(filename, f"{CONFIG['sftp_dir']}{filename}")
sftp.close()
transport.close()
print(f'Batch uploaded: {filename}')
# Example usage
process_batch([
{'token': 'token_abc123xyz', 'reference': 'SUB-001', 'amount': 9900},
{'token': 'token_def456uvw', 'reference': 'SUB-002', 'amount': 9900},
])
Process refunds against previously approved transactions. Each row must include the txnId from the original purchase.
txnId,merchReference,amount,txnType,hashedUserName
1195fd71220dfae,REF-12345,5000,20,abc123def456...
a3b4c5d6e7f8901,REF-12346,2500,20,abc123def456...
Include custom key-value data by prefixing column headers with metadata. — useful for reconciliation and reporting.
cardToken,merchReference,amount,txnType,hashedUserName,metadata.invoice,metadata.customer
token_abc123xyz,ORD-001,10000,1,abc123def456...,INV-2026-001,CUST-123
token_def456uvw,ORD-002,5000,1,abc123def456...,INV-2026-002,CUST-456
Configuration reference
Transaction types
| Value | Description | Requires txnId |
|---|---|---|
1 | Purchase — Standard payment | No |
9 | Capture — Capture pre-authorized funds | Yes |
10 | Pre-Auth — Hold funds without charging | No |
20 | Refund — Refund against original transaction | Yes |
Parameters
- Required
- Optional
| Field | Type | Description | Example |
|---|---|---|---|
cardToken | String | Stored card token or alias | token_abc123xyz |
merchReference | String | Unique reference per transaction | INV-12345 |
amount | Integer | Amount in cents (e.g. 10000 = $100.00) | 10000 |
txnType | Integer | Transaction type (numeric value) | 1 |
hashedUserName | String | HMAC-SHA256 of your batch username | abc123def456... |
| Field | Type | Description | Required when |
|---|---|---|---|
cardHolderName | String | Cardholder name | Optional but recommended |
txnId | String | Original transaction ID | Required for refund and complete |
metadata.* | String | Custom key-value data (e.g. metadata.invoice) | Never required |
File naming
| Component | Description | Example |
|---|---|---|
customerID | Your CommBank hierarchy ID | demoMerchant |
yyyymmdd | Processing date (today or future) | 20260531 |
suffix | Unique batch reference (unique per customer) | batchDemo |
Format: [customerID]-[yyyymmdd]-[suffix].csv
Security checklist
-
sharedSecretstored in environment variables — never hardcoded - SFTP credentials stored securely — prefer SSH keys over passwords
- Batch files use card tokens only — never include raw card numbers
- Uploaded files are archived and access is audited
Troubleshooting
For a full reference, see the Troubleshooting Guide in the FAQ & Support section.
Testing
Use the sandbox SFTP environment to test your batch files before processing live transactions. Never use real card numbers in test batches — use test cards and tokens instead.
Verification steps:
- Generate
hashedUserNameusing your sandbox shared secret - Build a CSV with test card tokens and a small number of rows
- Upload to your sandbox SFTP directory
- Check results in the Connected Payments dashboard under Batch Processing
For full test details, see the Testing Guide.