Direct integration

In this approach no platform web application is involved and all steps of the incoming payment process must be integrated by the merchant application.

The first step of the process is to generate auth token to be able to pass all authorization checks for each necessary operation.

Note

NEW

The easiest way to verify your merchant account is to use our Integration DEMO Web Application to make necessary API calls and check our Payment Web Application flow.

Payment options

In the second step, the customer must be challenged to select the appropriate payment option for the required transaction. Use the POST /payins/!availablePaymentOptions endpoint to list all available payment options.

This step is optional in cases where the merchant product configuration is not dynamic and the merchant is capable of taking the responsibility for using the correct payment method / payment operator selection.

Example CURL for requesting available payment options
curl -X POST 'https://api.sandbox.aopay.io/payins/!availablePaymentOptions' \
     -H 'Accept: application/json' \
     -H 'Content-Type: application/json' \
     -H 'X-API-Version: 2' \
     -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcGVyYXRpb25zIjpbIlBPU1QgL3BheWlucy8hYXZhaWxhYmxlUGF5bWVudE1ldGhvZHMiLCJQT1NUIC9wYXlpbnMvVFNULTExMjIzMyIsIkdFVCAvcGF5aW5zL1RTVC0xMTIyMzMiXSwiZXhwIjoxNjIyNjIzNjY5LCJqdGkiOiI5ZThhNDUwNC04MmRmLTQyY2QtOTQ3Ni03NjE2YjEzOTJlM2IiLCJpYXQiOjE2MjI2MjMwNjksInN1YiI6IllPVVJfTUVSQ0hBTlRfQ09ERSJ9.LkYT9qXY3hEixjoiUBKqxXnazWgfLCNg37RtdG_oXw0' \
     -d '{
           "money": {
             "amount": 100,
             "currencyCode": "IDR"
           }
         }'
Response of the example call
{
  "data": [
    {
      "paymentMethodCode": "VAPAY",
      "paymentOperators": [
        {
          "code": "BNK_000",
          "name": "Some real bank name"
        },
        {
          "code": "BNK_001",
          "name": "Some other real bank name"
        }
      ]
    }
  ]
}

Merchant information

In the this step, the merchant can obtain its merchant information such as merchant channel name configured in our platform to display it on the payment flow UI.

This step is optional as usually merchant displays such information from theirs own configuration when using the direct API integration.

Use the GET /merchant-info endpoint to obtain the merchant information.

Example CURL for requesting a merchant channel information
curl -X POST 'https://api.sandbox.aopay.io/merchant-info' \
     -H 'Accept: application/json' \
     -H 'Content-Type: application/json' \
     -H 'X-API-Version: 2' \
     -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcGVyYXRpb25zIjpbIlBPU1QgL3BheWlucy8hYXZhaWxhYmxlUGF5bWVudE1ldGhvZHMiLCJQT1NUIC9wYXlpbnMvVFNULTExMjIzMyIsIkdFVCAvcGF5aW5zL1RTVC0xMTIyMzMiXSwiZXhwIjoxNjIyNjIzNjY5LCJqdGkiOiI5ZThhNDUwNC04MmRmLTQyY2QtOTQ3Ni03NjE2YjEzOTJlM2IiLCJpYXQiOjE2MjI2MjMwNjksInN1YiI6IllPVVJfTUVSQ0hBTlRfQ09ERSJ9.LkYT9qXY3hEixjoiUBKqxXnazWgfLCNg37RtdG_oXw0' \
Response of the example call
{
  "channelInfo": {
    "name": "YOUR_MERCHANT_CHANNEL_NAME"
  }
}

Sensitive data encryption

Some payment methods require specific fields within the payment method request object to be encrypted - for more information see Payment methods

