PHPackages                             doku/doku-php-library - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. doku/doku-php-library

ActiveLibrary

doku/doku-php-library
=====================

Library to handle API SNAP

1.0.17(10mo ago)55.3k↓42.8%3[1 PRs](https://github.com/PTNUSASATUINTIARTHA-DOKU/doku-php-library/pulls)MITPHPPHP &gt;=8.1

Since Sep 24Pushed 10mo ago1 watchersCompare

[ Source](https://github.com/PTNUSASATUINTIARTHA-DOKU/doku-php-library)[ Packagist](https://packagist.org/packages/doku/doku-php-library)[ RSS](/packages/doku-doku-php-library/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (1)Dependencies (3)Versions (22)Used By (0)

DOKU PHP SDK Documentation
==========================

[](#doku-php-sdk-documentation)

Introduction
------------

[](#introduction)

Welcome to the DOKU PHP SDK! This SDK simplifies access to the DOKU API for your server-side PHP applications, enabling seamless integration with payment and virtual account services.

If your looking for another language [Node.js](https://github.com/PTNUSASATUINTIARTHA-DOKU/doku-nodejs-library), [Go](https://github.com/PTNUSASATUINTIARTHA-DOKU/doku-golang-library), [Python](https://github.com/PTNUSASATUINTIARTHA-DOKU/doku-python-library), [Java](https://github.com/PTNUSASATUINTIARTHA-DOKU/doku-java-library)

Table of Contents
-----------------

[](#table-of-contents)

- [DOKU PHP SDK Documentation](#doku-php-sdk-documentation)
    - [1. Getting Started](#1-getting-started)
    - [2. Usage](#2-usage)
        - [Virtual Account](#virtual-account)
            - [I. Virtual Account (DGPC &amp; MGPC)](#i-virtual-account-dgpc--mgpc)
            - [II. Virtual Account (DIPC)](#ii-virtual-account-dipc)
            - [III. Check Virtual Account Status](#iii-check-virtual-account-status)
        - [B. Binding / Registration Operations](#b-binding--registration-operations)
            - [I. Account Binding](#i-account-binding)
            - [II. Card Registration](#ii-card-registration)
        - [C. Direct Debit and E-Wallet](#c-direct-debit-and-e-wallet)
            - [I. Request Payment](#i-request-payment)
            - [II. Request Payment Jump APP ](#ii-request-payment-jump-app)
    - [3. Other Operation](#3-other-operation)
        - [Check Transaction Status](#a-check-transaction-status)
        - [Refund](#b-refund)
        - [Balance Inquiry](#c-balance-inquiry)
    - [4. Error Handling and Troubleshooting](#4-error-handling-and-troubleshooting)

1. Getting Started
------------------

[](#1-getting-started)

### Requirements

[](#requirements)

- PHP version 7.4 or higher
- Composer installed

### Installation

[](#installation)

To install the Doku Snap SDK, use Composer:

```
composer require doku/doku-php-library
```

### Configuration

[](#configuration)

Before using the Doku Snap SDK, you need to initialize it with your credentials:

1. **Client ID**, **Secret Key** and **DOKU Public Key**: Retrieve these from the Integration menu in your Doku Dashboard
2. **Private Key** and **Public Key** : Generate your Private Key and Public Key

How to generate Merchant privateKey and publicKey :

1. generate private key RSA : openssl genrsa -out private.key 2048
2. set passphrase your private key RSA : openssl pkcs8 -topk8 -inform PEM -outform PEM -in private.key -out pkcs8.key -v1 PBE-SHA1-3DES
3. generate public key RSA : openssl rsa -in private.key -outform PEM -pubout -out public.pem

The encryption model applied to messages involves both asymmetric and symmetric encryption, utilizing a combination of Private Key and Public Key, adhering to the following standards:

1. Standard Asymmetric Encryption Signature: SHA256withRSA dengan Private Key ( Kpriv ) dan Public Key ( Kpub ) (256 bits)
2. Standard Symmetric Encryption Signature HMAC\_SHA512 (512 bits)
3. Standard Symmetric Encryption AES-256 dengan client secret sebagai encryption key.

**Parameter****Description****Required**`privateKey`The private key for the partner service.✅`publicKey`The public key for the partner service.✅`dokuPublicKey`Key that merchants use to verify DOKU request✅`clientId`The client ID associated with the service.✅`secretKey`The secret key for the partner service.✅`isProduction`Set to true for production environment✅`issuer`Optional issuer for advanced configurations.❌`authCode`Optional authorization code for advanced use.❌```
use Doku\Snap\Snap;

$privateKey = "YOUR_PRIVATE_KEY";
$publicKey = "YOUR_PUBLIC_KEY";
$clientId = "YOUR_CLIENT_ID";
$secretKey = "YOUR_SECRET_KEY";
$isProduction = false;
$issuer = "YOUR_ISSUER";
$authCode = "YOUR_AUTH_CODE";
$dokuPublicKey = "DOKU_PUBLIC_KEY";

$snap = new Snap($privateKey, $publicKey, $dokuPublicKey, $clientId, $issuer, $isProduction, $secretKey, $authCode);
```

2. Usage
--------

[](#2-usage)

**Initialization**Always start by initializing the Snap object.

```
$snap = new Snap($privateKey, $publicKey, $dokuPublicKey, $clientId, $issuer, $isProduction, $secretKey, $authCode);
```

### Virtual Account

[](#virtual-account)

#### I. Virtual Account (DGPC &amp; MGPC)

[](#i-virtual-account-dgpc--mgpc)

##### DGPC

[](#dgpc)

- **Description:** A pre-generated virtual account provided by DOKU.
- **Use Case:** Recommended for one-time transactions.

##### MGPC

[](#mgpc)

- **Description:** Merchant generated virtual account.
- **Use Case:** Recommended for top up business model.

Parameters for **createVA** and **updateVA**

   **Parameter** **Description** **Data Type** **Required**     `partnerServiceId` The unique identifier for the partner service. String(20) ✅   `customerNo` The customer's identification number. String(20) ✅   `virtualAccountNo` The virtual account number associated with the customer. String(20) ✅   `virtualAccountName` The name of the virtual account associated with the customer. String(255) ✅   `virtualAccountEmail` The email address associated with the virtual account. String(255) ❌   `virtualAccountPhone` The phone number associated with the virtual account. String(9-30) ❌   `trxId` Invoice number in Merchants system. String(64) ✅   `totalAmount` `value`: Transaction Amount (ISO 4217)
 Example: "11500.00" String(16.2) ✅   `Currency`: Currency
 Example: "IDR" String(3) ✅   `additionalInfo` `channel`: Channel that will be applied for this VA
 Example: VIRTUAL\_ACCOUNT\_BANK\_CIMB String(20) ✅   `virtualAccountConfig` `reusableStatus`: Reusable Status For Virtual Account Transaction
value TRUE or FALSE Boolean ❌   `minAmount`: Minimum Amount can be used only if `virtualAccountTrxType` is Open Amount (O).
Example: "10000.00" String(16.2) ❌   `maxAmount`: Maximum Amount can be used only if `virtualAccountTrxType` is Open Amount (O).
Example: "5000000.00" String(16.2) ❌   `virtualAccountTrxType` Transaction type for this transaction. C (Closed Amount), O (Open Amount) String(1) ✅   `expiredDate` Expiration date for Virtual Account. ISO-8601
Example: "2023-01-01T10:55:00+07:00" String ❌   `freeText` `English`: Free text for additional description.
 Example: "Free text" String(64) ❌   `Indonesia`: Free text for additional description.
 Example: "Tulisan Bebas" String(64) ❌  1. **Create Virtual Account**

    - **Function:** `createVa`

    ```
      use Doku\Snap\Models\VA\Request\CreateVaRequestDto;
      use Doku\Snap\Models\TotalAmount\TotalAmount;
      use Doku\Snap\Models\VA\AdditionalInfo\CreateVaRequestAdditionalInfo;
      use Doku\Snap\Models\VA\VirtualAccountConfig\CreateVaVirtualAccountConfig;

      $createVaRequestDto = new CreateVaRequestDto(
        "8129014",  // partner
        "17223992157",  // customerno
        "812901417223992157",  // virtualAccountNo
        "T_" . time(),  // virtualAccountName
        "test.example." . time() . "@test.com",  // virtualAccountEmail
        "621722399214895",  // virtualAccountPhone
        "INV_CIMB_" . time(),  // trxId
        new TotalAmount("12500.00", "IDR"),  // totalAmount
        new CreateVaRequestAdditionalInfo(
              "VIRTUAL_ACCOUNT_BANK_CIMB", new CreateVaVirtualAccountConfig(true)
              ), // additionalInfo
        'C',  // virtualAccountTrxType
        "2024-08-31T09:54:04+07:00"  // expiredDate
      );

      $result = $snap->createVa($createVaRequestDto);
      echo json_encode($result, JSON_PRETTY_PRINT);
    ```
2. **Update Virtual Account**

    - **Function:** `updateVa`

    ```
      use Doku\Snap\Models\VA\Request\UpdateVaRequestDto;
      use Doku\Snap\Models\VA\AdditionalInfo\UpdateVaRequestAdditionalInfo;
      use Doku\Snap\Models\VA\VirtualAccountConfig\UpdateVaVirtualAccountConfig;

      $updateVaRequestDto = new UpdateVaRequestDto(
          "8129014",  // partnerServiceId
          "17223992155",  // customerNo
          "812901417223992155",  // virtualAccountNo
          "T_" . time(),  // virtualAccountName
          "test.example." . time() . "@test.com",  // virtualAccountEmail
          "00000062798",  // virtualAccountPhone
          "INV_CIMB_" . time(),  // trxId
          new TotalAmount("14000.00", "IDR"),  // totalAmount
          new UpdateVaRequestAdditionalInfo("VIRTUAL_ACCOUNT_BANK_CIMB", new UpdateVaVirtualAccountConfig("ACTIVE", "10000.00", "15000.00")),  // additionalInfo
          "O",  // virtualAccountTrxType
          "2024-08-02T15:54:04+07:00"  // expiredDate
      );

      $result = $snap->updateVa($updateVaRequestDto);
      echo json_encode($result, JSON_PRETTY_PRINT);
    ```
3. **Delete Virtual Account**

    **Parameter****Description****Data Type****Required**`partnerServiceId`The unique identifier for the partner service.String(8)✅`customerNo`The customer's identification number.String(20)✅`virtualAccountNo`The virtual account number associated with the customer.String(20)✅`trxId`Invoice number in Merchant's system.String(64)✅`additionalInfo``channel`: Channel applied for this VA.
    Example: VIRTUAL\_ACCOUNT\_BANK\_CIMBString(30)✅

- **Function:** `deletePaymentCode`

    ```
    use Doku\Snap\Models\VA\Request\DeleteVaRequestDto;
    use Doku\Snap\Models\VA\Request\DeleteVaRequestDto;
    use Doku\Snap\Models\VA\AdditionalInfo\DeleteVaRequestAdditionalInfo;

    $deleteVaRequestDto = new DeleteVaRequestDto(
        "8129014",  // partnerServiceId
        "17223992155",  // customerNo
        "812901417223992155",  // virtualAccountNo
        "INV_CIMB_" . time(),  // trxId
        new DeleteVaRequestAdditionalInfo("VIRTUAL_ACCOUNT_BANK_CIMB")  // additionalInfo
    );

    $result = $snap->deletePaymentCode($deleteVaRequestDto);
    echo json_encode($result, JSON_PRETTY_PRINT);
    ```

#### II. Virtual Account (DIPC)

[](#ii-virtual-account-dipc)

- **Description:** The VA number is registered on merchant side and DOKU will forward Acquirer inquiry request to merchant side when the customer make payment at the acquirer channel
- **Function:** `directInquiryVa`

    ```
        use Doku\Snap\Models\DirectInquiry\InquiryResponseBodyDto;
        use Doku\Snap\Models\DirectInquiry\InquiryResponseVirtualAccountDataDto;
        use Doku\Snap\Models\DirectInquiry\InquiryReasonDto;
        use Doku\Snap\Models\DirectInquiry\InquiryResponseAdditionalInfoDto;
        use Doku\Snap\Models\VA\VirtualAccountConfig\CreateVaVirtualAccountConfig;
        use Doku\Snap\Models\TotalAmount\TotalAmount;

        directInquiry(){
          $requestBody = $this->request->getJSON(true);
          $authorization = $this->request->getHeaderLine('Authorization');
          $isValid = $this->snap->validateTokenB2B($authorization);

          if($isValid) {
            $responseCode =2002400;
            $responseMessage = 'Successful';
            $inquiryRequestId = $requestBody['inquiryRequestId'];

            $partnerServiceId = $requestBody['partnerServiceId'];
            $customerNo = $requestBody['customerNo'];
            $virtualAccountNo = $requestBody['virtualAccountNo'];

            $virtualAccountName = "Nama ". time();
            $trxId =  "INV_MERCHANT_" . time();
            $virtualAccountEmail = "email." . time() . "@gmail.com";
            $virtualAccountPhone =time();
            $totalAmount = new TotalAmount(
              "25000.00",
              "IDR"
            );
            $inquiryStatus = "00";
            $additionalInfo = new InquiryResponseAdditionalInfoDto(
                $requestBody['additionalInfo']['channel'],
                $trxId,
                new CreateVaVirtualAccountConfig(
                    true,
                    "100000.00",
                    "10000.00"
                )
            );
            $inquiryReason = new InquiryReasonDto(
                "Success",
                "Sukses"
            );
            $virtualAccountTrxType = "C";
            $freeText = [
                [
                    "english" => "Free text",
                    "indonesia" => "Tulisan Bebas"
                ]
            ];
            $vaData = new InquiryResponseVirtualAccountDataDto(
                $partnerServiceId,
                $customerNo,
                $virtualAccountNo,
                $virtualAccountName,
                $virtualAccountEmail,
                $virtualAccountPhone,
                $totalAmount,
                $virtualAccountTrxType,
                $additionalInfo,
                $inquiryStatus,
                $inquiryReason,
                $inquiryRequestId,
                $freeText

            );
            $body = new InquiryResponseBodyDto(
                    $responseCode,
                    $responseMessage,
                    $vaData
            );
            return $this->respond($body);
        }
        }
    ```

#### III. Check Virtual Account Status

[](#iii-check-virtual-account-status)

**Parameter****Description****Data Type****Required**`partnerServiceId`The unique identifier for the partner service.String(8)✅`customerNo`The customer's identification number.String(20)✅`virtualAccountNo`The virtual account number associated with the customer.String(20)✅`inquiryRequestId`The customer's identification number.String(128)❌`paymentRequestId`The virtual account number associated with the customer.String(128)❌`additionalInfo`The virtual account number associated with the customer.String❌- **Function:** `checkStatusVa````
    use Doku\Snap\Models\VA\Request\CheckStatusVaRequestDto;

    $checkStatusVaRequestDto = new CheckStatusVaRequestDto(
        "8129014",  // partnerServiceId
        "17223992155",  // customerNo
        "812901417223992155",  // virtualAccountNo
        null,
        null,
        null
    );

    $result = $snap-> ($checkStatusVaRequestDto);
    echo json_encode($result, JSON_PRETTY_PRINT);
    ```

### B. Binding / Registration Operations

[](#b-binding--registration-operations)

The card registration/account binding process must be completed before payment can be processed. The merchant will send the card registration request from the customer to DOKU.

Each card/account can only registered/bind to one customer on one merchant. Customer needs to verify OTP and input PIN.

**Services****Binding Type****Details**Direct DebitAccount BindingSupports **Allo Bank** and **CIMB**Direct DebitCard RegistrationSupports **BRI**E-WalletAccount BindingSupports **OVO**#### I. Account Binding

[](#i-account-binding)

1. **Binding**

   **Parameter** **Description** **Data Type** **Required**     `phoneNo` Phone Number Customer.
 Format: 628238748728423  String(9-16) ✅   `additionalInfo` `channel`: Payment Channel
 String ✅   `custIdMerchant`: Customer id from merchant String(64) ✅   `customerName`: Customer name from merchant String(70) ❌   `email`: Customer email from merchant  String(64) ❌   `idCard`: Customer id card from merchant String(20) ❌   `country`: Customer country  String ❌   `address`: Customer Address String(255) ❌   `dateOfBirth`  String(YYYYMMDD) ❌   `successRegistrationUrl`: Redirect URL when binding is success  String ✅   `failedRegistrationUrl`: Redirect URL when binding is success fail String ✅   `deviceModel`: Device Model customer  String ✅   `osType`: Format: ios/android  String ✅   `channelId`: Format: app/web  String ✅   - **Function:** `doAccountBinding`

    ```
    use Doku\Snap\Models\AccountBinding\AccountBindingRequestDto;
    use Doku\Snap\Models\AccountBinding\AccountBindingAdditionalInfoRequestDto;

     public function accountBinding()
    {
        $requestData = $this->request->getJSON(true);
        $partnerReferenceNo = $requestData['phoneNo'] ?? null;

        $additionalInfo = new AccountBindingAdditionalInfoRequestDto(
            $requestData['additionalInfo']['channel'],
            $requestData['additionalInfo']['custIdMerchant'],
            $requestData['additionalInfo']['customerName']?? null,
            $requestData['additionalInfo']['email'],
            $requestData['additionalInfo']['idCard'] ?? null,
            $requestData['additionalInfo']['country'] ?? null,
            $requestData['additionalInfo']['address'] ?? null,
            $requestData['additionalInfo']['dateOfBirth'] ?? null,
            $requestData['additionalInfo']['successRegistrationUrl'],
            $requestData['additionalInfo']['failedRegistrationUrl'],
            $requestData['additionalInfo']['deviceModel'] ?? null,
            $requestData['additionalInfo']['osType'] ?? null,
            $requestData['additionalInfo']['channelId'] ?? null
        );
        $requestBody = new AccountBindingRequestDto(
            $partnerReferenceNo,
            $additionalInfo
        );

        $ipAddress = $this->request->getHeaderLine('X-IP-ADDRESS');
        $deviceId = $this->request->getHeaderLine('X-DEVICE-ID');
        $response = $this->snap->doAccountBinding($requestBody, $ipAddress, $deviceId);

        if (is_array($response) || is_object($response)) {
            $responseObject = (array)$response; // Ubah objek ke array jika perlu
        } else {
            throw new \Exception('Unexpected response type');
        }
        $responseCode = $responseObject['responseCode'];
        $statusCode = substr($responseCode, 0, 3);
        $this->response->setStatusCode((int)$statusCode);
        return $this->response->setJSON($responseObject);

    }
    ```

1. **Unbinding**
    - **Function:** `getTokenB2B2C`

    ```
    public function getTokenB2B2C() {
        $requestData = $this->request->getJSON(true);

        $authCode = $requestData['authCode'];
        $tokenData = $this->snap->getTokenB2B2C($authCode);
        return $this->response->setJSON($tokenData);
    }
    ```

    - **Function:** `doAccountUnbinding`

    ```
    use Doku\Snap\Models\AccountUnbinding\AccountUnbindingRequestDto;
    use Doku\Snap\Models\AccountUnbinding\AccountUnbindingAdditionalInfoRequestDto;

     public function accountUnbinding()
    {
        $requestData = $this->request->getJSON(true);
        $tokenId =  $requestData['tokenId'] ?? '';
        $additionalInfo = new AccountUnbindingAdditionalInfoRequestDto(
            $requestData['additionalInfo']['channel']
        );
        $requestBody = new AccountUnbindingRequestDto(
            $tokenId,
            $additionalInfo
        );
        $ipAddress = $this->request->getHeaderLine('X-IP-ADDRESS');

        $response = $this->snap->doAccountUnbinding($requestBody, $ipAddress);

        if (is_array($response) || is_object($response)) {
            $responseObject = (array)$response; // Ubah objek ke array jika perlu
        } else {
            throw new \Exception('Unexpected response type');
        }
        $responseCode = $responseObject['responseCode'];
        $statusCode = substr($responseCode, 0, 3);
        $this->response->setStatusCode((int)$statusCode);
        return $this->response->setJSON($responseObject);
    }
    ```

#### II. Card Registration

[](#ii-card-registration)

1. **Registration**

    - **Function:** `doCardRegistration`

    ```
    use Doku\Snap\Models\CardRegistration\CardRegistrationRequestDto;
    use Doku\Snap\Models\CardRegistration\CardRegistrationAdditionalInfoRequestDto;
    use Doku\Snap\Models\CardRegistration\CardRegistrationCardDataRequestDto;

     public function cardRegist()
    {
        $requestData = $this->request->getJSON(true);
        $cardData = new CardRegistrationCardDataRequestDto(
            $requestData['cardData']['bankCardNo'],
            $requestData['cardData']['bankCardType'],
            $requestData['cardData']['expiryDate'],
            $requestData['cardData']['identificationNo'],
            $requestData['cardData']['identificationType'],
            $requestData['cardData']['email'],
        );
        $custIdMerchant = $requestData['custIdMerchant'] ?? null;
        $phoneNo = $requestData['phoneNo'] ?? null;
        $additionalInfo = new CardRegistrationAdditionalInfoRequestDto(
            $requestData['additionalInfo']['channel'],
            $requestData['additionalInfo']['customerName']?? null,
            $requestData['additionalInfo']['email'],
            $requestData['additionalInfo']['idCard'] ?? null,
            $requestData['additionalInfo']['country'] ?? null,
            $requestData['additionalInfo']['address'] ?? null,
            $requestData['additionalInfo']['dateOfBirth'] ?? null,
            $requestData['additionalInfo']['successRegistrationUrl']?? null,
            $requestData['additionalInfo']['failedRegistrationUrl']?? null
        );
        $requestBody = new CardRegistrationRequestDto(
            $cardData,
            $custIdMerchant,
            $phoneNo,
            $additionalInfo
        );
        $response = $this->snap->doCardRegistration($requestBody);

        if (is_array($response) || is_object($response)) {
            $responseObject = (array)$response; // Ubah objek ke array jika perlu
        } else {
            throw new \Exception('Unexpected response type');
        }
        $responseCode = $responseObject['responseCode'];
        $statusCode = substr($responseCode, 0, 3);
        $this->response->setStatusCode((int)$statusCode);
        return $this->response->setJSON($responseObject);

    }
    ```
2. **UnRegistration**

    - **Function:** `getTokenB2B2C`

    ```
    public function getTokenB2B2C() {
        $requestData = $this->request->getJSON(true);

        $authCode = $requestData['authCode'];
        $tokenData = $this->snap->getTokenB2B2C($authCode);
        return $this->response->setJSON($tokenData);
    }
    ```

    - **Function:** `doCardUnbinding`

    ```
      use Doku\Snap\Models\AccountUnbinding\AccountUnbindingRequestDto;
      use Doku\Snap\Models\AccountUnbinding\AccountUnbindingAdditionalInfoRequestDto;

      public function cardUnbinding()
    {
        $requestData = $this->request->getJSON(true);
        $tokenId =  $requestData['tokenId'] ?? '';
        $additionalInfo = new AccountUnbindingAdditionalInfoRequestDto(
            $requestData['additionalInfo']['channel']
        );
        $requestBody = new AccountUnbindingRequestDto(
            $tokenId,
            $additionalInfo
        );
        $ipAddress = $this->request->getHeaderLine('X-IP-ADDRESS');

        $response = $this->snap->doCardUnbinding($requestBody);

        if (is_array($response) || is_object($response)) {
            $responseObject = (array)$response; // Ubah objek ke array jika perlu
        } else {
            throw new \Exception('Unexpected response type');
        }
        $responseCode = $responseObject['responseCode'];
        $statusCode = substr($responseCode, 0, 3);
        $this->response->setStatusCode((int)$statusCode);
        return $this->response->setJSON($responseObject);

    }
    ```

### C. Direct Debit and E-Wallet

[](#c-direct-debit-and-e-wallet)

#### I. Request Payment

[](#i-request-payment)

Once a customer’s account or card is successfully register/bind, the merchant can send a payment request. This section describes how to send a unified request that works for both Direct Debit and E-Wallet channels.

**Acquirer****Channel Name**Allo BankDIRECT\_DEBIT\_ALLO\_SNAPBRIDIRECT\_DEBIT\_BRI\_SNAPCIMBDIRECT\_DEBIT\_CIMB\_SNAPOVOEMONEY\_OVO\_SNAP##### Common parameter

[](#common-parameter)

   **Parameter** **Description** **Data Type** **Required**     `partnerReferenceNo`  Reference No From Partner
 Format: 628238748728423  String(9-16) ✅   `amount` `value`: Transaction Amount (ISO 4217)
 Example: "11500.00" String(16.2) ✅   `Currency`: Currency
 Example: "IDR" String(3) ✅   `additionalInfo`  `channel`: payment channel String ✅   `remarks`:Remarks from Partner String(40) ✅   `successPaymentUrl`: Redirect Url if payment success String ✅   `failedPaymentUrl`: Redirect Url if payment fail  String ✅   ##### Allo Bank Specific Parameters

[](#allo-bank-specific-parameters)

**Parameter****Description****Required**`additionalInfo.remarks`Remarks from the partner✅`additionalInfo.lineItems.name`Item name (String)✅`additionalInfo.lineItems.price`Item price (ISO 4217)✅`additionalInfo.lineItems.quantity`Item quantity (Integer)✅`payOptionDetails.payMethod`Balance type (options: BALANCE/POINT/PAYLATER)✅`payOptionDetails.transAmount.value`Transaction amount✅`payOptionDetails.transAmount.currency`Currency (ISO 4217, e.g., "IDR")✅##### CIMB Specific Parameters

[](#cimb-specific-parameters)

**Parameter****Description****Required**`additionalInfo.remarks`Remarks from the partner✅##### OVO Specific Parameters

[](#ovo-specific-parameters)

**Parameter****Description****Required**`feeType`Fee type from partner (values: OUR, BEN, SHA)❌`payOptionDetails.payMethod`Payment method format: CASH, POINTS✅`payOptionDetails.transAmount.value`Transaction amount (ISO 4217)✅`payOptionDetails.transAmount.currency`Currency (ISO 4217, e.g., "IDR")✅`payOptionDetails.feeAmount.value`Fee amount (if applicable)✅`payOptionDetails.feeAmount.currency`Currency for the fee✅`additionalInfo.paymentType`Transaction type (values: SALE, RECURRING)✅Here’s how you can use the `doPayment` function for both payment types:

- **Function:** `doPayment`

    ```
     use Doku\Snap\Models\TotalAmount\TotalAmount;
     use Doku\Snap\Models\Payment\PaymentRequestDto;
     use Doku\Snap\Models\Payment\PaymentAdditionalInfoRequestDto;

     public function payment(){
        $requestData = $this->request->getJSON(true);
        $payOptionDetails =json_decode(json_encode($requestData['payOptionDetails'] ?? null));
        $partnerReferenceNo = $requestData['partnerReferenceNo'] ?? null;
        $amount = new TotalAmount(
            $requestData['amount']['value'],
            $requestData['amount']['currency']
        );
        $additionalInfo = new PaymentAdditionalInfoRequestDto(
            $requestData['additionalInfo']['channel'],
            $requestData['additionalInfo']['remarks'],
            $requestData['additionalInfo']['successPaymentUrl'],
            $requestData['additionalInfo']['failedPaymentUrl'],
            $requestData['additionalInfo']['lineItems'],
            $requestData['additionalInfo']['paymentType'] ?? null
        );
        $feeType = $requestData['feeType'] ?? '';
        $chargeToken = $requestData['chargeToken'] ?? '';
        $request = new PaymentRequestDto(
            $partnerReferenceNo,
            $amount,
            $payOptionDetails,
            $additionalInfo,
            $feeType,
            $chargeToken
        );
        $ipAddress = $this->request->getHeaderLine('X-IP-ADDRESS');
        $authCode = $requestData['authCode'];

        $response = $this->snap->doPayment($request, $authCode, $ipAddress);
        if (is_array($response) || is_object($response)) {
            $responseObject = (array)$response; // Ubah objek ke array jika perlu
        } else {
            throw new \Exception('Unexpected response type');
        }
        // var_dump($responseObject);
        // Ambil responseCode
        $responseCode = $responseObject['responseCode'];

        // Atur status HTTP berdasarkan tiga angka pertama
        $statusCode = substr($responseCode, 0, 3);
        $this->response->setStatusCode((int)$statusCode); // Set status HTTP
        return $this->response->setJSON($responseObject);

      }
    ```

#### II. Request Payment Jump APP

[](#ii-request-payment-jump-app)

**Acquirer****Channel Name**DANAEMONEY\_DANA\_SNAPShopeePayEMONEY\_SHOPEE\_PAY\_SNAPThe following fields are common across **DANA and ShopeePay** requests:

   **Parameter** **Description** **Data Type** **Required**     `partnerReferenceNo`  Reference No From Partner
 Examplae : INV-0001  String(9-16) ✅   `validUpto` Expired time payment url  String ❌   `pointOfInitiation` Point of initiation from partner,
 value: app/pc/mweb  String ❌    `urlParam` `url`: URL after payment sucess  String ✅   `type`: Pay Return
 always PAY\_RETURN  String ✅   `isDeepLink`: Is Merchant use deep link or not
 Example: "Y/N" String(1) ✅   `amount` `value`: Transaction Amount (ISO 4217)
 Example: "11500.00" String(16.2) ✅   `Currency`: Currency
 Example: "IDR" String(3) ✅   `additionalInfo`  `channel`: payment channel String ✅   ##### DANA

[](#dana)

DANA spesific parameters

   **Parameter** **Description** **Data Type** **Required**     `additionalInfo` `orderTitle`: Order title from merchant String ❌   `supportDeepLinkCheckoutUrl` : Value 'true' for Jumpapp behaviour, 'false' for webview, false by default String ❌    For Shopeepay and Dana you can use the `doPaymentJumpApp` function for for Jumpapp behaviour - **Function:** `doPaymentJumpApp`

```
     use Doku\Snap\Models\TotalAmount\TotalAmount;
     use Doku\Snap\Models\PaymentJumpApp\PaymentJumpAppRequestDto;
      use Doku\Snap\Models\PaymentJumpApp\PaymentJumpAppAdditionalInfoRequestDto;
      use Doku\Snap\Models\PaymentJumpApp\UrlParamDto;

    public function paymentJumpApp()
    {
        $requestData = $this->request->getJSON(true);
        $partnerReferenceNo =  $requestData['partnerReferenceNo'] ?? '';
        $validUpTo =  $requestData['validUpTo'] ?? '';
        $pointOfInitiation =  $requestData['pointOfInitiation'] ?? '';
        $urlParam = array_map(function ($item) {
            return new UrlParamDto(
                $item['url'] ?? null,
                $item['type'] ?? null,
                $item['isDeepLink'] ?? null
            );
        }, $requestData['urlParam'] ?? []);
        $amount = new TotalAmount(
            $requestData['amount']['value'],
            $requestData['amount']['currency']
        );
        $additionalInfo = new PaymentJumpAppAdditionalInfoRequestDto(
            $requestData['additionalInfo']['channel']?? null,
            $requestData['additionalInfo']['orderTitle']?? null,
            $requestData['additionalInfo']['metadata']?? null,
            $requestData['additionalInfo']['supportDeepLinkCheckoutUrl']?? null,
            $requestData['additionalInfo']['origin']?? null,
        );
        $requestBody = new PaymentJumpAppRequestDto(
            $partnerReferenceNo,
            $validUpTo,
            $pointOfInitiation,
            $urlParam,
            $amount,
            $additionalInfo
        );
        $ipAddress = $this->request->getHeaderLine('X-IP-ADDRESS');
        $deviceId = $this->request->getHeaderLine('X-DEVICE-ID');
        $response = $this->snap->doPaymentJumpApp($requestBody,$deviceId,$ipAddress);

        if (is_array($response) || is_object($response)) {
            $responseObject = (array)$response; // Ubah objek ke array jika perlu
        } else {
            throw new \Exception('Unexpected response type');
        }
        $responseCode = $responseObject['responseCode'];
        $statusCode = substr($responseCode, 0, 3);
        $this->response->setStatusCode((int)$statusCode);
        return $this->response->setJSON($responseObject);

    }
```

3. Other Operation
------------------

[](#3-other-operation)

### A. Check Transaction Status

[](#a-check-transaction-status)

```
 public function debitStatus()
  {
      $requestData = $this->request->getJSON(true);
      $originalPartnerReferenceNo =  $requestData['originalPartnerReferenceNo'] ?? '';
      $originalReferenceNo =  $requestData['originalReferenceNo'] ?? '';
      $originalExternalId =  $requestData['originalExternalId'] ?? '';
      $serviceCode =  $requestData['serviceCode'] ?? '';
      $transactionDate =  $requestData['transactionDate'] ?? '';
      $amountValue = $requestData['amount']['value'] ?? '';
      $amountCurrency = $requestData['amount']['currency'] ?? '';
      $amount = new TotalAmount($amountValue, $amountCurrency);

      $merchantId =  $requestData['merchantId'] ?? '';
      $subMerchantId =  $requestData['subMerchantId'] ?? '';
      $externalStoreId =  $requestData['externalStoreId'] ?? '';
      $deviceId = $requestData['additionalInfo']['deviceId'] ?? '';
      $channel = $requestData['additionalInfo']['channel'] ?? '';
      $additionalInfo = new CheckStatusAdditionalInfoRequestDto($deviceId, $channel);
      $requestBody = new DirectDebitCheckStatusRequestDto(
          $originalPartnerReferenceNo,
          $originalReferenceNo,
          $originalExternalId,
          $serviceCode,
          $transactionDate,
          $amount,
          $merchantId,
          $subMerchantId,
          $externalStoreId,
          $additionalInfo
      );

      $response = $this->snap->doCheckStatus($requestBody);

      if (is_array($response) || is_object($response)) {
          $responseObject = (array)$response; // Ubah objek ke array jika perlu
      } else {
          throw new \Exception('Unexpected response type');
      }
      $responseCode = $responseObject['responseCode'];
      $statusCode = substr($responseCode, 0, 3);
      $this->response->setStatusCode((int)$statusCode);
      return $this->response->setJSON($responseObject);

  }
```

### B. Refund

[](#b-refund)

```
public function refund()
  {
      $requestData = $this->request->getJSON(true);
      $additionalInfo = new RefundAdditionalInfoRequestDto(
          $requestData['additionalInfo']['channel']
      );
      $originalPartnerReferenceNo =  $requestData['originalPartnerReferenceNo'] ?? '';
      $originalExternalId =  $requestData['originalExternalId'] ?? '';
      $refundAmount = new TotalAmount(
          $requestData['refundAmount']['value'],
          $requestData['refundAmount']['currency']
      );
      $reason =  $requestData['reason'] ?? '';
      $partnerRefundNo =  $requestData['partnerRefundNo'] ?? '';
      $ipAddress = $this->request->getHeaderLine('X-IP-ADDRESS');
      $authCode = $requestData['authCode'];
      $deviceId = $this->request->getHeaderLine('deviceId');
      $requestBody = new RefundRequestDto(
          $additionalInfo,
          $originalPartnerReferenceNo,
          $originalExternalId,
          $refundAmount,
          $reason,
          $partnerRefundNo
      );
      $response = $this->snap->doRefund($requestBody, $authCode, $ipAddress, $deviceId);

      if (is_array($response) || is_object($response)) {
          $responseObject = (array)$response; // Ubah objek ke array jika perlu
      } else {
          throw new \Exception('Unexpected response type');
      }
      $responseCode = $responseObject['responseCode'];
      $statusCode = substr($responseCode, 0, 3);
      $this->response->setStatusCode((int)$statusCode);
      return $this->response->setJSON($responseObject);

  }
```

### C. Balance Inquiry

[](#c-balance-inquiry)

```
public function checkBalance()
  {
      $requestData = $this->request->getJSON(true);

      $additionalInfo = new BalanceInquiryAdditionalInfoRequestDto(
          $requestData['additionalInfo']['channel']
      );
      $requestBody = new BalanceInquiryRequestDto(
          $additionalInfo
      );
      $ipAddress = $this->request->getHeaderLine('X-IP-ADDRESS');
      $authCode = $requestData['authCode'];
      $response = $this->snap->doBalanceInquiry($requestBody, $authCode, $ipAddress);

      if (is_array($response) || is_object($response)) {
          $responseObject = (array)$response; // Ubah objek ke array jika perlu
      } else {
          throw new \Exception('Unexpected response type');
      }
      $responseCode = $responseObject['responseCode'];
      $statusCode = substr($responseCode, 0, 3);
      $this->response->setStatusCode((int)$statusCode);
      return $this->response->setJSON($responseObject);
  }
```

4. Error Handling and Troubleshooting
-------------------------------------

[](#4-error-handling-and-troubleshooting)

The SDK throws exceptions for various error conditions. Always wrap your API calls in try-catch blocks:

```
 try {
   $result = $snap->createVa($createVaRequestDto);
   // Process successful result
 } catch (Exception $e) {
     echo "Error: " . $e->getMessage() . PHP_EOL;
     // Handle the error appropriately
 }
```

This section provides common errors and solutions:

Error CodeDescriptionSolution`4010000`UnauthorizedCheck if Client ID and Secret Key are valid.`4012400`Virtual Account Not FoundVerify the virtual account number provided.`2002400`SuccessfulTransaction completed successfully.

###  Health Score

42

—

FairBetter than 90% of packages

Maintenance54

Moderate activity, may be stable

Popularity31

Limited adoption so far

Community14

Small or concentrated contributor base

Maturity57

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 60.8% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~17 days

Recently: every ~66 days

Total

18

Last Release

306d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/9df077a637bdad3df2bd4d401bdeaee3cb2b6a998cffed1f5e15aad9fd5b7558?d=identicon)[Dokutech](/maintainers/Dokutech)

---

Top Contributors

[![azzam2912](https://avatars.githubusercontent.com/u/63704395?v=4)](https://github.com/azzam2912 "azzam2912 (107 commits)")[![zulfikardoku](https://avatars.githubusercontent.com/u/224491943?v=4)](https://github.com/zulfikardoku "zulfikardoku (32 commits)")[![fikar46](https://avatars.githubusercontent.com/u/43537558?v=4)](https://github.com/fikar46 "fikar46 (20 commits)")[![rafidoku](https://avatars.githubusercontent.com/u/104545377?v=4)](https://github.com/rafidoku "rafidoku (15 commits)")[![robbyald](https://avatars.githubusercontent.com/u/73611463?v=4)](https://github.com/robbyald "robbyald (2 commits)")

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/doku-doku-php-library/health.svg)

```
[![Health](https://phpackages.com/badges/doku-doku-php-library/health.svg)](https://phpackages.com/packages/doku-doku-php-library)
```

###  Alternatives

[laravel/socialite

Laravel wrapper around OAuth 1 &amp; OAuth 2 libraries.

5.7k96.9M674](/packages/laravel-socialite)[laravel/passport

Laravel Passport provides OAuth2 server support to Laravel.

3.4k85.0M532](/packages/laravel-passport)[google/auth

Google Auth Library for PHP

1.4k272.7M162](/packages/google-auth)[kreait/firebase-php

Firebase Admin SDK

2.4k39.7M72](/packages/kreait-firebase-php)[shopify/shopify-api

Shopify API Library for PHP

4634.8M16](/packages/shopify-shopify-api)[thenetworg/oauth2-azure

Azure Active Directory OAuth 2.0 Client Provider for The PHP League OAuth2-Client

2509.6M48](/packages/thenetworg-oauth2-azure)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
