You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
You can use the APIs below to interface with DANA's WidgetApi API.
To start using the API, you need to destruct instantiated DANA client. This client would be a singleton object that you can use across various api and operation.
import{Dana}from'dana-node';constdanaClient=newDana({partnerId: "YOUR_PARTNER_ID",// process.env.X_PARTNER_IDprivateKey: "YOUR_PRIVATE_KEY",// process.env.X_PRIVATE_KEYorigin: "YOUR_ORIGIN",// process.env.ORIGINenv: "sandbox",// process.env.DANA_ENV or process.env.ENV or "sandbox" or "production"});const{ widgetApi }=danaClient;
The API is used to query user profile such as DANA balance (unit in IDR), masked DANA phone number, KYC or OTT (one time token) between merchant server and DANA's server
import{Dana}from'dana-node';import{AccountUnbindingRequest,AccountUnbindingResponse}from'dana-node/widget/v1';constdanaClient=newDana({partnerId: "YOUR_PARTNER_ID",// process.env.X_PARTNER_IDprivateKey: "YOUR_PRIVATE_KEY",// process.env.X_PRIVATE_KEYorigin: "YOUR_ORIGIN",// process.env.ORIGINenv: "sandbox",// process.env.DANA_ENV or process.env.ENV or "sandbox" or "production"});const{ widgetApi }=danaClient;constrequest: AccountUnbindingRequest={// Define the request parameters for the API call here};constresponse: AccountUnbindingResponse=awaitwidgetApi.accountUnbinding(request);
import{Dana}from'dana-node';import{ApplyOTTRequest,ApplyOTTResponse}from'dana-node/widget/v1';constdanaClient=newDana({partnerId: "YOUR_PARTNER_ID",// process.env.X_PARTNER_IDprivateKey: "YOUR_PRIVATE_KEY",// process.env.X_PRIVATE_KEYorigin: "YOUR_ORIGIN",// process.env.ORIGINenv: "sandbox",// process.env.DANA_ENV or process.env.ENV or "sandbox" or "production"});const{ widgetApi }=danaClient;constrequest: ApplyOTTRequest={// Define the request parameters for the API call here};constresponse: ApplyOTTResponse=awaitwidgetApi.applyOTT(request);
import{Dana}from'dana-node';import{ApplyTokenRequest,ApplyTokenResponse}from'dana-node/widget/v1';constdanaClient=newDana({partnerId: "YOUR_PARTNER_ID",// process.env.X_PARTNER_IDprivateKey: "YOUR_PRIVATE_KEY",// process.env.X_PRIVATE_KEYorigin: "YOUR_ORIGIN",// process.env.ORIGINenv: "sandbox",// process.env.DANA_ENV or process.env.ENV or "sandbox" or "production"});const{ widgetApi }=danaClient;constrequest: ApplyTokenRequest={// Define the request parameters for the API call here};constresponse: ApplyTokenResponse=awaitwidgetApi.applyToken(request);
import{Dana}from'dana-node';import{BalanceInquiryRequest,BalanceInquiryResponse}from'dana-node/widget/v1';constdanaClient=newDana({partnerId: "YOUR_PARTNER_ID",// process.env.X_PARTNER_IDprivateKey: "YOUR_PRIVATE_KEY",// process.env.X_PRIVATE_KEYorigin: "YOUR_ORIGIN",// process.env.ORIGINenv: "sandbox",// process.env.DANA_ENV or process.env.ENV or "sandbox" or "production"});const{ widgetApi }=danaClient;constrequest: BalanceInquiryRequest={// Define the request parameters for the API call here};constresponse: BalanceInquiryResponse=awaitwidgetApi.balanceInquiry(request);
import{Dana}from'dana-node';import{CancelOrderRequest,CancelOrderResponse}from'dana-node/widget/v1';constdanaClient=newDana({partnerId: "YOUR_PARTNER_ID",// process.env.X_PARTNER_IDprivateKey: "YOUR_PRIVATE_KEY",// process.env.X_PRIVATE_KEYorigin: "YOUR_ORIGIN",// process.env.ORIGINenv: "sandbox",// process.env.DANA_ENV or process.env.ENV or "sandbox" or "production"});const{ widgetApi }=danaClient;constrequest: CancelOrderRequest={// Define the request parameters for the API call here};constresponse: CancelOrderResponse=awaitwidgetApi.cancelOrder(request);
import{Dana}from'dana-node';import{QueryPaymentRequest,QueryPaymentResponse}from'dana-node/widget/v1';constdanaClient=newDana({partnerId: "YOUR_PARTNER_ID",// process.env.X_PARTNER_IDprivateKey: "YOUR_PRIVATE_KEY",// process.env.X_PRIVATE_KEYorigin: "YOUR_ORIGIN",// process.env.ORIGINenv: "sandbox",// process.env.DANA_ENV or process.env.ENV or "sandbox" or "production"});const{ widgetApi }=danaClient;constrequest: QueryPaymentRequest={// Define the request parameters for the API call here};constresponse: QueryPaymentResponse=awaitwidgetApi.queryPayment(request);
import{Dana}from'dana-node';import{QueryUserProfileRequest,QueryUserProfileResponse}from'dana-node/widget/v1';constdanaClient=newDana({partnerId: "YOUR_PARTNER_ID",// process.env.X_PARTNER_IDprivateKey: "YOUR_PRIVATE_KEY",// process.env.X_PRIVATE_KEYorigin: "YOUR_ORIGIN",// process.env.ORIGINenv: "sandbox",// process.env.DANA_ENV or process.env.ENV or "sandbox" or "production"});const{ widgetApi }=danaClient;constrequest: QueryUserProfileRequest={// Define the request parameters for the API call here};constresponse: QueryUserProfileResponse=awaitwidgetApi.queryUserProfile(request);
import{Dana}from'dana-node';import{RefundOrderRequest,RefundOrderResponse}from'dana-node/widget/v1';constdanaClient=newDana({partnerId: "YOUR_PARTNER_ID",// process.env.X_PARTNER_IDprivateKey: "YOUR_PRIVATE_KEY",// process.env.X_PRIVATE_KEYorigin: "YOUR_ORIGIN",// process.env.ORIGINenv: "sandbox",// process.env.DANA_ENV or process.env.ENV or "sandbox" or "production"});const{ widgetApi }=danaClient;constrequest: RefundOrderRequest={// Define the request parameters for the API call here};constresponse: RefundOrderResponse=awaitwidgetApi.refundOrder(request);
import{Dana}from'dana-node';import{WidgetPaymentRequest,WidgetPaymentResponse}from'dana-node/widget/v1';constdanaClient=newDana({partnerId: "YOUR_PARTNER_ID",// process.env.X_PARTNER_IDprivateKey: "YOUR_PRIVATE_KEY",// process.env.X_PRIVATE_KEYorigin: "YOUR_ORIGIN",// process.env.ORIGINenv: "sandbox",// process.env.DANA_ENV or process.env.ENV or "sandbox" or "production"});const{ widgetApi }=danaClient;constrequest: WidgetPaymentRequest={// Define the request parameters for the API call here};constresponse: WidgetPaymentResponse=awaitwidgetApi.widgetPayment(request);
Enum Types
In Node.js, enums are located within each model class rather than being centralized in a separate enum file. Each enum is named after its parent model.
For example, to use the promoType enum from PaymentPromoInfo:
import{PaymentPromoInfoPromoTypeEnum}from'dana-node/widget/v1';// Use the enum valueconstpromoType=PaymentPromoInfoPromoTypeEnum.CashBack;
In this example the PaymentPromoInfo is the parent model and PromoType is the enum name. In below list, the enums are listed in format of {ParentModel}{EnumName} (Enum Field).
Order is accepted by merchant after order is paid for PAY-CONFIRM
Cancelled
Order is cancelled
UrlParamTypeEnum (type)
Value
Description
PayReturn
After the payment, the user will be redirected to merchant page, this is mandatory
Notification
When finish payment, DANA will notify to the URL that has been defined by user
UserResourceInfoResourceTypeEnum (resourceType)
Value
Description
Balance
Query balance of user in DANA
TopupUrl
Obtain the top up URL for merchant to redirect
TransactionUrl
Obtain the transaction URL for merchant to redirect
Ott
Obtain the OTT of URLs including TOPUP/TRANSACTION/CASHIER/CHECKOUT_URL
MaskDanaId
The masked identifier from DANA side
UserKyc
KYC level. 00 = KYC level 0, 02 = KYC level 2
LoginId
Login identifier of the user, currently it's only set to phone number
ClearTextDanaId
The unmasked identifier from DANA side
Nickname
Nickname of the user in DANA
Fullname
Full name of the user in DANA
KtpNumber
KTP number of the user in DANA
KtpPhotoData
KTP photo binary data in base64 of the user in DANA
SelfiePhotoData
Selfie photo binary data in base64 of the user in DANA
AvatarUrl
Location of avatar photo of the user in DANA
MaskedFullname
Masked full name of the user in DANA
Webhook Verification
This document explains how to use the WebhookParser utility from the `` SDK to securely verify and parse webhook notifications sent by DANA.
Example
import{WebhookParser}from'dana-node/webhook/v1';// Adjust import path as needed// Assuming you are in an Express.js route handler or similar framework context.// If using Express, you might import types like this:// import { Request, Response } from 'express';// Example route handler for DANA webhooks.// Replace `AnyRequestType` and `AnyResponseType` with types from your web framework (e.g., Express's Request, Response).asyncfunctionhandleDanaWebhook(req: AnyRequestType,res: AnyResponseType){// Retrieve the DANA public key from environment variables or a secure configuration.// Option 1: Public key as a stringconstdanaPublicKeyString: string|undefined=process.env.DANA_PUBLIC_KEY;// Option 2: Path to the public key file (recommended for production)constdanaPublicKeyPath: string|undefined=process.env.DANA_PUBLIC_KEY_PATH;if(!danaPublicKeyString&&!danaPublicKeyPath){console.error('DANA webhook public key not configured.');res.status(500).send('Webhook processor configuration error.');// Or appropriate error handlingreturn;}// Extract necessary data from the request objectconsthttpMethod: string=req.method!;// e.g., "POST"constrelativePathUrl: string=req.path!;// e.g., "/v1.0/debit/notify". Ensure this is the path DANA signs.// req.headers is typically an object like { 'header-name': 'value' }.// The WebhookParser expects Record<string, string>.// Node's IncomingHttpHeaders can have string[] for values, but X-SIGNATURE and X-TIMESTAMP// are expected to be single strings. Casting or careful handling might be needed.constheaders: Record<string,string>=req.headersasRecord<string,string>;// The body needs to be the raw JSON string.// If you're using a body-parsing middleware (e.g., express.json()),// req.body might already be a parsed JavaScript object.// The WebhookParser expects the raw string body that was signed.letrequestBodyString: string;if(typeofreq.body==='string'){requestBodyString=req.body;}elseif(req.body&&typeofreq.body==='object'){// If req.body is an object, it means middleware parsed it.// We need to stringify it back to pass to the parser,// assuming this stringified version matches what DANA signed.// IMPORTANT: This assumes JSON.stringify(parsedBody) is equivalent to the raw body DANA sent.// For robust parsing, it's best to get the raw body *before* any JSON parsing middleware,// e.g., using `express.raw({ type: 'application/json' })` for specific routes.requestBodyString=JSON.stringify(req.body);}else{console.error('Request body is not a string or a parseable object.');res.status(400).send('Invalid request body format.');return;}// Initialize WebhookParser.// The constructor prioritizes publicKeyPath if both are provided.constparser=newWebhookParser(danaPublicKeyString,danaPublicKeyPath);try{// Verify the signature and parse the webhook payloadconstfinishNotify=parser.parseWebhook(httpMethod,relativePathUrl,headers,requestBodyString);console.log('Webhook verified successfully:');console.log('Original Partner Reference No:',finishNotify.originalPartnerReferenceNo);// TODO: Process the finishNotify object (e.g., update order status in your database)res.status(200).send('Webhook received and verified.');}catch(error: any){// Catching as 'any' to access error.messageconsole.error('Webhook verification failed:',error.message);// Respond with an error status. DANA might retry if it receives an error.res.status(400).send(`Webhook verification failed: ${error.message}`);}}
publicKey (string, optional): The DANA gateway's public key as a PEM formatted string. This is used if publicKeyPath is not provided or is empty.
publicKeyPath (string, optional): The file path to the DANA gateway's public key PEM file. If provided, this will be prioritized over the publicKey string.
One of publicKey or publicKeyPath must be provided.
Represents the standard notification payload for payment events.
OAuth URL Generation
You can generate OAuth URLs for widget authorization using the WidgetUtils helper:
import{WidgetUtils,Oauth2UrlDataModeEnum}from'dana-node/widget/v1';// Generate OAuth URLconstoauth2UrlData={redirectUrl: 'https://your-redirect-url.com',externalId: 'your-external-id',// or use uuidv4()merchantId: process.env.MERCHANT_ID,seamlessData: {mobileNumber: '08xxxxxxxxx'// Optional},mode: Oauth2UrlDataModeEnum.Api// or Oauth2UrlDataModeEnum.Deeplink};constoauthUrl=WidgetUtils.generateOauthUrl(oauth2UrlData);console.log(oauthUrl);
The generated URL can be used to redirect users to DANA's authorization page.
Complete Payment URL Generation
You can generate a payment URL by combining the webRedirectUrl from a WidgetPaymentResponse with an OTT token from an ApplyOTTResponse.
import{Util}from'dana-node/widget/v1';import{WidgetPaymentResponse,ApplyOTTResponse}from'dana-node/widget/v1/models';// Example response from createWidgetPaymentconstwidgetPaymentResponse=newWidgetPaymentResponse({webRedirectUrl: 'https://example.com/payment?token=abc123'});// this should be from createPayment Widget API// Example response from applyOTTconstapplyOTTResponse=newApplyOTTResponse({userResources: [{value: 'ott_token_value'}]});// this should be from applyOTT Widget API// Generate the payment URLconstpaymentUrl=Util.generateCompletePaymentUrl(widgetPaymentResponse,applyOTTResponse);