When submitting a payment method which requires encrypted values in payment method’s object, follow these steps:

  1. Obtain the Public Key: Send a request to GET /sensitive-data-encryption-key endpoint using your valid token.

  2. Prepare the Plaintext value: Concatenate your idPayment and the sensitive string separated by triple colons (:::): <idPayment>:::<sensitiveString>.

  3. Encrypt: Encrypt the combined string using the public key obtained in keyData.

  4. Format the Field Value: Prepend the keyId followed by triple colons (:::) to the resulting encrypted ciphertext string: <keyId>:::<encryptedString>.

  5. Send Payment Request: Pass this final <keyId>:::<encryptedString> value into the corresponding field of the payment method request object.

Example CURL for requesting the sensitive data encryption key
curl -X GET 'https://api.sandbox.aopay.io/sensitive-data-encryption-key' \
     -H 'Accept: application/json' \
     -H 'X-API-Version: 2' \
     -H 'Authorization: Bearer <YOUR_JWT_TOKEN>' \
Response of the example call
{
  "keyId": "key123",
  "key": "<Base64 encoded public key>",
  "keyType": "<KEY_TYPE>",
  "encryptionAlgorithm": "<ENCRYPTION_ALGORITHM>"
}

Key Rotation and Error Handling

The encryption key is rotated periodically. To optimize performance, merchants may cache the key and its keyId rather than fetching it before every transaction.

If a payment request POST /payins/{idPayin} (or payment query GET /payins/{idPayin}) return the error DECRYPTION_FAILED, it indicates that the encrypted data could not be decrypted. In this event, your application must call GET /sensitive-data-encryption-key to fetch the new key and use this new key for encryption of sensitive payment data in subsequent payment requests.

Payment request

The forth step involves creating the payment request itself via POST /payins/{idPayin} endpoint.

Example CURL for requesting payment
curl -X POST 'https://api.sandbox.aopay.io/payins/TST-112233' \
     -H 'Accept: application/json' \
     -H 'Content-Type: application/json' \
     -H 'X-API-Version: 2' \
     -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcGVyYXRpb25zIjpbIlBPU1QgL3BheWlucy8hYXZhaWxhYmxlUGF5bWVudE1ldGhvZHMiLCJQT1NUIC9wYXlpbnMvVFNULTExMjIzMyIsIkdFVCAvcGF5aW5zL1RTVC0xMTIyMzMiXSwiZXhwIjoxNjIyNjIzNjY5LCJqdGkiOiI5ZThhNDUwNC04MmRmLTQyY2QtOTQ3Ni03NjE2YjEzOTJlM2IiLCJpYXQiOjE2MjI2MjMwNjksInN1YiI6IllPVVJfTUVSQ0hBTlRfQ09ERSJ9.LkYT9qXY3hEixjoiUBKqxXnazWgfLCNg37RtdG_oXw0' \
     -d '{
           "paymentRequested": {
             "money": {
               "amount": 100,
               "currencyCode": "IDR"
             }
           },
           "paymentMethod": {
             "account": {
               "accountName": "Test account",
               "accountNumber": "11223344"
             },
             "paymentMethodCode": "VAPAY",
             "paymentOperatorCode": "BNK_000",
             "emailAddress": "customer@test.com"
           },
           "callbackUrl": "https://example.com/order-status-change",
           "returnUrl": "https://example.com?id=123"
         }'
Response of the example call
{
  "paymentRequested": {
    "money": {
      "amount": 100,
      "currencyCode": "IDR"
    }
  },
  "paymentMethodResponse": {
    "idPayin": "TST-112233",
    "paymentMethodCode": "VAPAY",
    "account": {
      "accountName": "Test account",
      "accountNumber": "11223344",
      "bankCode": "BNK_000",
      "bankName": "Some real bank name"
    },
    "money": {
      "amount": 100,
      "currencyCode": "IDR"
    },
    "expireAt": "2021-05-20T08:37:05.350Z",
    "reference": "VA1122334455",
    "returnUrl": "https://example.com?id=123"
  }
}

Get Payment status

The merchant is automatically notified of a payment status change via callback. This can be obtained anytime via our API.

Get payment customer account data

This can be obtained anytime via our API. Customer account data from request should be available shortly after payment creation. Customer account data from payment process should be available shortly after payment is successfully finished.