Alipay+ DocsAlipay+ Docs

TransactionPermit

The TransactionPermit SPI controls transaction authorization. It enables you to make final authorization decisions during the transaction process based on transaction details and risk control results.

Method signature

copy
public interface TransactionPermit {
    AppPermitResult isAllowed(boolean authBefore, @Nullable TransactionInfo transactionInfo, @NotNull RiskControlInfo riskControlInfo);
}

Request parameters

Method

Item

Type

Description

isAllowed

authBefore

boolean

Indicates whether the user completed authentication within 30 seconds before the transaction. Use this field to skip re-authentication for recent sessions.

transactionInfo

TransactionInfo

Transaction information. Can be null.

riskControlInfo

RiskControlInfo

Risk control evaluation result.

TransactionInfo

Method

Return type

Description

getAuthorizedAmount()

byte[]

The transaction amount.

getCurrencyCode()

byte[]

The transaction currency code.

getCountryCode()

byte[]

The terminal country code.

getOtherAmount()

byte[]

A second amount, if provided by the terminal.

getRichTransactionType()

RichTransactionType

The transaction type, following ISO 8583.

getTransactionRange()

TransactionRange

The transaction range, following the card scheme specification.

getExpectedUserActionOnPoi()

ExpectedUserActionOnPoi

The action the terminal expects from the user at the point of interaction.

getPurpose()

Purpose

Indicates whether the terminal settles the transaction immediately or defers it.

getConditionsOfUse()

ConditionsOfUse

Indicates whether the transaction is domestic or international.

hasTerminalRequestedCdCvm()

boolean

Returns true if the terminal requested the user to perform a cardholder verification method (CVM).

isAlternateAidUsed()

boolean

Returns true if the transaction ran on a secondary card application (alternate AID).

RichTransactionType

Value

Type

Description

PURCHASE

ENUM

A standard purchase transaction.

CASH

ENUM

A cash withdrawal.

PURCHASE_WITH_CASHBACK

ENUM

A purchase transaction that includes cashback to the user.

REFUND

ENUM

A refund transaction. Treat the amount as a credit rather than a deduction.

TRANSIT

ENUM

A transportation-related transaction.

TransactionRange

Value

Type

Description

LOW_VALUE

ENUM

A low-value transaction.

HIGH_VALUE

ENUM

A high-value transaction.

UNKNOWN

ENUM

The transaction range could not be determined.

ExpectedUserActionOnPoi

The action the terminal expects from the user at the point of interaction. Most actions listed below cannot be performed on a mobile device. This field is provided for informational purposes and does not imply that the MPP app must fulfill these actions.

Value

Type

Description

NONE

ENUM

No action is expected from the user.

ONLINE_PIN

ENUM

The terminal expects a PIN entry.

SIGNATURE

ENUM

The terminal expects a signature.

ONLINE_PIN_OR_SIGNATURE

ENUM

The terminal accepts either a PIN or a signature.

UNKNOWN

ENUM

The expected action could not be determined.

Purpose

Value

Type

Description

AUTHORIZE

ENUM

The terminal settles the transaction immediately.

AUTHENTICATE

ENUM

The terminal records the tap and settles the transaction later.

UNKNOWN

ENUM

The settlement method could not be determined.

ConditionsOfUse

Value

Type

Description

DOMESTIC

ENUM

The transaction occurs in the card's home country.

INTERNATIONAL

ENUM

The transaction occurs outside the card's home country.

Note: The card scheme may decline certain international transactions regardless of the MPP app's authorization decision.

UNKNOWN

ENUM

The terminal did not provide location information.

copy
public interface TransactionInfo {
    byte[] getCurrencyCode();
    
    byte[] getCountryCode();

    byte[] getAuthorizedAmount();

    byte[] getOtherAmount();

    TransactionRange getTransactionRange();

    RichTransactionType getRichTransactionType();

    ExpectedUserActionOnPoi getExpectedUserActionOnPoi();

    Purpose getPurpose();

    ConditionsOfUse getConditionsOfUse();

    boolean hasTerminalRequestedCdCvm();

    boolean isAlternateAidUsed();
}

RiskControlInfo

Method

Item

Type

Description

RiskControlInfo()

riskControlDecision

boolean

Indicates whether the risk control check passed.

isRiskProceed()

N/A

boolean

Returns the value of riskControlDecision.

isRiskCalculated()

N/A

boolean

Indicates whether the risk evaluation has been completed.

getRiskAmountLevel()

N/A

String

The authentication-exempted amount level determined by risk control.

setRiskControlDecision()

riskControlDecision

boolean

Updates the risk control decision.

setRiskCalculated()

