API Reference
DOKU DocsChangelogDOKU Github
  • Getting Started with DOKU API
    • User Registration
    • Idempotency Request
    • Notification
      • Setup Notification URL
      • HTTP Notification Sample for SNAP
      • HTTP Notification Sample - Non SNAP
      • Best Practice
      • Retry Notification
      • Override Notification URL
    • Signature Component
      • Non-SNAP
        • Signature Component from Request Header
        • Signature Componen from Response Header
        • Signature from API Get Method
        • Sample Code
      • SNAP
        • Symmetric Signature
        • Asymmetric Signature
    • Response Code
      • HTTP Status and Case Code
    • Check Status API
      • Non-SNAP
      • SNAP
    • Retrieve Payment Credential
  • Accept Payment
    • DOKU Checkout
      • Integration Guide
        • Backend Integration
        • Frontend Integration
        • Simulate payment and Notification
      • Supported Payment Methods
      • Status Order
      • Additional Feature
        • Tokenization
        • Promo on DOKU Checkout Page
        • Track Campaign Source on Google Analytics
      • Checkout Settings
    • Direct API
      • Non-SNAP
        • Cards
          • Payment Page Integration Guide
          • Host-To-Host Integration Guide
          • Mastercard Automatic Billing Updater (ABU) Integration Guide
            • Backend Integration
        • e-Wallet
          • Overview
          • DOKU e-Wallet
          • OVO Push Payment
          • ShopeePay
          • LinkAja
        • Paylater
          • Akulaku
          • Kredivo
          • Indodana
        • Digital Banking
          • Jenius Pay
        • Convenience Store
          • Alfa Group
          • Indomaret
      • SNAP
        • Integration Guide
          • Get Token API
            • B2B
            • B2B2C
          • Virtual Account
            • CIMB Virtual Account
            • BSI Virtual Account
            • BCA Virtual Account
            • BNC Virtual Account
            • BNI Virtual Account
            • Mandiri Virtual Account
            • BRI Virtual Account
            • BTN Virtual Account
            • Permata Virtual Account
            • Danamon Virtual Account
            • BSS Virtual Account
          • E-Wallet
            • DOKU Wallet
            • DANA
            • OVO
            • ShopeePay
          • Direct Debit
            • Allo Bank Direct Debit
            • BRI Direct Debit
            • CIMB Direct Debit
            • Mandiri Direct Debit
          • Kartu Kredit Indonesia Cepat Secure(KKI CPTS)
            • Host to Host Integration
          • QRIS
    • Finance and Settlement
      • Split Settlement
      • Custom Settlement Report
      • Hold and Release Settlement
      • Bulk Registration Bank
    • Test on DOKU Demo Site
    • DOKU Payment Simulator
  • Developer Kit
    • Postman Collection
    • Libraries and SDK
  • Wallet As A Service
    • Sub Account
  • Partnership
    • Partner API
      • Check Requirements API
      • Generate Token API
      • Upload File API
      • Business Registration API
      • Create Business Lite API
      • Get Business Data API
  • Payout
    • Kirim DOKU
  • FLEXIBILL
    • Account Billing
      • Batch Upload
    • DOKU Biller
      • Response Code
      • Samples
  • PAYCHAT API
    • Send WhatsApp Message
  • Archive
    • Non-SNAP
      • Tokenization V1
      • e-Wallet
        • OVO Recurring
        • OVO Open API
    • SNAP
      • Virtual Account
        • BCA v1.0
        • BRI v1.0
        • BNI v1.0
        • BNC v1.0
        • Mandiri v1.0
        • BTN v1.0
        • Permata v1.0
        • Danamon Virtual Account
      • e-Wallet
        • OVO Open API
        • DANA
        • ShopeePay
      • Direct Debit
        • CIMB Direct Debit
        • BRI Direct Debit
        • Allobank
Powered by GitBook

DOKU API

  • Legacy Documentation
On this page

Was this helpful?

  1. Getting Started with DOKU API
  2. Signature Component
  3. Non-SNAP

Sample Code

Here is the sample code to generate the Signature:

