Skip to main content

Implement capture-separated payment

In offline payment, you can separate payment confirmation and capture. You can separate payment confirmation and capture to account for the possibility that you may need to delay the settlement of the payment or that the amount of the payment may change.

In Taiwan, automatic capture is the basic payment method, and you cannot process payment with capture separated without a prior request. To use capture-separated payments in Taiwan, contact the representative of LINE Pay.

In offline payment, the flow for separating payment confirmation and capture is as follows.

If you're separating capture, you must implement the following in the merchant server.

Request capture separation

To separate payment confirmation and capture, set the value of the field (capture) that determines whether to automatically capture when you request payment to false. Below is an example of calling the payment request API that separates confirmation and capture.

try {
let response = await requestOfflineAPI({
method: "POST",
baseUrl: targetAPIServer,
apiPath: "/v2/payments/oneTimeKeys/pay",
data: {
amount: 100,
currency: "TWD",
orderId: "EXAMPLE_ORDER_20230422_1000001",
// ...
capture: false,
},
});

console.log("Response: ", response);
} catch (error) {
console.log(error);
}

If you request a payment as above, the process will be completed to the payment confirmation stage, at which point you can either capture the payment or void the payment.

Retrieve confirmation details

To capture or void a payment with payment confirmation and the capture separated, you need to know if the payment is confirmed. Call the retrieve confirmation information API to determine the confirmation status of a specific payment. Retrieve confirmation information using the order ID or transaction ID as follows:

const getConfirmedPaymenrtInfo = async function ({
orderId = "",
transactionId = "",
}) {
let queryString = "";

if (orderId === "" && transactionId === "") {
throw new Error(
"At least one of order ID or transaction ID must be input."
);
} else if (orderId !== "") {
queryString = `orderId=${orderId}`;
} else {
queryString = `transactionId=${transactionId}`;
}

let response = await requestOfflineAPI({
method: "GET",
baseUrl: targetAPIServer,
apiPath: `/v2/payments/authorizations?${queryString}`,
});

return response;
};

// ...

try {
response = await getConfirmedPaymenrtInfo({ orderId: "test_order_1" });

console.log(response);
} catch (error) {
console.error(error);
}

You must enter either order ID or transaction ID in the query parameters.

Depending on the service implementation language, you may need to process the transaction ID as a string when handling transaction ID information. For more information, see the Transaction ID.

You will receive the following response as a result of retrieving the confirmation information.

{
"returnCode": "0000",
"returnMessage": "success",
"info": [
{
"transactionId": 2019049910005498410,
"orderId": "20190408003",
"payStatus": "VOIDED_AUTHORIZATION",
"transactionDate": "2019-04-08T07:02:38Z",
"transactionType": "PAYMENT",
"productName": "test product",
"currency": "THB",
"authorizationExpireDate": "2019-04-13T07:02:38Z",
"payInfo": [
{
"method": "BALANCE",
"amount": 100
}
]
}
]
}

You can determine the payment status from the payment status information (info.payStatus) in the response. You can capture or void the confirmed payment. The following values are returned as payment status information.

  • "AUTHORIZATION": Payment confirmed
  • "EXPIRED_AUTHORIZATION": Payment confirmation expired (capture not processed within the allowed time)
  • "VOIDED_AUTHORIZATION": Payment confirmation voided

Some of the confirmed payments may already have been captured. In this case, you cannot cancel the capture or confirmation. You can only refund the payment.

Capture

If the transaction with the customer is completed and the settlement amount is determined, call the capture request API. You must request the capture for the payment confirmed with the order ID entered during payment request. The following is an example of requesting a capture.

try {
// Payment request
let requestResponse = await requestOfflineAPI({
method: "POST",
baseUrl: targetAPIServer,
apiPath: "/v2/payments/oneTimeKeys/pay",
data: {
amount: 100,
currency: "TWD",
// ...
capture: false,
},
});

console.log("Request response: ", requestResponse);

// ...

// Capture request
let captureResponse = await requestOfflineAPI({
method: "POST",
baseUrl: targetAPIServer,
apiPath: `/v2/payments/orders/${requestResponse.info.orderId}/capture`,
data: {
amount: 100,
currency: "TWD",
},
});

console.log("Capture response: ", captureResponse);
} catch (error) {
console.log(error);
}

If you request payment confirmation with capture separated, the LINE Pay server includes the payment confirmation expiration date and time information (info.authorizationExpireDate) in the response. If the payment isn't captured before the payment confirmation expiration date and time, the confirmed payment is automatically voided. You can also manually void the payment.

Once the capture is completed, you will receive the following response.

{
"returnCode": "0000",
"returnMessage": "success",
"info": {
"transactionId": 2019010112345678910,
"orderId": "test_order_1",
"transactionDate": "2019-01-01T01:01:00Z",
"payInfo": [
{
"method": "BALANCE",
"amount": 100
}
]
}
}

You cannot capture an amount greater than the payment amount that was originally requested. However, you can capture an amount equal to or less than the payment amount. Partial capture is processed if you capture an amount less than the payment amount, and the remaining amount that wasn't captured is partially canceled. Once the capture is complete, you cannot void the payment. You can only process the refund.

Void

If you're processing payment with capture separated, you can void the payment without capturing after payment confirmation. The process for voiding a payment is as follows.

Just as with a capture, call the void API using the order ID entered when calling the payment request API. The following is an example of voiding a payment.

try {
// Void request
let voidResponse = await requestOfflineAPI({
method: "POST",
baseUrl: targetAPIServer,
apiPath: `/v2/payments/orders/${requestResponseBody.info.orderId}/void`,
});

console.log("Response: ", voidResponse);
} catch (error) {
console.log(error);
}

If the payment is voided, you will receive the following response.

{
"returnCode": "0000",
"returnMessage": "OK"
}