riskCalculated

boolean

Updates whether the risk evaluation has been completed.

setRiskAmountLevel()

riskAmountLevel

String

Updates the authentication-exempted amount level.

copy
public RiskControlInfo(boolean riskControlDecision) {
    this.riskControlDecision = riskControlDecision;
}

private boolean riskControlDecision;

public boolean isRiskProceed() {
    return riskControlDecision;
}

public void setRiskControlDecision(boolean riskControlDecision) {
    this.riskControlDecision = riskControlDecision;
}

private boolean isRiskCalculated = false;

public boolean isRiskCalculated() {
    return isRiskCalculated;
}

public void setRiskCalculated(boolean riskCalculated) {
    isRiskCalculated = riskCalculated;
}

private String riskAmountLevel = "";

public String getRiskAmountLevel() {
    return riskAmountLevel;
}

public void setRiskAmountLevel(String riskAmountLevel) {
    this.riskAmountLevel = riskAmountLevel;
}

Response parameters

Item

Type

Description

Required

result

AppPermitResult

The authorization decision for the transaction.

Yes

AppPermitResult

Value

Type

Description

PROCEED

ENUM

The transaction is authorized.

DECLINE

ENUM

The transaction is declined.

NEED_AUTH

ENUM

User authentication is required before the transaction can proceed.

DECLINE_CUSTOM_1

ENUM

The transaction was declined for MPP-defined reason 1.

DECLINE_CUSTOM_2

ENUM

The transaction was declined for MPP-defined reason 2.

DECLINE_CUSTOM_3

ENUM

The transaction was declined for MPP-defined reason 3.

DECLINE_CUSTOM_4

ENUM

The transaction was declined for MPP-defined reason 4.

DECLINE_CUSTOM_5

ENUM

The transaction was declined for MPP-defined reason 5.

Note: DECLINE_CUSTOM_1 through DECLINE_CUSTOM_5 are values of the AppPermitResult enum. They are distinct from the NFCErrorCode constants APP_CUSTOM_DECLINE_1 through APP_CUSTOM_DECLINE_5, which correspond to error codes 11001 through 11005.

Sample

The following example shows a typical implementation of TransactionPermit. The MPP app returns PROCEED if the risk control check passed, or NEED_AUTH if additional user authentication is required.

copy
public class TransactionAuthInProgress implements TransactionPermit {

    private Context context;

    private SharedPreferencesUtil sharedPreferencesUtil;
    public static final String CURRENCY_CODE = "currencyCode";
    public static final String AUTHORIZED_AMOUNT = "authorizedAmount";
    private static final String IS_3TAB_PAGE = "is_3tab_page";
    private static final String IS_3TAB_PAGE_Switch = "is_3tab_page_switch";

    public TransactionAuthInProgress(Context context) {
        this.context = context;
        sharedPreferencesUtil = new SharedPreferencesUtil(context);
    }

    @Override
    public AppPermitResult isAllowed(boolean authBefore, TransactionInfo transactionInfo, @NonNull RiskControlInfo riskControlInfo) {
        Log.d("PERMIT", "authBefore: " + authBefore + ", riskControlInfo.isRiskProceed(): " + riskControlInfo.isRiskProceed());
        byte[] currencyCode = transactionInfo.getCurrencyCode();
        byte[] authorizedAmount = transactionInfo.getAuthorizedAmount();
        Log.d("20241113", "currencyCode: " + currencyCode + ", authorizedAmount: " + authorizedAmount);
        boolean is3tabSwitch = sharedPreferencesUtil.getBool(IS_3TAB_PAGE_Switch);
        boolean is3TabPage = sharedPreferencesUtil.getBool(IS_3TAB_PAGE);
        Log.d("20241231", "currencyIs3TabPage: " + is3TabPage );

        if (currencyCode != null) {
            String currencyCodeString = HCEApduCommandMock.t(currencyCode);
            sharedPreferencesUtil.saveString(CURRENCY_CODE, currencyCodeString);
        }
        if (authorizedAmount != null) {
            String authorizedAmountString = HCEApduCommandMock.t(authorizedAmount);
            sharedPreferencesUtil.saveString(AUTHORIZED_AMOUNT, authorizedAmountString);
        }

        if (!is3tabSwitch || transactionInfo.getRichTransactionType() == RichTransactionType.TRANSIT) {
            return (riskControlInfo.isRiskProceed())? AppPermitResult.PROCEED :AppPermitResult.NEED_AUTH;
        } else {
            if (is3TabPage) {
                return AppPermitResult.PROCEED;
            } else {
                return AppPermitResult.DECLINE;
            }
        }
    }
}