SAMPLE ONLY!

This is just a sample code to demonstrate how to generate the Signature on different programming language. Kindly adjust the code to suited your project's structure.

import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
 
public class Signature {
 
    public static final String CLIENT_ID = "Client-Id";
    public static final String REQUEST_ID = "Request-Id";
    public static final String REQUEST_TIMESTAMP = "Request-Timestamp";
    public static final String REQUEST_TARGET = "Request-Target";
    public static final String DIGEST = "Digest";
    public static final String COLON_SYMBOL = ":";
    public static final String NEW_LINE = "\n";
    
    // Generate Digest
    public static String generateDigest(String requestBody) throws NoSuchAlgorithmException {
        MessageDigest md = MessageDigest.getInstance("SHA-256");
        md.update(requestBody.getBytes(StandardCharsets.UTF_8));
        byte[] digest = md.digest();
        return Base64.getEncoder().encodeToString(digest);
    }
    
    private static String generateSignature(String clientId, String requestId, String requestTimestamp, String requestTarget, String digest, String secret) throws InvalidKeyException, NoSuchAlgorithmException {
        // Prepare Signature Component
        System.out.println("----- Component Signature -----");
        StringBuilder component = new StringBuilder();
        component.append(CLIENT_ID).append(COLON_SYMBOL).append(clientId);
        component.append(NEW_LINE);
        component.append(REQUEST_ID).append(COLON_SYMBOL).append(requestId);
        component.append(NEW_LINE);
        component.append(REQUEST_TIMESTAMP).append(COLON_SYMBOL).append(requestTimestamp);
        component.append(NEW_LINE);
        component.append(REQUEST_TARGET).append(COLON_SYMBOL).append(requestTarget);
        // If body not send when access API with HTTP method GET/DELETE
        if(digest != null && !digest.isEmpty()) {
            component.append(NEW_LINE);
            component.append(DIGEST).append(COLON_SYMBOL).append(digest);
        }

        System.out.println(component.toString());
        System.out.println();
 
        // Calculate HMAC-SHA256 base64 from all the components above
        byte[] decodedKey = secret.getBytes();
        SecretKey originalKey = new SecretKeySpec(decodedKey, 0, decodedKey.length, "HmacSHA256");
        Mac hmacSha256 = Mac.getInstance("HmacSHA256");
        hmacSha256.init(originalKey);
        hmacSha256.update(component.toString().getBytes());
        byte[] HmacSha256DigestBytes = hmacSha256.doFinal();
        String signature = Base64.getEncoder().encodeToString(HmacSha256DigestBytes);
        // Prepend encoded result with algorithm info HMACSHA256=
        return "HMACSHA256="+signature;
    }
    
    // Sample of Usage
    public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeyException {
         String jsonBody = new JSONObject()
                          .put("order", new JSONObject()
                            .put("invoice_number", "INV-20210124-0001")
                            .put("amount", 15000)
                          )
                          .put("virtual_account_info", new JSONObject()
                            .put("expired_time", 60)
                            .put("amount", 15000)
                          )
                          .toString();
 
        // Generate Digest from JSON Body, For HTTP Method GET/DELETE don't need generate Digest
        System.out.println("----- Digest -----");
        String digest = generateDigest(jsonBody);
        System.out.println(digest);
        System.out.println();
 
        // Generate Signature
        String headerSignature = generateSignature(
                "yourClientId",
                "yourRequestId",
                "2020-10-21T03:38:28Z",
                "/request-target/goes-here", // For merchant request to DOKU, use DOKU path here. For HTTP Notification, use merchant path here
                digest, // Set empty string for this argumentes if HTTP Method is GET/DELETE
                "secret-key-from-DOKU-back-office");
 
        System.out.println("----- Header Signature -----");
        System.out.println(headerSignature);
    }
}
<?php

