Deferred Authorizations


Deferred authorization is a function which allows a merchant to simulate an approval offline, without processing by our gateway platform or acquirer. This function can provide merchants with a means of continuing to transact in an offline environment by relying solely on the local exchange between the card and the payment acceptance device (e.g. the ID Tech VP3350, Ingenico Lane, or Miura M020).

Deferred authorization can provide a useful means of payment processing in an offline environment, for example in a ‘no comms’ scenario where it is still desirable for a customer purchase to go ahead, albeit with some risk to the merchant.

This function should be used with great caution as the merchant has no guarantee that the transaction will approve when it is sent online for processing. When the authorization is sent online to the acquirer, a subsequent declined transaction is completely and totally at the merchant's own risk. The gateway, processor, acquirer, or card scheme will accept no liability for these declines.

Essentially, a deferred authorization is an act of good faith that approval will occur when later processed, and so all deferred authorizations carry the risk of issuing goods and/or services without payment. As deferred authorization always presents an approval as long as local validation is passed there is inherent risk involved - the payment device will validate an EMV card is a ‘real’ card to the best of its ability, for example, however it will not determine whether funds are available on the account, or whether the card has been stolen.

It is extremely important that implementation of this functionality carries with it the logic to decide when and how deferred authorization is allowed, as appropriate to the merchant's specific circumstances. It is recommended that an integrator carefully consider how and when to allow a deferred authorization, as this transaction flow carries risks for the merchant. Consider adding transaction amount caps, supervisor PIN, and total number of offline transaction limits to mitigate any serious risk of declined transactions.


Deferred authorizations operate similar to a standard transaction, up until the transaction response. If the host device is offline, the integrator has the option to introduce deferred authorizations as a means of mimicking acceptance, to then submit the authorization for processing when comms is reestablished.

Once you have Deferred Authorizations enabled, if a standalone sale transaction attempts to go online but fails, the Deferred Authorization callback will be invoked, at which point the merchant can choose to accept a Deferred Authorization.

Once a Deferred Authorization is confirmed (and only when), the transaction will be added to the pending offline queue which will attempt to send the transaction to our platform once internet connectivity is reestablished for a period of 24 hours. If the transaction does not get sent to our platform or gain an approval response within the 24-hour period, it will be moved from the pending queue to the failed queue.

Transactions that get sent to our Platform and get declined will be placed back in the pending queue to be retried at 8-hour intervals until the 24-hour period is reached or approved.



The Payment Device SDK uses a Parameter object, with parameter key and value sets passed into functions to proceed with transactions for Android and iOS respectively.

Deferred Authorization Callback

The NMI Payment Device SDK fires a deferredAuthorization event, during a transaction, when it determines that a deferred authorization is possible, and verification from the merchant or integration is required. Call continueDeferredAuthorization() to set the result and continue the transaction.

Methods to add or remove callback delegate in ChipDnaMobile:


void addDeferredAuthorizationTarget:(id)self  
 	action :(SEL)@selector (onDeferredAuthorization:)  
void removeDeferredAuthorizationTarget:(id)self


