Batch Close
Usage Flow
- Call the Batch Query API first to retrieve pending settlement batches. If no pending batches exist, no close operation is needed.
- A single terminal may connect to multiple Processors (each represented by a different
channelCode). Call this API once for eachchannelCodereturned in the Batch Query response. - The
channelCodevalue comes from the Batch Query response — always use it dynamically rather than using a fixed value.
Timeout Handling
If a Batch Close request times out due to a network issue, call the Batch Query API to verify the settlement result. The batch close was successful — and no retry is needed — if either of the following is true:
- No pending settlement batch exists for that
channelCode; - The
batchNoof the pending batch returned by the query differs from thebatchNoin your original close request (indicating the original batch has already been closed and a new batch has been opened).
ENDPOINT
POST
https://open.sunbay.us/v1/settlement/batch-closeThe Batch Close API is used to close the current transaction batch and trigger the settlement process. After calling this API, the backend immediately initiates a batch close settlement request, and the API returns the batch close result. Once the batch is closed, it cannot be reversed, and transactions within the batch will enter the settlement process.
Parameters
Header parameters
| Name | Type | Required | Description |
|---|---|---|---|
Authorization | string | Y | Bearer Token authentication, format: Bearer {your_api_key} Example: "Bearer sk_test_4eC39HqLyjWDarjtT1zdp7dc" |
Content-Type | string | Y | Request content type, fixed value: application/json |
X-Client-Request-Id | string(64) | Y | Request unique identifier, used to prevent duplicate requests and issue tracking. UUID format is recommended, each request must use a unique Request ID Example: "550e8400-e29b-41d4-a716-446655440000" |
X-Timestamp | string | Y | Request timestamp, Unix timestamp (milliseconds), 13 digits. The deviation between the request timestamp and server time cannot exceed ±10 minutes Pattern: ^[0-9]{13}$Example: "1701234567890" |
Body parameters
| Name | Type | Required | Description |
|---|---|---|---|
appId | string(32) | Y | Application ID Example: "app_123456" |
merchantId | string(32) | Y | Merchant ID Example: "mch_789012" |
transactionRequestId | string(32) | Y | Batch close request unique identifier. Used to identify the unique ID of this batch close, serves as an API idempotency control field, and can be used to query batch close results later. Can only contain letters, numbers, underscores and hyphens, maximum length 32 characters. Must not be repeated for each request Pattern: ^[A-Za-z0-9_\-]+$Example: "BATCH_CLOSE_20231119001" |
terminalSn | string(32) | Y | Payment terminal serial number. The payment terminal device serial number provided by SUNBAY, which is used for reading bank cards, processing PINs and other security operations Example: "T1234567890" |
channelCode | string(32) | Y | Payment channel code. Obtain this value from the Batch Query API response — always use it dynamically rather than using a fixed value. A single terminal may connect to multiple Processors (each represented by a different channelCode); call this API once per channelCode returned by Batch Query. Example: "TSYS" |
description | string(128) | N | Batch close description Example: "End of business day, close batch" |
attach | string(128) | N | Additional data, returned as is, JSON format recommended Example: "{\"closeTime\":\"2023-11-19T22:00:00+08:00\"}" |
Request Example
{
"appId": "app_123456",
"merchantId": "mch_789012",
"transactionRequestId": "BATCH_CLOSE_20231119001",
"terminalSn": "T1234567890",
"channelCode": "TSYS",
"description": "End of business day, close batch"
}Code Examples
cURLbash
Response parameters
| Name | Type | Required | Description |
|---|---|---|---|
code | string(16) | Y | Response code, 0 indicates success Example: "0" |
msg | string(128) | N | Response description Example: "Batch close successful" |
traceId | string(64) | Y | Trace ID, used for troubleshooting Example: "TRACE123456789" |
data | object | Y |
Full Settlement Flow Example (Java)
The following pseudocode demonstrates the complete flow: query pending batches → close each one → handle timeout.
// 1. Query pending settlement batches
BatchQueryResponse queryResponse = client.batchQuery(new BatchQueryRequest(appId, merchantId, terminalSn));
List<BatchInfo> pendingBatches = queryResponse.getPendingBatches();
if (pendingBatches == null || pendingBatches.isEmpty()) {
// No pending batches — nothing to close
return;
}
// 2. Close each batch by channelCode
for (BatchInfo batch : pendingBatches) {
String channelCode = batch.getChannelCode();
String batchNo = batch.getBatchNo();
try {
BatchCloseResponse closeResponse = client.batchClose(new BatchCloseRequest(
appId, merchantId, generateRequestId(), terminalSn, channelCode
));
log.info("Batch closed successfully: channelCode={}, batchNo={}", channelCode, closeResponse.getBatchNo());
} catch (TimeoutException e) {
// 3. Timeout: verify the result via Batch Query
handleTimeout(client, appId, merchantId, terminalSn, channelCode, batchNo);
}
}
/**
* After a timeout, query to confirm whether the batch close has taken effect.
*/
private void handleTimeout(NexusClient client, String appId, String merchantId,
String terminalSn, String channelCode, String originalBatchNo) {
BatchQueryResponse retryQuery = client.batchQuery(new BatchQueryRequest(appId, merchantId, terminalSn));
// Check if a pending batch still exists for this channelCode
Optional<BatchInfo> pending = retryQuery.getPendingBatches().stream()
.filter(b -> channelCode.equals(b.getChannelCode()))
.findFirst();
if (pending.isEmpty()) {
// No pending batch for this channelCode → close was successful
log.info("Batch close confirmed (no pending batch): channelCode={}", channelCode);
return;
}
if (!originalBatchNo.equals(pending.get().getBatchNo())) {
// Pending batchNo has changed → original batch was closed, current is a new batch
log.info("Batch close confirmed (batchNo changed): channelCode={}, old={}, new={}",
channelCode, originalBatchNo, pending.get().getBatchNo());
return;
}
// Same batchNo still pending → close did not take effect, retry
log.warn("Batch close not confirmed, retrying: channelCode={}, batchNo={}", channelCode, originalBatchNo);
// Retry batchClose ...
}Last updated on