$clientId = "yourClientId";
$requestId = "yourRequestId";
$requestDate = "2020-10-21T03:38:28Z";
$targetPath = "/request-target/goes-here"; // For merchant request to Jokul, use Jokul path here. For HTTP Notification, use merchant path here
$secretKey = "secret-key-from-jokul-back-office";
$requestBody = array (
    'order' => array (
        'amount' => 15000,
        'invoice_number' => 'INV-20210124-0001',
    ),
    'virtual_account_info' => array (
        'expired_time' => 60,
        'reusable_status' => false,
        'info1' => 'Merchant Demo Store',
    ),
    'customer' => array (
        'name' => 'Taufik Ismail',
        'email' => 'taufik@example.com',
    ),
);

// Generate Digest
$digestValue = base64_encode(hash('sha256', json_encode($requestBody), true));
echo "Digest: " . $digestValue;
echo "\r\n\n";

// Prepare Signature Component
$componentSignature = "Client-Id:" . $clientId . "\n" . 
                      "Request-Id:" . $requestId . "\n" .
                      "Request-Timestamp:" . $requestDate . "\n" . 
                      "Request-Target:" . $targetPath . "\n" .
                      "Digest:" . $digestValue;
echo "Component Signature: \n" . $componentSignature;
echo "\r\n\n";
 
// Calculate HMAC-SHA256 base64 from all the components above
$signature = base64_encode(hash_hmac('sha256', $componentSignature, $secretKey, true));
echo "Signature: " . $signature;
echo "\r\n\n";

// Sample of Usage
$headerSignature =  "Client-Id:" . $clientId ."\n". 
                    "Request-Id:" . $requestId . "\n".
                    "Request-Timestamp:" . $requestDate ."\n".
                    // Prepend encoded result with algorithm info HMACSHA256=
                    "Signature:" . "HMACSHA256=" . $signature;
echo "your header request look like: \n".$headerSignature;
echo "\r\n\n";
import hashlib
import hmac
import base64

# Generate Digest
def generateDigest(jsonBody):  
    return base64.b64encode(hashlib.sha256(jsonBody.encode('utf-8')).digest()).decode("utf-8")

def generateSignature(clientId, requestId, requestTimestamp, requestTarget, digest, secret):
    # Prepare Signature Component
    print("----- Signature Component -----")
    componentSignature = "Client-Id:" + clientId
    componentSignature += "\n"
    componentSignature += "Request-Id:" + requestId
    componentSignature += "\n"
    componentSignature += "Request-Timestamp:" + requestTimestamp
    componentSignature += "\n"
    componentSignature += "Request-Target:" + requestTarget
    # If body not send when access API with HTTP method GET/DELETE
    if digest:
        componentSignature += "\n"
        componentSignature += "Digest:" + digest
     
    print(componentSignature)
    message = bytes(componentSignature, 'utf-8')
    secret = bytes(secret, 'utf-8')
 
    # Calculate HMAC-SHA256 base64 from all the components above
    signature = base64.b64encode(hmac.new(secret, message, digestmod=hashlib.sha256).digest()).decode("utf-8")

    # Prepend encoded result with algorithm info HMACSHA256=
    return "HMACSHA256="+signature 

# Sample of usage

# Generate Digest from JSON Body, For HTTP Method GET/DELETE don't need generate Digest
print("----- Digest -----")
jsonBody = '{\"order\":{\"invoice_number\":\"INV-20210124-0001\",\"amount\":150000},\"virtual_account_info\":{\"expired_time\":60,\"reusable_status\":false,\"info1\":\"Merchant Demo Store\"},\"customer\":{\"name\":\"Taufik Ismail\",\"email\":\"taufik@example.com\"}}'
digest = generateDigest(jsonBody)
print(digest)
print("")

# Generate Signature
headerSignature = generateSignature(
        "yourClientId",
        "yourRequestId",
        "2020-10-21T03:38:28Z",
        "/request-target/goes-here", # For merchant request to Jokul, use Jokul path here. For HTTP Notification, use merchant path here
        digest, # Set empty string for this argumentes if HTTP Method is GET/DELETE
        "secret-key-from-jokul-back-office")
print("----- Header Signature -----")
print(headerSignature)
const crypto = require('crypto');
  