void addDeferredAuthorizationListener(  
	DeferredAuthorizationListener listener  
void removeDeferredAuthorizationListener(  
	DeferredAuthorizationListener listener  

Continue Deferred Authorization

Parameters continueDeferredAuthorization(Parameters parameters)

Call continueDeferredAuthorization() during a transaction after a onDeferredAuthorization callback has been triggered. The integrating application can specify whether to proceed with the deferred authorization or to reject it.

Deferred Authorization Listener

Please note that you will need to add the Deferred Authorization target/listener, as it is not included by default, this function will also need to be created.


[ChipDnaMobile addDeferredAuthorizationTarget:self action:@selector(deferredAuthorisation:)];
-(void)deferredAuthorisation:(CCParameters *)request{
	 [request setValue:CCValueTrue forKey:CCParamResult];
         // Add Operator PIN if required
	 [request setValue:OPERATOR_PIN forKey:CCParamOperatorPin];
	 CCParameters *response = [[ChipDnaMobile sharedInstance] continueDeferredAuthorization:request];


public void onDeferredAuthorizationListener(Parameters parameters) {
	parameters.add(ParameterKeys.Result, ParameterValues.TRUE);
        // Add Operator PIN if required
	parameters.add(ParameterKeys.OperatorPin, OPERATOR_PIN);
	Parameters response = ChipDnaMobile.getInstance().continueDeferredAuthorization(parameters);

RequestQueue Status

The RequestQueueStatus class is used to access the details of stored pending and failed requests. This includes details such as the number of requests in the offline pending and failed queues, as well as the total amount stored within each queue. This was formerly known as the OfflineProcessingManager class in the old API.

You can also utilize the RequestQueueStatus to process and retry failed transactions, as included in the examples below.

Implementation of the RequestQueueStatus class and the following functionality is mandatory if you wish to process offline transactions (including deferred authorizations). Please note, that it is the responsibility of the integrator to ensure all transactions have reached our platform and are confirmed/committed. The below example is to provide a working code example but does not keep on retrying to submit a failed transaction until approved/declined by our platform. This is something your integration needs to do.


[self log:@"Querying offline queue..."];
// Create a Parameters object and fill it with ChipDnaMobile status
CCParameters *statusParameters = [[ChipDnaMobile sharedInstance] getStatus:nil];
// Deserialize the CCParamRequestQueueStatus key value from the status parameters into a RequestQueueStatus object
RequestQueueStatus *reqQueueStatus = [ChipDnaMobileSerializer deserializeRequestQueueStatus:[statusParameters valueForKey:CCParamRequestQueueStatus]];

// Log useful information regarding the pending and failed queue, as well as type of failed
[self log:[NSString stringWithFormat:@"Pending: %ld", (long)reqQueueStatus.totalNumberOfPendingRequests]];
[self log:[NSString stringWithFormat:@"Failed: %ld", (long)reqQueueStatus.totalNumberOfFailedRequires]];
[self log:[NSString stringWithFormat:@"Pending Req Total: %ld", (long)reqQueueStatus.totalPendingValueStored]];

if (reqQueueStatus.totalNumberOfFailedRequires > 0 ) {
    [self log:@"Retrying failed requests..."];
    // Iterate through our failed offline requests, pulling the userReference
    for (NSString * userReference in [reqQueueStatus failedOfflineRequests]) {
        CCParameters * userReferenceParameters = [[CCParameters alloc] init];
        [userReferenceParameters setValue:userReference forKey:CCParamUserReference];
        // Retry the failed transaction
        CCParameters * response = [[ChipDnaMobile sharedInstance] retryFailedOfflineRequest:userReferenceParameters];
        // Report if transaction retry attempt is successful or not
        if ([[response valueForKey:CCParamTransactionResult] isEqualToString:CCValueApproved]) {
            [self log:[NSString stringWithFormat:@"%@ : Approved", userReference]];
        } else {
            [self log:[NSString stringWithFormat:@"%@ : Declined", userReference]];
        // Report any errors
        if([[response valueForKey:CCParamError] isEqualToString:CCValueFalse]){
            [self log:[NSString stringWithFormat:@"Error: %@", [response valueForKey:CCParamError]]];


log("Querying offline queue...");
// Create a Parameters object and fill it with ChipDnaMobile status
Parameters statusParameters = ChipDnaMobile.getInstance().getStatus(null);

try {
    // Deserialize the RequestQueueStatus key value from the status parameters into a RequestQueueStatus object
    RequestQueueStatus reqQueueStatus = ChipDnaMobileSerializer.deserializeRequestQueueStatus(statusParameters.getValue(ParameterKeys.RequestQueueStatus));

    // Log useful information regarding the pending and failed queue, as well as type of failed
    log("Pending: "+reqQueueStatus.getTotalNumberOfPendingRequests());
    log("Failed: "+reqQueueStatus.getTotalNumberOfFailedRequests());
    log("Pending Req Total: "+reqQueueStatus.getPendingRequestTotalsByRequestType());

    // Iterate through our failed offline requests, pulling the userReference
    if (reqQueueStatus.getTotalNumberOfFailedRequests() > 0) {
        log("Retrying failed requests...");
        // Iterate through our failed offline requests, pulling the userReference
        for (String userReference : reqQueueStatus.getFailedOfflineRequests()) {
            Parameters userReferenceParameters = new Parameters();
            userReferenceParameters.add(ParameterKeys.UserReference, userReference);

            // Retry the failed transaction
            Parameters response = ChipDnaMobile.getInstance().retryFailedOfflineRequest(userReferenceParameters);

            // Report if transaction retry attempt is successful or not
            if (response.containsKey(ParameterKeys.TransactionResult) && response.getValue(ParameterKeys.TransactionResult).equals(ParameterValues.Approved))
                log(userReference+" : Approved");
                log(userReference+" : Declined");

            // Report any errors
            if (response.containsKey(ParameterKeys.Result) && response.getValue(ParameterKeys.Result).equals(ParameterValues.FALSE))
                log("Error: " + response.getValue(ParameterKeys.Error));
} catch (XmlPullParserException|IOException  e) {


Small integration issues can snowball into instances where substantial risk is introduced to the merchant. As a result, regular reconciliation is critical when Deferred Authorizations are utilized to ensure issues are identified and remedied quickly.

When performing reconciliation, the following should be taken into consideration:

  • In the event a Deferred Authorization cannot be sent to the platform the transaction will not be visible on the partner or merchant portal, nor in reports.
  • If a Deferred Authorization has received multiple declines due to repeated attempts to gain approval, you should expect to see multiple requests with the same request data (such as User Reference) in the partner and merchant portals, and reports.