// Generate Digest
function generateDigest(jsonBody) {
    let jsonStringHash256 = crypto.createHash('sha256').update(jsonBody,"utf-8").digest();
    
    let bufferFromJsonStringHash256 = Buffer.from(jsonStringHash256);
    return bufferFromJsonStringHash256.toString('base64'); 
}
 
function generateSignature(clientId, requestId, requestTimestamp, requestTarget, digest, secret) {
    // Prepare Signature Component
    console.log("----- Component Signature -----")
    let componentSignature = "Client-Id:" + clientId;
    componentSignature += "\n";
    componentSignature += "Request-Id:" + requestId;
    componentSignature += "\n";
    componentSignature += "Request-Timestamp:" + requestTimestamp;
    componentSignature += "\n";
    componentSignature += "Request-Target:" + requestTarget;
    // If body not send when access API with HTTP method GET/DELETE
    if (digest) {
        componentSignature += "\n";
        componentSignature += "Digest:" + digest;
    }
 
    console.log(componentSignature.toString());
    console.log();

    // Calculate HMAC-SHA256 base64 from all the components above
    let hmac256Value = crypto.createHmac('sha256', secret)
                   .update(componentSignature.toString())
                   .digest();  
      
    let bufferFromHmac256Value = Buffer.from(hmac256Value);
    let signature = bufferFromHmac256Value.toString('base64');
    // Prepend encoded result with algorithm info HMACSHA256=
    return "HMACSHA256="+signature 
}
 
// Sample of Usage

// Generate Digest from JSON Body, For HTTP Method GET/DELETE don't need generate Digest
console.log("----- Digest -----");
let jsonBody = '{\"order\":{\"invoice_number\":\"INV-20210124-0001\",\"amount\":150000},\"virtual_account_info\":{\"expired_time\":60,\"reusable_status\":false,\"info1\":\"Merchant Demo Store\"},\"customer\":{\"name\":\"Taufik Ismail\",\"email\":\"taufik@example.com\"}}';
let digest = generateDigest(jsonBody);
console.log(digest);
console.log();
  
// Generate Header Signature
let headerSignature = generateSignature(
        "yourClientId",
        "yourRequestId",
        "2020-10-21T03:38:28Z",
        "/request-target/goes-here", // For merchant request to Jokul, use Jokul path here. For HTTP Notification, use merchant path here
        digest, // Set empty string for this argumentes if HTTP Method is GET/DELETE
        "secret-key-from-jokul-back-office")
console.log("----- Header Signature -----")
console.log(headerSignature)
require 'openssl'
require 'base64'
require 'digest'
 
# Generate Digest
def generateDigest(jsonBody)
    return Base64.encode64(Digest::SHA256.digest(jsonBody)).strip()
end
 
def generateSignature(clientId, requestId, requestTimestamp, requestTarget, digest, secret)
    # Prepare Signature Component
    puts "----- Component Signature -----"
    componentSignature = ("Client-Id:" + clientId")
    componentSignature.concat("\n")
    componentSignature.concat("Request-Id:" + requestId)
    componentSignature.concat("\n")
    componentSignature.concat("Request-Timestamp:" + requestTimestamp)
    componentSignature.concat("\n")
    componentSignature.concat("Request-Target:" + requestTarget)
    # If body not send when access API with HTTP method GET/DELETE
    unless digest.to_s.strip.empty?
        componentSignature.concat("\n")
        componentSignature.concat("Digest:" + digest)
    end
    puts componentSignature
    puts "\n"  

    # Calculate HMAC-SHA256 base64 from all the components above
    hash = OpenSSL::HMAC.digest("sha256", secret, componentSignature)
    signature = Base64.encode64(hash).strip()

    # Prepend encoded result with algorithm info HMACSHA256=
    return "HMACSHA256="+signature 
end
 
# Sample of Usage

# Generate Digest from JSON Body, For HTTP Method GET/DELETE don't need generate Digest
puts "----- Digest -----"
jsonBody = '{\"order\":{\"invoice_number\":\"INV-20210124-0001\",\"amount\":150000},\"virtual_account_info\":{\"expired_time\":60,\"reusable_status\":false,\"info1\":\"Merchant Demo Store\"},\"customer\":{\"name\":\"Taufik Ismail\",\"email\":\"taufik@example.com\"}}'
digest = generateDigest(jsonBody)
puts digest
puts "\n"
 
# Generate Header Signature
headerSignature = generateSignature(
        "yourClientId",
        "yourRequestId",
        "2020-10-21T03:38:28Z",
        "/request-target/goes-here", # For merchant request to Jokul, use Jokul path here. For HTTP Notification, use merchant path here
        digest, # Set empty string for this argumentes if HTTP Method is GET/DELETE
        "secret-key-from-jokul-back-office")
puts "----- Header Signature -----"
puts headerSignature
package main
 
import (
    "crypto/hmac"
    "crypto/sha256"
    "encoding/base64"
    "fmt"
    "strings"
)
 
const CLIENT_ID = "Client-Id"
const REQUEST_ID = "Request-Id"
const REQUEST_TIMESTAMP = "Request-Timestamp"
const REQUEST_TARGET = "Request-Target"
const DIGEST = "Digest"
const SYMBOL_COLON = ":"
 
// Generate Digest
func generateDigest(jsonBody string) string {
    converted := []byte(jsonBody)
    hasher := sha256.New()
    hasher.Write(converted)
    return (base64.StdEncoding.EncodeToString(hasher.Sum(nil)))
     
}

func generateSignature(clientId string, requestId string, requestTimestamp string, requestTarget string, digest string, secret string) string {
    // Prepare Signature Component
    fmt.Println("----- Component Signature -----")
    var componentSignature strings.Builder
    componentSignature.WriteString(CLIENT_ID + SYMBOL_COLON + clientId)
    componentSignature.WriteString("\n")
    componentSignature.WriteString(REQUEST_ID + SYMBOL_COLON + requestId)
    componentSignature.WriteString("\n")
    componentSignature.WriteString(REQUEST_TIMESTAMP + SYMBOL_COLON + requestTimestamp)
    componentSignature.WriteString("\n")
    componentSignature.WriteString(REQUEST_TARGET + SYMBOL_COLON + requestTarget) 
    componentSignature.WriteString("\n")
    componentSignature.WriteString(DIGEST + SYMBOL_COLON +digest) 
    // If body not send when access API with HTTP method GET/DELETE
    if len(digest) > 0  {
        componentSignature.WriteString("\n")
        componentSignature.WriteString(DIGEST + SYMBOL_COLON +digest)
    }
 
    fmt.Println(componentSignature.String())
    fmt.Println("")
 
    // Calculate HMAC-SHA256 base64 from all the components above
    key := []byte(secret)
    h := hmac.New(sha256.New, key)
    h.Write([]byte(componentSignature.String()))
    signature := base64.StdEncoding.EncodeToString(h.Sum(nil))
    // Prepend encoded result with algorithm info HMACSHA256=
    return "HMACSHA256="+signature
}

// Sample of Usage
func main() {
  
    // Genreate Digest from JSON Body
    var jsonBody = '{\"order\":{\"invoice_number\":\"INV-20210124-0001\",\"amount\":150000},\"virtual_account_info\":{\"expired_time\":60,\"reusable_status\":false,\"info1\":\"Merchant Demo Store\"},\"customer\":{\"name\":\"Taufik Ismail\",\"email\":\"taufik@example.com\"}}'
    digest := generateDigest(jsonBody);
    fmt.Println("----- Digest -----")
    fmt.Println(digest)
    fmt.Println("")
    
    // Generate Signature
    headerSignature := generateSignature(
        "yourClientId",
        "yourRequestId",
        "2020-10-21T03:38:28Z",
        "/request-target/goes-here", // For merchant request to DOKU, use DOKU path here. For HTTP Notification, use merchant path here
        digest, // Set empty string for this argumentes if HTTP Method is GET/DELETE
        "secret-key-from-DOKU-back-office")
 
    fmt.Println("----- Header Signature -----")    
    fmt.Println(headerSignature)
}
PreviousSignature from API Get MethodNextSNAP

Last updated 1 year ago

Was this helpful?