{"id":21878072,"url":"https://github.com/midtrans/midtrans-java","last_synced_at":"2025-08-21T01:32:06.079Z","repository":{"id":38365718,"uuid":"210317313","full_name":"Midtrans/midtrans-java","owner":"Midtrans","description":"This is the Official Java API client/library for Midtrans Payment API. Visit https://midtrans.com. More information about the product and see documentation at http://docs.midtrans.com for more technical details","archived":false,"fork":false,"pushed_at":"2024-10-16T08:48:06.000Z","size":863,"stargazers_count":33,"open_issues_count":2,"forks_count":11,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-08-04T08:58:58.679Z","etag":null,"topics":["java","java-library","midtrans","payment-gateway"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Midtrans.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-09-23T09:36:24.000Z","updated_at":"2025-07-21T08:38:45.000Z","dependencies_parsed_at":"2024-11-28T10:17:05.819Z","dependency_job_id":null,"html_url":"https://github.com/Midtrans/midtrans-java","commit_stats":null,"previous_names":[],"tags_count":12,"template":false,"template_full_name":null,"purl":"pkg:github/Midtrans/midtrans-java","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Midtrans%2Fmidtrans-java","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Midtrans%2Fmidtrans-java/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Midtrans%2Fmidtrans-java/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Midtrans%2Fmidtrans-java/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Midtrans","download_url":"https://codeload.github.com/Midtrans/midtrans-java/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Midtrans%2Fmidtrans-java/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":271415019,"owners_count":24755628,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-20T02:00:09.606Z","response_time":69,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["java","java-library","midtrans","payment-gateway"],"created_at":"2024-11-28T08:11:36.141Z","updated_at":"2025-08-21T01:32:05.748Z","avatar_url":"https://github.com/Midtrans.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Midtrans Client - Java\n[![Download](https://maven-badges.herokuapp.com/maven-central/com.midtrans/java-library/badge.svg)](https://search.maven.org/artifact/com.midtrans/java-library/)\n[![Build Status](https://travis-ci.org/Xaxxis/midtrans-java.svg?branch=master)](https://travis-ci.org/Xaxxis/midtrans-java)\n[![Demo apps](https://img.shields.io/badge/Go%20to-Demo%20Apps-green)](https://sample-demo-dot-midtrans-support-tools.et.r.appspot.com/)\n\nMidtrans :heart: Java, This is the Official Java API client/library for Midtrans Payment API. Visit [https://midtrans.com](https://midtrans.com). More information about the product and see documentation at [http://docs.midtrans.com](https://beta-docs.midtrans.com/) for more technical details. This library used java version 1.8\n\n## 1. Installation\n\n### 1.a Using Maven or Gradle\nIf you're using Maven as the build tools for your project, please add the following dependency to your project's build definition (pom.xml):\nMaven:\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.midtrans\u003c/groupId\u003e\n    \u003cartifactId\u003ejava-library\u003c/artifactId\u003e\n    \u003cversion\u003e3.2.1\u003c/version\u003e\n\u003c/dependency\u003e\n```\nGradle:\nIf you're using Gradle as the build tools for your project, please add jcenter repository to your build script then add the following dependency to your project's build definition (build.gradle):\n```Gradle\ndependencies {\n\timplementation 'com.midtrans:java-library:3.2.1'\n}\n```\n\u003e **IMPORTANT NOTE**: Since April 13, 2021 We already migrate the repository from jcenter/bintray repository to [Maven central](https://search.maven.org/artifact/com.midtrans/java-library).\n\n### 1.b Using JAR File\n\nIf you are not using project build management like Maven, Gradle or Ant you can use manual jar library download JAR Library on [here](https://search.maven.org/remotecontent?filepath=com/midtrans/java-library/3.2.1/java-library-3.2.1.jar)\n\n## 2. Usage\n\n### 2.1 Choose Product/Method\n\nWe have [3 different products](https://beta-docs.midtrans.com/) that you can use:\n- [Snap](#22A-snap) - Customizable payment popup will appear on **your web/app** (no redirection). [doc ref](https://snap-docs.midtrans.com/)\n- [Snap Redirect](#22B-snap-redirect) - Customer need to be redirected to payment url **hosted by midtrans**. [doc ref](https://snap-docs.midtrans.com/)\n- [Core API (VT-Direct)](#22C-core-api-vt-direct) - Basic backend implementation, you can customize the frontend embedded on **your web/app** as you like (no redirection). [doc ref](https://api-docs.midtrans.com/)\n- [Iris Disbursement](#22D-iris-api) - Iris is Midtrans’ cash management solution that allows you to disburse payments to any bank accounts in Indonesia securely and easily. [doc ref](https://iris-docs.midtrans.com/)\n\nChoose one that you think best for your unique needs.\n\n### 2.2 Client Initialization and Configuration\n\nGet your client key and server key from [Midtrans Dashboard](https://dashboard.midtrans.com)\n\nCreate API client object, Select one from any of methods below that you most prefer. You can also check the [project's functional tests](library/src/test/java/com/midtrans/java) for more examples.\n\nSet a config with globally, except iris api\n```java\nimport com.midtrans.Midtrans;\nimport com.midtrans.httpclient.CoreApi;\nimport com.midtrans.httpclient.SnapApi;\nimport com.midtrans.httpclient.error.MidtransError;\nimport org.json.JSONObject;\n\nMidtrans.serverKey = \"YOUR_SERVER_KEY\";\nMidtrans.clientKey = \"YOUR_CLIENT_KEY\";\nMidtrans.isProduction = false;\n\n// CoreApi Request with global config\nJSONObject result = CoreApi.chargeTransaction(param);\n\n// SnapApi request with global config\nJSONObject result = SnapApi.createTransaction(param);\n```\n#### Per-request Configuration\nIt is also possible if on each of individual requests you want to set a unique/different configuration; like idempotency key, \nproxy, override/append notification url, or multiple account API keys via Config options and set as param on static method e.g: `CoreApi.chargeTransaction(param, configOptions)` method available on `CoreApi.class`, `SnapApi.class`, `TransactionApi.class` or `IrisApi.class`. Please follow the steps given below.\n\n\u003eNote: This method is expected to be thread-safe, you should prefer this if you are implementing multi-threading/concurrency in your code.\n```java\nimport com.midtrans.Config;\nimport com.midtrans.Midtrans;\nimport com.midtrans.httpclient.CoreApi;\nimport com.midtrans.httpclient.error.MidtransError;\nimport org.json.JSONObject;\n\nConfig coreApiConfigOptions = Config.builder()\n        .setServerKey(\"YOUR_SERVER_KEY\")\n        .setClientKey(\"YOUR_CLIENT_KEY\")\n        .setIrisIdempotencyKey(\"UNIQUE_ID\")\n        .setPaymentIdempotencyKey(\"UNIQUE_ID\")\n        .setProxyConfig(PROXY_CONFIG)\n        .setPaymentOverrideNotification(\"WEBHOOK_ENDPOINT\")\n        .setIsProduction(false)\n        .build();\n\n// CoreApi request with config options\nJSONObject result = CoreApi.chargeTransaction(param, coreApiConfigOptions);\n\nConfig snapConfigOptions = Config.builder()\n        .setServerKey(\"YOUR_SERVER_KEY\")\n        .setClientKey(\"YOUR_CLIENT_KEY\")\n        .setIrisIdempotencyKey(\"UNIQUE_ID\")\n        .setPaymentIdempotencyKey(\"UNIQUE_ID\")\n        .setProxyConfig(PROXY_CONFIG)\n        .setPaymentOverrideNotification(\"WEBHOOK_ENDPOINT\")\n        .setIsProduction(false)\n        .build();\n\n// SnapApi request with config options\nJSONObject result = SnapApi.createTransaction(param, snapConfigOptions);\n```\n\nIn case you are using a single account API key, but you need to set the config options value dynamically from the config object. Please follow the steps given below.\n```java\nimport com.midtrans.Midtrans;\nimport com.midtrans.httpclient.CoreApi;\nimport com.midtrans.httpclient.SnapApi;\nimport com.midtrans.httpclient.error.MidtransError;\nimport org.json.JSONObject;\n\n//1. Set credentials key globally\nMidtrans.serverKey = \"YOUR_SERVER_KEY\";\nMidtrans.clientKey = \"YOUR_CLIENT_KEY\";\nMidtrans.isProduction = false;\n\n//2. Set config options for core-api charge request\nConfig configOptions = Config.builder()\n     .setPaymentIdempotencyKey(\"UNIQUE_ID\")\n     .setPaymentOverrideNotification(\"DYNAMIC_WEBHOOK_ENDPOINT\")\n     .build();\n\n//3. CoreApi request with config options\nJSONObject result = CoreApi.chargeTransaction(param, configOptions);\n\n//4. Set config options for Snap charge request\nConfig snapConfigOptions = Config.builder()\n     .setPaymentOverrideNotification(\"DYNAMIC_WEBHOOK_ENDPOINT\")\n     .build();\n\n//5. SnapApi request with config options\nJSONObject result = SnapApi.createTransaction(param, snapConfigOptions);\n```\n\n#### Alternative way to initialize\n```java\nimport com.midtrans.Config;\nimport com.midtrans.ConfigFactory;\nimport com.midtrans.service.MidtransCoreApi;\n\nConfig coreApiConfigOptions = Config.builder()\n        .setServerKey(\"YOUR_SERVER_KEY\")\n        .setClientKey(\"YOUR_CLIENT_KEY\")\n        .setIsProduction(false)\n        .build();\n\nMidtransCoreApi coreApi = new ConfigFactory(coreApiConfigOptions).getCoreApi();\n\n//You can set Config.class with\n`YOUR_SERVER_KEY`\n`YOUR_CLIENT_KEY`\n`isProduction`\n```\n\n```java\nimport com.midtrans.Config;\nimport com.midtrans.ConfigFactory;\nimport com.midtrans.service.MidtransSnapApi;\n\nConfig snapConfigOptions = Config.builder()\n        .setServerKey(\"YOUR_SERVER_KEY\")\n        .setClientKey(\"YOUR_CLIENT_KEY\")\n        .setIsProduction(false)\n        .build();\n\nMidtransSnapApi snapApi = new ConfigFactory(snapConfigOptions).getSnapApi();\n\n//You can set Config.class with\n`YOUR_SERVER_KEY`\n`YOUR_CLIENT_KEY`\n`isProduction`\n```\n\n```java\nimport com.midtrans.Config;\nimport com.midtrans.ConfigFactory;\nimport com.midtrans.service.MidtransIrisApi;\n\nConfig irisConfigOptions = Config.builder()\n        .setServerKey(\"IRIS-CREDENTIAL\")\n        .setIsProduction(false)\n        .build();\n\nMidtransIrisApi irisApi = new ConfigFactory(irisConfigOptions).getIrisApi();\n\n//You can set Config.class with\n`IRIS-CREDNTIALS`\n`null`\n`isProduction`\n```\n\nYou can also re-set config using `apiConfig()` method on MidtransCoreApi.Class, MidtransSnapApi.Class or MidtransIrisApi.class like `coreApi.apiConfig().set( ... )`\n\u003e Please note that if you are using multi-thread concurrency, this method is not thread-safe. For that, you should use the method of creating \u0026 setting individual Config option instances per request. [Refer to this section](README.md#per-request-configuration)\n\nexample:\n\n```java\n// Create Snap API instance, empty config\ncoreApi.apiConfig().setProduction(false);\ncoreApi.apiConfig().setClientKey(\"YOUR_CLIENT_KEY\");\ncoreApi.apiConfig().setServerKey(\"YOUR_SERVER_KEY\");\n\n// You don't have to re-set using all the options, \n// i.e. set serverKey only\ncoreApi.apiConfig().setServerKey(\"YOUR_SERVER_KEY\");\n\n// For Iris Disbursement can set creator \u0026 approver credentials with apiConfig()\nirisApi.apiConfig().setServerKey(\"IRIS-CREDENTIALS\");\n```\n\nIn production environment, LOG is by default turned off, you can enable by `setEnabledLog`, e.g:\n\n```java\ncoreApi.apiConfig().setEnabledLog(true);\n\n//or using\n        \nconfig.setEnabledLog(true);\n```\n\nUsing internal proxy, you can set ProxyConfig object with ProxyConfigBuilder to set hostname, port, username, and password. and also connectionTimeout, readTimeout, and writeTimeout. But if you not define network configuration like\nProxyConfig, connectionTimeout, readTimeout and writeTimeout, default value is 10 second and the connection no proxy configuration.\n\nexample:\n```java\nimport com.midtrans.proxy.ProxyConfig;\nimport com.midtrans.service.MidtransCoreApi;\n\nProxyConfig proxyConfig = ProxyConfig.builder()\n        .setHost(PROXY_HOTS)\n        .setPort(PROXY_PORT)\n        .setUsername(PROXY_USERNAME)\n        .setPassword(PROXY_PASSWORD)\n        .build();\n\n//Initialize MidtransCoreApi config with proxy and network configuration\nprivate MidtransCoreApi coreApi = new ConfigFactory(new Config(\"YOU_SERVER_KEY\",\"YOUR_CLIENT_KEY\", false, 10, 10, 10, proxyConfig)).getCoreApi();\n\n// Alternative, initialize proxy in Global Config\nMidtrans.setProxyConfig(proxyConfig);\n```\nadd new 4 params to use http proxy and network config,\n- connectionTimeout - default value 10s\n- readTimeout - default values 10s\n- writeTimeout - default value 10s\n- proxyConfig\n- maxConnectionPool - default value 16\n- keepAliveDuration - default value 300s\n\nand also you can set value for connectionTimeout or etc with configuration class, default value for TimeUnit is SECONDS, you can change the TimeUnit with config class.\n\nexample: \n```java\n// set as globally\nMidtrans.setConnectTimeout(10000);\nMidtrans.setReadTimeout(10000);\nMidtrans.setWriteTimeout(10000);\nMidtrans.setMaxConnectionPool(16);\nMidtrans.setKeepAliveDuration(300000);\nMidtrans.setHttpClientTimeUnit(TimeUnit.MILLISECONDS);\n\n// set connection timeout with Config class\nconfig.setConnectionTimeout(10000, TimeUnit.MILLISECONDS);\nconfig.setReadTimeout(10000, TimeUnit.MILLISECONDS);\nconfig.setWriteTimeout(10000, TimeUnit.MILLISECONDS);\nconfig.setKeepAliveDuration(300000, TimeUnit.MILLISECONDS);\nconfig.setMaxConnectionPool(16);\n\n// Set connection timeout from initiate api object\ncoreApi.apiConfig().setConnectionTimeout(10000, TimeUnit.MILLISECONDS);\ncoreApi.apiConfig().setReadTimeout(10000, TimeUnit.MILLISECONDS);\ncoreApi.apiConfig().setWriteTimeout(10000, TimeUnit.MILLISECONDS);\ncoreApi.apiConfig().setKeepAliveDuration(300000, TimeUnit.MILLISECONDS);\ncoreApi.apiConfig().setMaxConnectionPool(16);\n```\n\n#### Override Notification Url\nMerchant can opt to change or add custom notification urls on every transaction. It can be achieved by adding additional HTTP headers into charge request.\n\nThere are two headers we provide:\n\n1. `X-Append-Notification`: to add new notification url(s) alongside the settings on dashboard\n2. `X-Override-Notification`: to use new notification url(s) disregarding the settings on dashboard\nBoth header can only receive up to maximum of 3 urls.\n\n[More details](https://api-docs.midtrans.com/#override-notification-url)\n\n```java\n//X-Append-Notification\nConfig configOptions = Config.builder()\n     .setPaymentAppendNotification(\"https://example.com/test1,https://example.com/test\")\n     .build();\n        \nCoreApi.chargeTransaction(param, configOptions);\n\n//X-Override-Notification\nConfig configOptions = Config.builder()\n     .setPaymentOverrideNotification(\"https://example.com/test1,https://example.com/test\")\n     .build();;\n\nCoreApi.chargeTransaction(param, configOptions);\n```\nWhen both `X-Append-Notification` and `X-Override-Notification` are used together then only override will be used.\n\n### Handling Error / Exception\nWhen using function that result in Midtrans API call e.g: CoreApi.chargeTransaction(...) or SnapApi.createTransaction(...) there's a chance it may throw error (MidtransError object), the error object will contains below properties that can be used as information to your error handling logic:\n```java\ntry {\n    JSONObject result = CoreApi.chargeTransaction(param);\n} catch (MidtransError e) {\n    e.printStackTrace();\n    e.getStatusCode(); // basic error message string\n    e.getMessage(); // HTTP status code e.g: 400, 401, etc.\n    e.getResponseBody(); // API response body\n    e.getResponse(); // raw OkHttp response object\n}\n```\n#### CoreAPI Simple Sample Usage\n```java\nimport com.midtrans.httpclient.CoreApi;\nimport com.midtrans.httpclient.error.MidtransError;\nimport com.midtrans.Midtrans;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.UUID;\nimport org.json.JSONObject;\n\n\npublic class MidtransExample {\n\n    public static void main(String[] args) throws MidtransError {\n        Midtrans.serverKey = \"YOUR_SERVER_KEY\";\n        Midtrans.isProduction = false;\n\n        UUID idRand = UUID.randomUUID();\n        Map\u003cString, Object\u003e chargeParams = new HashMap\u003c\u003e();\n\n        Map\u003cString, String\u003e transactionDetails = new HashMap\u003c\u003e();\n        transactionDetails.put(\"order_id\", idRand.toString());\n        transactionDetails.put(\"gross_amount\", \"265000\");\n\n        chargeParams.put(\"transaction_details\", transactionDetails);\n        chargeParams.put(\"payment_type\", \"gopay\");\n        \n            JSONObject result = CoreApi.chargeTransaction(chargeParams);\n            System.out.println(result);\n    }\n}\n```\n\n### 2.2.A Snap\nYou can see Snap example [here](example/src/main/java/com/midtrans/sample/controller/SnapController.java).\n\nAvailable methods for `MidtransSnapApi` class\n```java\n//1. To get snap transaction with return json raw object\nJSONObject createTransaction(Map\u003cString, Object\u003e params);\n\n//2. To get snap token with return String token\nString createTransactionToken(Map\u003cString, Object\u003e params);\n\n//3. To get snap redirect url with return String redirect url\nString createTransactionRedirectUrl(Map\u003cString, Object\u003e params);\n```\n`params` is Map Object or String of JSON of [SNAP Parameter](https://snap-docs.midtrans.com/#json-objects)\n\n\n#### Get Snap Token\n\n```java\n// Create new Object SnapAPI\nMidtransSnapApi snapApi = new ConfigFactory(new Config(\"YOU_SERVER_KEY\",\"YOUR_CLIENT_KEY\", false)).getSnapApi();\n\n// Create params JSON Raw Object request\npublic Map\u003cString, Object\u003e requestBody() {\n    UUID idRand = UUID.randomUUID();\n    Map\u003cString, Object\u003e params = new HashMap\u003c\u003e();\n    \n    Map\u003cString, String\u003e transactionDetails = new HashMap\u003c\u003e();\n    transactionDetails.put(\"order_id\", idRand);\n    transactionDetails.put(\"gross_amount\", \"265000\");\n    \n    Map\u003cString, String\u003e creditCard = new HashMap\u003c\u003e();\n    creditCard.put(\"secure\", \"true\");\n    \n    params.put(\"transaction_details\", transactionDetails);\n    params.put(\"credit_card\", creditCard);\n    \n    return params;\n}\n\n// Create Token and then you can send token variable to FrontEnd,\n// to initialize Snap JS when customer click pay button\nString transactionToken = snapApi.createTransactionToken(requestBody())\n\n//you can use Model object in springboot controller to send token to FrontEnd\nmodel.addAttribute(\"transactionToken\", transactionToken);\n```\n\n\n#### Initialize Snap JS when customer click pay button\n\nOn frontend / html:\nReplace `PUT_TRANSACTION_TOKEN_HERE` with `transactionToken` acquired above, you can use java template engine like Thymeleaf to parse `transactionToken` to frontEnd like [this](https://github.com/Xaxxis/midtrans-java/blob/master/example/src/main/resources/templates/snap/check-out.html#L90) `[[${transactionToken}]]`\n```html\n\u003chtml\u003e\n  \u003cbody\u003e\n    \u003cbutton id=\"pay-button\"\u003ePay!\u003c/button\u003e\n    \u003cpre\u003e\u003cdiv id=\"result-json\"\u003eJSON result will appear here after payment:\u003cbr\u003e\u003c/div\u003e\u003c/pre\u003e \n\n\u003c!-- TODO: Remove \".sandbox\" from script src URL for production environment. Also input your client key in \"data-client-key\" --\u003e\n    \u003cscript src=\"https://app.sandbox.midtrans.com/snap/snap.js\" data-client-key=\"\u003cSet your ClientKey here\u003e\"\u003e\u003c/script\u003e\n    \u003cscript type=\"text/javascript\"\u003e\n      document.getElementById('pay-button').onclick = function(){\n        // SnapToken acquired from previous step\n        snap.pay('PUT_TRANSACTION_TOKEN_HERE', {\n          // Optional\n          onSuccess: function(result){\n            /* You may add your own js here, this is just example */ document.getElementById('result-json').innerHTML += JSON.stringify(result, null, 2);\n          },\n          // Optional\n          onPending: function(result){\n            /* You may add your own js here, this is just example */ document.getElementById('result-json').innerHTML += JSON.stringify(result, null, 2);\n          },\n          // Optional\n          onError: function(result){\n            /* You may add your own js here, this is just example */ document.getElementById('result-json').innerHTML += JSON.stringify(result, null, 2);\n          }\n        });\n      };\n    \u003c/script\u003e\n  \u003c/body\u003e\n\u003c/html\u003e\n```\n\n#### Implement Notification Handler\n[Refer to this section](#23-handle-http-notification)\n\n### 2.2.B Snap Redirect\n\nAlso available as examples [here](example/src/main/java/com/midtrans/sample/controller/SnapController.java).\n\n#### Get Redirection URL of a Payment Page\n\n```java\n// Create new Object SnapAPI\nMidtransSnapApi snapApi = new ConfigFactory(new Config(\"YOU_SERVER_KEY\",\"YOUR_CLIENT_KEY\", false)).getSnapApi();\n\n// Create params JSON Raw Object request\npublic Map\u003cString, Object\u003e requestBody() {\n    UUID idRand = UUID.randomUUID();\n    Map\u003cString, Object\u003e params = new HashMap\u003c\u003e();\n    \n    Map\u003cString, String\u003e transactionDetails = new HashMap\u003c\u003e();\n    transactionDetails.put(\"order_id\", idRand);\n    transactionDetails.put(\"gross_amount\", \"265000\");\n    \n    Map\u003cString, String\u003e creditCard = new HashMap\u003c\u003e();\n    creditCard.put(\"secure\", \"true\");\n    \n    params.put(\"transaction_details\", transactionDetails);\n    params.put(\"credit_card\", creditCard);\n    \n    return params;\n}\n\n// Create Token and then you can send token variable to FrontEnd,\n// to initialize Snap JS when customer click pay button\nString redirectURL = snapApi.createTransactionRedirectUrl(requestBody())\n\n//you can return to redirectURL on springboot controller\nreturn \"redirect:\" +redirectURL;\n```\n#### Implement Notification Handler\n[Refer to this section](#23-handle-http-notification)\n\n### 2.2.C Core API (VT-Direct)\n\nYou can see Core API examples [here](example/src/main/java/com/midtrans/sample/controller/CoreApiController.java).\n\nAvailable methods for `MidtransCoreApi` class\n```java\n    /**\n     * Do re-set config Class like clientKey, serverKey, isProduction\n     * @return {Config class}\n     */\n    Config apiConfig();\n\n    /**\n    * Do `/charge` API request to Core API\n    * @param  {Map Object} parameter - object of Core API JSON body as parameter, will be converted to JSON (more params detail refer to: https://api-docs.midtrans.com)\n    * @return {JSONObject} - org.json Promise contains Object from JSON decoded response\n    */\n    JSONObject chargeTransaction(Map\u003cString, Object\u003e params);\n\n    /**\n     * Do `/\u003corderId\u003e/status` API request to Core API\n     * @param  {String} orderId - orderId of the transaction (more detail refer to: https://api-docs.midtrans.com)\n     * @return {JSONObject} - org.json Promise contains Object from JSON decoded response\n     */\n    JSONObject checkTransaction(String orderId);\n\n    /**\n     * Do `/\u003corderId\u003e/approve` API request to Core API\n     * @param  {String} orderId - orderId of the transaction (more detail refer to: https://api-docs.midtrans.com)\n     * @return {JSONObject} - org.json Promise contains Object from JSON decoded response\n     */\n    JSONObject approveTransaction(String orderId);\n\n    /**\n     * Do `/\u003corderId\u003e/cancel` API request to Core API\n     * @param  {String} orderId - orderId of the transaction (more detail refer to: https://api-docs.midtrans.com)\n     * @return {JSONObject} - org.json Promise contains Object from JSON decoded response\n     */\n    JSONObject cancelTransaction(String orderId);\n\n    /**\n     * Do `/\u003corderId\u003e/expire` API request to Core API\n     * @param  {String} orderId - orderId of the transaction (more detail refer to: https://api-docs.midtrans.com)\n     * @return {JSONObject} - org.json Promise contains Object from JSON decoded response\n     */\n    JSONObject expireTransaction(String orderId);\n\n    /**\n     * Do `/\u003corderId\u003e/refund` API request to Core API\n     * @param  {String} orderId - orderId of the transaction (more detail refer to: https://api-docs.midtrans.com)\n     * @param  {Map Object} parameter - object of Core API JSON body as parameter, will be converted to JSON (more params detail refer to: https://api-docs.midtrans.com)\n     * @return {JSONObject} - org.json Promise contains Object from JSON decoded response\n     */\n    JSONObject refundTransaction(String orderId, Map\u003cString, String\u003e params);\n\n    /**\n     * Do `/token` API request to Core API\n     * @param  {Map Object} parameter - object of Core API JSON body as parameter, will be converted to JSON (more params detail refer to: https://api-docs.midtrans.com)\n     * @return {JSONObject} - org.json Promise contains Object from JSON decoded response\n     */\n    JSONObject cardToken(Map\u003cString, String\u003e params);\n\n    /**\n     * Do `/card/register` API request to Core API\n     * @param  {Map Object} parameter - object of Core API JSON body as parameter, will be converted to JSON (more params detail refer to: https://api-docs.midtrans.com)\n     * @return {JSONObject} - org.json Promise contains Object from JSON decoded response\n     */\n    JSONObject registerCard(Map\u003cString, String\u003e params);\n\n    /**\n     * Do `/point_inquiry/\u003ctokenId\u003e` API request to Core API\n     * @param  {String} tokenId - tokenId of credit card (more detail refer to: https://api-docs.midtrans.com)\n     * @return {JSONObject} - org.json Promise contains Object from JSON decoded response\n     */\n    JSONObject cardPointInquiry(String tokenId);\n    \n    /**\n     * Do `/\u003corderId\u003e/deny` API request to Core API\n     * @param {String} orderId - orderId of the transaction (more detail refer to: https://api-docs.midtrans.com/#deny-transaction)\n     * @return {JSONObject} - org.json Promise contains Object from JSON decoded response\n     */\n    JSONObject denyTransaction(String orderId);\n    \n    /**\n     * Do `v1/bins/{bin}` API request to Core API\n     * @param binNumber {String} of the transaction (more detail refer to: https://api-docs.midtrans.com/#bin-api)\n     * @return {JSONObject} - org.json Promise contains Object from JSON decoded response\n     * @throws MidtransError when an exception was occurred during executing the request.\n     */\n    JSONObject getBIN(String binNumber) throws MidtransError;\n```\n`params` is Map Object or String of JSON of [Core API Parameter](https://api-docs.midtrans.com/#json-objects)\n\n#### Credit Card Get Token\n\nGet token should be handled on  Frontend please refer to [API docs](https://api-docs.midtrans.com)\n\n#### Credit Card Charge\n\n```java\nMidtransCoreApi coreApi = new ConfigFactory(new Config(\"YOU_SERVER_KEY\",\"YOUR_CLIENT_KEY\", false)).getCoreApi();\n\n\n// Create Function JSON Raw Object\npublic Map\u003cString, Object\u003e requestBody() {\n    UUID idRand = UUID.randomUUID();\n    Map\u003cString, Object\u003e params = new HashMap\u003c\u003e();\n    \n    Map\u003cString, String\u003e transactionDetails = new HashMap\u003c\u003e();\n    transactionDetails.put(\"order_id\", idRand);\n    transactionDetails.put(\"gross_amount\", \"265000\");\n    \n    Map\u003cString, String\u003e creditCard = new HashMap\u003c\u003e();\n    creditCard.put(\"token_id\", YOUR_TOKEN_ID);\n    creditCard.put(\"authentication\", \"true\");\n    \n    params.put(\"transaction_details\", transactionDetails);\n    params.put(\"credit_card\", creditCard);\n    \n    return params;\n}\n\n// charge transaction\nJSONObject result = coreApi.chargeTransaction(requestBody());\nSystem.out.println(result);\n```\n\n#### Credit Card 3DS Authentication\n\nThe credit card charge result may contains `redirect_url` for 3DS authentication. 3DS Authentication should be handled on Frontend please refer to [API docs](https://api-docs.midtrans.com/#card-features-3d-secure)\n\nFor full example on Credit Card 3DS transaction refer to:\n- [App examples](example/src/main/java/com/midtrans/sample) that implement Snap \u0026 Core Api\n\n### 2.3 Handle HTTP Notification\n\n\u003e **IMPORTANT NOTE**: To update transaction status on your backend/database, **DO NOT** solely rely on frontend callbacks! For security reason to make sure the status is authentically coming from Midtrans, only update transaction status based on HTTP Notification or API Get Status.\n\nCreate separated web endpoint (notification url) to receive HTTP POST notification callback/webhook. \nHTTP notification will be sent whenever transaction status is changed.\nExample also available [here](example/src/main/java/com/midtrans/sample/controller/CoreApiController.java)\n\n```java\n@PostMapping(value = \"/notification\", produces = MediaType.APPLICATION_JSON_VALUE)\n    private ResponseEntity\u003cString\u003e handleNotification(@RequestBody Map\u003cString, Object\u003e response) throws MidtransError {\n        String notifResponse = null;\n        if (!(response.isEmpty())) {\n            //Get Order ID from notification body\n            String orderId = (String) response.get(\"order_id\");\n\n            // Get status transaction to api with order id\n            JSONObject transactionResult = coreApi.checkTransaction(orderId);\n\n            String transactionStatus = (String) transactionResult.get(\"transaction_status\");\n            String fraudStatus = (String) transactionResult.get(\"fraud_status\");\n\n            notifResponse = \"Transaction notification received. Order ID: \" + orderId + \". Transaction status: \" + transactionStatus + \". Fraud status: \" + fraudStatus;\n            System.out.println(notifResponse);\n\n            if (transactionStatus.equals(\"capture\")) {\n                if (fraudStatus.equals(\"challenge\")) {\n                    // TODO set transaction status on your database to 'challenge' e.g: 'Payment status challenged. Please take action on your Merchant Administration Portal\n                } else if (fraudStatus.equals(\"accept\")) {\n                    // TODO set transaction status on your database to 'success'\n                }\n            } else if (transactionStatus.equals(\"cancel\") || transactionStatus.equals(\"deny\") || transactionStatus.equals(\"expire\")) {\n                // TODO set transaction status on your database to 'failure'\n            } else if (transactionStatus.equals(\"pending\")) {\n                // TODO set transaction status on your database to 'pending' / waiting payment\n            }\n        }\n        return new ResponseEntity\u003c\u003e(notifResponse, HttpStatus.OK);\n    }\n```\n\n### 2.4 Transaction Action\nAlso available as examples [here](example/src/main/java/com/midtrans/sample/controller/CoreApiController.java)\n#### Get Status\n```java\n// get status of transaction that already recorded on midtrans (already `charge`-ed) \nJSONObject result = checkTransaction(\"YOUR_ORDER_ID OR TRANSACTION_ID\");\n    //do something with `result` JSON Raw Object\n```\n#### Get Status B2B\n```java\n// get transaction status of VA b2b transaction\nJSONObject result = getTransactionStatusB2B(\"YOUR_ORDER_ID OR TRANSACTION_ID\");\n    //do something with `result` JSON Raw Object\n```\n#### Approve Transaction\n```java\n// approve a credit card transaction with `challenge` fraud status\nJSONObject result = approveTransaction(\"YOUR_ORDER_ID OR TRANSACTION_ID\");\n    //do something with `result` JSON Raw Object\n```\n#### Deny Transaction\n```java\n// deny a credit card transaction with `challenge` fraud status\nJSONObject result = denyTransaction(\"YOUR_ORDER_ID OR TRANSACTION_ID\");\n    //do something with `result` JSON Raw Object\n```\n#### Cancel Transaction\n```java\nJSONObject result = cancelTransaction(\"YOUR_ORDER_ID OR TRANSACTION_ID\");\n    //do something with `result` JSON Raw Object\n```\n#### Expire Transaction\n```java\nJSONObject result = expireTransaction(\"YOUR_ORDER_ID OR TRANSACTION_ID\");\n    //do something with `result` JSON Raw Object\n```\n#### Refund Transaction\n```java\n//Make params with Map Object\nprivate Map\u003cString,String\u003e params() {\n    params.put(\"amount\", \"5000\");\n    params.put(\"reason\", \"Item out of stock\");\n    return params;\n}\n\nJSONObject refundTransaction(\"YOUR_ORDER_ID OR TRANSACTION_ID\", params());\n    //do something with `result` JSON Raw Object\n```\n### 2.2.D Iris API (Disbursement)\nYou can see Iris API examples [here](example/src/main/java/com/midtrans/sample/controller/IrisController.java).\n\n#### IrisAPI Simple Sample Usage\n```java\n\nimport com.midtrans.Config;\nimport com.midtrans.ConfigFactory;\nimport com.midtrans.service.MidtransIrisApi;\nimport com.midtrans.httpclient.error.MidtransError;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.UUID;\nimport org.json.JSONObject;\n\npublic class MidtransIrisExample {\n\n    public static void main(String[] args) throws MidtransError {\n        MidtransIrisApi irisApi = new ConfigFactory(new Config(\"IRIS-CREDENTIALS\", null, false)).getIrisApi();\n        \n        Map\u003cString, String\u003e beneficiary = new HashMap\u003c\u003e();\n            beneficiary.put(\"bank\", \"bca\");\n            beneficiary.put(\"name\", \"PT Jon Snow\");\n            beneficiary.put(\"alias_name\", \"ptjonsnow\");\n            beneficiary.put(\"account\", \"1145532134\");\n            beneficiary.put(\"email\", \"jonsnow@mail.com\");\n\n        // Optional - Use idempotency key\n        irisApi.apiConfig().setIrisIdempotencyKey(\"Iris-Idempotency-Key\");\n        \n        // Request create beneficiary to Iris API\n        JSONObject result = irisApi.createBeneficiaries(beneficiary);\n        System.out.println(result);\n    }\n}\n```\n\nAvailable methods for `MidtransIrisApi` class\n```java\n    /**\n     * Do re-set config Class iris-credential, IrisIdempotencyKey\n     *\n     * @return {Config class}\n     */\n    Config apiConfig();\n\n    /**\n     * Do `/ping` Returns pong message for monitoring purpose\n     *\n     * @return {String} - with value Pong\n     * @throws MidtransError when an exception was occurred during executing the request.\n     */\n    String ping() throws MidtransError;\n\n    /**\n     * Do get `/balance` API request to Use get current balance information. For Aggregator Partner you need to top up to Iris’ bank account.\n     *\n     * @return {JSONObject} - org.json Promise contains Object from JSON decoded response refer to: https://iris-docs.midtrans.com/#check-balance-aggregator\n     * @throws MidtransError when an exception was occurred during executing the request.\n     */\n    JSONObject getBalance() throws MidtransError;\n\n    /**\n     * Do create `/beneficiaries` Use this API to create a new beneficiary information for quick access on the payout page in Iris Portal.\n     *\n     * @param params Map Object parameter, object of Core API JSON body as parameter, will be converted to JSON (more params detail refer to: https://iris-docs.midtrans.com/#create-beneficiaries)\n     * @return {JSONObject} - org.json Promise contains Object from JSON decoded response\n     * @throws MidtransError when an exception was occurred during executing the request.\n     */\n    JSONObject createBeneficiaries(Map\u003cString, String\u003e params) throws MidtransError;\n\n    /**\n     * Do update `/beneficiaries/{alias_name}` Use this API to update an existing beneficiary identified by it's `alias_name`.\n     *\n     * @param aliasName Alias name used by the Beneficiary. Length should be less than or equal to 20 characters only alphanumeric characters are allowed\n     * @param params    Map Object parameter, object of Core API JSON body as parameter, will be converted to JSON (more params detail refer to: https://iris-docs.midtrans.com/#update-beneficiaries)\n     * @return {JSONObject} - org.json Promise contains Object from JSON decoded response\n     * @throws MidtransError when an exception was occurred during executing the request.\n     */\n    JSONObject updateBeneficiaries(String aliasName, Map\u003cString, String\u003e params) throws MidtransError;\n\n    /**\n     * Do get `/beneficiaries` Use this API to fetch list of all beneficiaries saved in Iris Portal.\n     *\n     * @return {JSONObject} - org.json Promise contains Object from JSON decoded response refer to: https://iris-docs.midtrans.com/#list-beneficiaries\n     * @throws MidtransError when an exception was occurred during executing the request.\n     */\n    JSONArray getBeneficiaries() throws MidtransError;\n\n    /**\n     * Do create `/payouts` This API is for Creator to create a payout. It can be used for single payout and also multiple payouts.\n     *\n     * @param params Map Object parameter, object of Core API JSON body as parameter, will be converted to JSON (more params detail refer to: https://iris-docs.midtrans.com/#create-payouts)\n     * @return {JSONObject} - org.json Promise contains Object from JSON decoded response\n     * @throws MidtransError when an exception was occurred during executing the request.\n     */\n    JSONObject createPayouts(Map\u003cString, Object\u003e params) throws MidtransError;\n\n    /**\n     * Do approve `/payouts/approve` Use this API for Apporver to approve multiple payout request.\n     *\n     * @param params Map Object parameter, object of Core API JSON body as parameter, will be converted to JSON (more params detail refer to: https://iris-docs.midtrans.com/#approve-payouts)\n     * @return {JSONObject} - org.json Promise contains Object from JSON decoded response\n     * @throws MidtransError when an exception was occurred during executing the request.\n     */\n    JSONObject approvePayouts(Map\u003cString, Object\u003e params) throws MidtransError;\n\n    /**\n     * Do reject `/payouts/reject` Use this API for Apporver to reject multiple payout request.\n     *\n     * @param params Map Object parameter, object of Core API JSON body as parameter, will be converted to JSON (more params detail refer to: https://iris-docs.midtrans.com/#reject-payouts)\n     * @return {JSONObject} - org.json Promise contains Object from JSON decoded response\n     * @throws MidtransError when an exception was occurred during executing the request.\n     */\n    JSONObject rejectPayouts(Map\u003cString, Object\u003e params) throws MidtransError;\n\n    /**\n     * Do get `/payouts/{reference_no}` Use this API for get details of a single payout\n     *\n     * @param referenceNo String parameter, unique reference no of a payout (more params detail refer to: https://iris-docs.midtrans.com/#get-payout-details)\n     * @return {JSONObject} - org.json Promise contains Object from JSON decoded response\n     * @throws MidtransError when an exception was occurred during executing the request.\n     */\n    JSONObject getPayoutDetails(String referenceNo) throws MidtransError;\n\n    /**\n     * Do get `/statements` Use this API for list all transactions history for a month. You can specified start date and also end date for range transaction history.\n     *\n     * @param fromDate String date parameter, start date range for payouts (YYYY-MM-DD) more params detail refer to: https://iris-docs.midtrans.com/#transaction-history\n     * @param toDate   String date parameter, end date range for payouts (YYYY-MM-DD) more params detail refer to: https://iris-docs.midtrans.com/#get-payout-details\n     * @return {JSONObject} - org.json Promise contains Object from JSON decoded response\n     * @throws MidtransError when an exception was occurred during executing the request.\n     */\n    JSONArray getTransactionHistory(String fromDate, String toDate) throws MidtransError;\n\n    /**\n     * Do get `/channels` Use this API for get top up information channel only for Aggregator Partner\n     *\n     * @return {JSONObject} - org.json Promise contains Object from JSON decoded response (more params detail refer to: https://iris-docs.midtrans.com/#top-up-channel-information-aggregator)\n     * @throws MidtransError when an exception was occurred during executing the request.\n     */\n    JSONArray getTopUpChannels() throws MidtransError;\n\n    /**\n     * Do get `/bank_accounts` Use this API for show list of registered bank accounts for facilitator partner\n     *\n     * @return {JSONObject} - org.json Promise contains Object from JSON decoded response (more params detail refer to: https://iris-docs.midtrans.com/#bank-accounts-facilitator)\n     * @throws MidtransError when an exception was occurred during executing the request.\n     */\n    JSONArray getBankAccounts() throws MidtransError;\n\n    /**\n     * Do get `/bank_accounts/{bank_account_id}/balance` For Facilitator Partner, use this API is to get current balance information of your registered bank account.\n     *\n     * @param bankAccountId String Bank Account Number\n     * @return {JSONObject} - org.json Promise contains Object from JSON decoded response refer to: https://iris-docs.midtrans.com/#check-balance-facilitator\n     * @throws MidtransError when an exception was occurred during executing the request.\n     */\n    JSONObject getFacilitatorBalance(String bankAccountId) throws MidtransError;\n\n    /**\n     * Do get `/beneficiary_banks` Use this API for show list of supported banks in IRIS. https://iris-docs.midtrans.com/#supported-banks\n     *\n     * @return {JSONObject} - org.json Promise contains Object from JSON decoded response (more params detail refer to: https://iris-docs.midtrans.com/#list-banks)\n     * @throws MidtransError when an exception was occurred during executing the request.\n     */\n    JSONObject getBeneficiaryBanks() throws MidtransError;\n\n    /**\n     * Do validate `/account_validation` Use this API for check if an account is valid, if valid return account information.\n     *\n     * @param bank    String bank code\n     * @param account String Account number\n     * @return {JSONObject} - org.json Promise contains Object from JSON decoded response (more params detail refer to: https://iris-docs.midtrans.com/#validate-bank-account)\n     * @throws MidtransError when an exception was occurred during executing the request.\n     */\n    JSONObject validateBankAccount(String bank, String account) throws MidtransError;\n```\n## 3. Snap-BI (*NEW FEATURE starting v3.2.0)\nStandar Nasional Open API Pembayaran, or in short SNAP, is a national payment open API standard published by Bank Indonesia. To learn more you can read this [docs](https://docs.midtrans.com/reference/core-api-snap-open-api-overview)\n\n### 3.1 General Settings\n\n```java\n//These config value are based on the header stated here https://docs.midtrans.com/reference/getting-started-1\n// Set to Development/Sandbox Environment (default). Set to true for Production Environment (accept real transaction).\nSnapBiConfig.setProduction(true);\n// Set your client id. Merchant’s client ID that will be given by Midtrans, will be used as X-CLIENT-KEY on request’s header in B2B Access Token API.\nSnapBiConfig.setSnapBiClientId(\"YOUR CLIENT ID\");\n// Set your private key here, make sure to add \\n on the private key, you can refer to the examples\nSnapBiConfig.setSnapBiPrivateKey(\"YOUR PRIVATE KEY\");\n// Set your client secret. Merchant’s secret key that will be given by Midtrans, will be used for symmetric signature generation for Transactional API’s header.\nSnapBiConfig.setSnapBiClientSecret(\"YOUR CLIENT SECRET\");\n// Set your partner id. Merchant’s partner ID that will be given by Midtrans, will be used as X-PARTNER-ID on Transactional API’s header.\nSnapBiConfig.setSnapBiPartnerId(\"YOUR PARTNER ID\");\n// Set the channel id here.\nSnapBiConfig.setSnapBiChannelId(\"YOUR CHANNEL ID\");\n// Enable logging to see details of the request/response make sure to disable this on production, the default is disabled.\nSnapBiConfig.setEnableLogging(true);\n// Set your public key here if you want to verify your webhook notification, make sure to add \\n on the public key, you can refer to the examples\nSnapBiConfig.setSnapBiPublicKey(\"YOUR PUBLIC KEY\");\n```\n\n### 3.2 Create Payment\n\n#### 3.2.1 Direct Debit (Gopay, Dana, Shopeepay)\nRefer to this [docs](https://docs.midtrans.com/reference/direct-debit-api-gopay) for more detailed information about creating payment using direct debit.\n\n```java\n\n// Create the top-level map of request body\npublic Map\u003cString, Object\u003e createDirectDebitRequestBody() {\n    // Create the top-level map\n    Map\u003cString, Object\u003e requestBody = new HashMap\u003c\u003e();\n\n    // Add partnerReferenceNo and other fields\n    requestBody.put(\"partnerReferenceNo\", externalId);\n    requestBody.put(\"chargeToken\", \"\");\n    requestBody.put(\"merchantId\", merchantId);\n    requestBody.put(\"validUpTo\", \"2030-07-20T20:34:15.452305Z\");\n\n    // Create and add urlParam map\n    Map\u003cString, String\u003e urlParam = new HashMap\u003c\u003e();\n    urlParam.put(\"url\", \"https://midtrans-test.com/api/notification\");\n    urlParam.put(\"type\", \"PAY_RETURN\");\n    urlParam.put(\"isDeeplink\", \"N\");\n    requestBody.put(\"urlParam\", urlParam);\n\n    // Create and add payOptionDetails list\n    List\u003cMap\u003cString, Object\u003e\u003e payOptionDetails = new ArrayList\u003c\u003e();\n    Map\u003cString, Object\u003e payOptionDetail = new HashMap\u003c\u003e();\n    payOptionDetail.put(\"payMethod\", \"GOPAY\");\n    payOptionDetail.put(\"payOption\", \"GOPAY_WALLET\");\n\n    // Create and add transAmount map\n    Map\u003cString, String\u003e transAmount = new HashMap\u003c\u003e();\n    transAmount.put(\"value\", \"1500\");\n    transAmount.put(\"currency\", \"IDR\");\n    payOptionDetail.put(\"transAmount\", transAmount);\n\n    payOptionDetails.add(payOptionDetail);\n    requestBody.put(\"payOptionDetails\", payOptionDetails);\n\n    // Create and add additionalInfo map\n    Map\u003cString, Object\u003e additionalInfo = new HashMap\u003c\u003e();\n\n    // Create and add customerDetails map\n    Map\u003cString, Object\u003e customerDetails = new HashMap\u003c\u003e();\n    customerDetails.put(\"firstName\", \"Merchant\");\n    customerDetails.put(\"lastName\", \"Operation\");\n    customerDetails.put(\"email\", \"merchant-ops@midtrans.com\");\n    customerDetails.put(\"phone\", \"+6281932358123\");\n\n    // Create and add billingAddress map\n    Map\u003cString, String\u003e billingAddress = new HashMap\u003c\u003e();\n    billingAddress.put(\"firstName\", \"Merchant\");\n    billingAddress.put(\"lastName\", \"Operation\");\n    billingAddress.put(\"phone\", \"+6281932358123\");\n    billingAddress.put(\"address\", \"Pasaraya Blok M\");\n    billingAddress.put(\"city\", \"Jakarta\");\n    billingAddress.put(\"postalCode\", \"12160\");\n    billingAddress.put(\"countryCode\", \"IDN\");\n    customerDetails.put(\"billingAddress\", billingAddress);\n\n    // Create and add shippingAddress map\n    Map\u003cString, String\u003e shippingAddress = new HashMap\u003c\u003e();\n    shippingAddress.put(\"firstName\", \"Merchant\");\n    shippingAddress.put(\"lastName\", \"Operation\");\n    shippingAddress.put(\"phone\", \"+6281932358123\");\n    shippingAddress.put(\"address\", \"Pasaraya Blok M\");\n    shippingAddress.put(\"city\", \"Jakarta\");\n    shippingAddress.put(\"postalCode\", \"12160\");\n    shippingAddress.put(\"countryCode\", \"IDN\");\n    customerDetails.put(\"shippingAddress\", shippingAddress);\n\n    additionalInfo.put(\"customerDetails\", customerDetails);\n\n    // Create and add items list\n    List\u003cMap\u003cString, Object\u003e\u003e items = new ArrayList\u003c\u003e();\n    Map\u003cString, Object\u003e item = new HashMap\u003c\u003e();\n    item.put(\"id\", \"8143fc4f-ec05-4c55-92fb-620c212f401e\");\n\n    // Create and add price map\n    Map\u003cString, String\u003e price = new HashMap\u003c\u003e();\n    price.put(\"value\", \"1500.00\");\n    price.put(\"currency\", \"IDR\");\n    item.put(\"price\", price);\n\n    item.put(\"quantity\", 1);\n    item.put(\"name\", \"test item name\");\n    item.put(\"brand\", \"test item brand\");\n    item.put(\"category\", \"test item category\");\n    item.put(\"merchantName\", \"Merchant Operation\");\n\n    items.add(item);\n    additionalInfo.put(\"items\", items);\n\n    requestBody.put(\"additionalInfo\", additionalInfo);\n\n    return requestBody;\n}\n/**\n *  Basic example\n * to change the payment method, you can change the value of the request body on the `payOptionDetails`\n * the `currency` value that we support for now is only `IDR`\n */\nJSONObject snapBiResponse1 = SnapBi.directDebit()\n        .withBody(createDirectDebitRequestBody)\n        .createPayment(externalId);\n\n```\n#### 3.2.2 VA (Bank Transfer)\nRefer to this [docs](https://docs.midtrans.com/reference/virtual-account-api-bank-transfer) for more detailed information about VA/Bank Transfer.\n```java\n\n//function to create request body\npublic Map\u003cString, Object\u003e createVaRequestBody() {\n    // Create the top-level map\n    Map\u003cString, Object\u003e requestBody = new HashMap\u003c\u003e();\n\n    // Create and add transAmount map\n    Map\u003cString, Object\u003e totalAmount = new HashMap\u003c\u003e();\n    totalAmount.put(\"value\", \"1500.00\");\n    totalAmount.put(\"currency\", \"IDR\");\n    requestBody.put(\"totalAmount\", totalAmount);\n\n    Map\u003cString, Object\u003e flags = new HashMap\u003c\u003e();\n    flags.put(\"shouldRandomizeVaNumber\", true);\n\n    Map\u003cString, Object\u003e billingAddress = new HashMap\u003c\u003e();\n    billingAddress.put(\"firstName\", \"Merchant\");\n    billingAddress.put(\"lastName\", \"Operation\");\n    billingAddress.put(\"phone\", \"+6281932358123\");\n    billingAddress.put(\"address\", \"Pasaraya Blok M\");\n    billingAddress.put(\"city\", \"Jakarta\");\n    billingAddress.put(\"postalCode\", \"12160\");\n    billingAddress.put(\"countryCode\", \"IDN\");\n\n    Map\u003cString, Object\u003e shippingAddress = new HashMap\u003c\u003e();\n    shippingAddress.put(\"firstName\", \"Merchant\");\n    shippingAddress.put(\"lastName\", \"Operation\");\n    shippingAddress.put(\"phone\", \"6281932358123\");\n    shippingAddress.put(\"address\", \"Pasaraya Blok M\");\n    shippingAddress.put(\"city\", \"Jakarta\");\n    shippingAddress.put(\"postalCode\", \"12160\");\n    shippingAddress.put(\"countryCode\", \"IDN\");\n\n\n    Map\u003cString, Object\u003e customerDetails = new HashMap\u003c\u003e();\n    customerDetails.put(\"firstName\", \"Merchant\");\n    customerDetails.put(\"lastName\", \"Operation\");\n    customerDetails.put(\"email\", \"merchant-ops@midtrans.com\");\n    customerDetails.put(\"phone\", \"+6281932358123\");\n    customerDetails.put(\"billingAddress\", billingAddress);\n    customerDetails.put(\"shippingAddress\", shippingAddress);\n\n    List\u003cMap\u003cString, Object\u003e\u003e items = new ArrayList\u003c\u003e();\n    Map\u003cString, Object\u003e item = new HashMap\u003c\u003e();\n    item.put(\"id\", \"8143fc4f-ec05-4c55-92fb-620c212f401e\");\n    // Create and add price map\n    Map\u003cString, Object\u003e price = new HashMap\u003c\u003e();\n    price.put(\"value\", \"1500.00\");\n    price.put(\"currency\", \"IDR\");\n    item.put(\"price\", price);\n\n    item.put(\"quantity\", 1);\n    item.put(\"name\", \"test item name\");\n    item.put(\"brand\", \"test item brand\");\n    item.put(\"category\", \"test item category\");\n    item.put(\"merchantName\", \"Merchant Operation\");\n\n    items.add(item);\n\n    Map\u003cString, Object\u003e additionalInfo = new HashMap\u003c\u003e();\n    additionalInfo.put(\"merchantId\", merchantId);\n    additionalInfo.put(\"bank\", \"bca\");\n    additionalInfo.put(\"flags\", flags);\n    additionalInfo.put(\"customerDetails\", customerDetails);\n    additionalInfo.put(\"shippingAddress\", shippingAddress);\n    additionalInfo.put(\"billingAddress\", billingAddress);\n    additionalInfo.put(\"items\", items);\n\n    requestBody.put(\"partnerServiceId\", \"    1234\");\n    requestBody.put(\"customerNo\", \"0000000000\");\n    requestBody.put(\"virtualAccountNo\", \"    12340000000000\");\n    requestBody.put(\"virtualAccountName\", \"Merchant Operation\");\n    requestBody.put(\"virtualAccountEmail\", \"merchant-ops@midtrans.com\");\n    requestBody.put(\"virtualAccountPhone\", \"6281932358123\");\n    requestBody.put(\"trxId\", externalId);\n    requestBody.put(\"additionalInfo\", additionalInfo);\n\n    return requestBody;\n}\n\n/**\n * basic implementation to create payment using va\n */\nJSONObject snapBiResponse1 = SnapBi.va()\n        .withBody(createVaRequestBody())\n        .createPayment(externalId);\n```\n#### 3.2.3 Qris\nRefer to this [docs](https://docs.midtrans.com/reference/mpm-api-qris) for more detailed information about Qris.\n```java\n\n//function to create the request body\npublic static Map\u003cString, Object\u003e createQrisRequestBody() {\n    // Create the top-level map\n    Map\u003cString, Object\u003e requestBody = new HashMap\u003c\u003e();\n\n    // Add partnerReferenceNo and other fields\n    requestBody.put(\"partnerReferenceNo\", externalId);\n    requestBody.put(\"merchantId\", merchantId);\n    requestBody.put(\"validityPeriod\", \"2030-07-03T12:08:56-07:00\");\n\n    // Create and add amount map\n    Map\u003cString, String\u003e amount = new HashMap\u003c\u003e();\n    amount.put(\"value\", \"1500.00\");\n    amount.put(\"currency\", \"IDR\");\n    requestBody.put(\"amount\", amount);\n\n    // Create and add additionalInfo map\n    Map\u003cString, Object\u003e additionalInfo = new HashMap\u003c\u003e();\n\n    // Create and add customerDetails map\n    Map\u003cString, Object\u003e customerDetails = new HashMap\u003c\u003e();\n    customerDetails.put(\"firstName\", \"Merchant\");\n    customerDetails.put(\"lastName\", \"Operation\");\n    customerDetails.put(\"email\", \"merchant-ops@midtrans.com\");\n    customerDetails.put(\"phone\", \"+6281932358123\");\n\n    additionalInfo.put(\"customerDetails\", customerDetails);\n\n    // Create and add items list\n    List\u003cMap\u003cString, Object\u003e\u003e items = new ArrayList\u003c\u003e();\n    Map\u003cString, Object\u003e item = new HashMap\u003c\u003e();\n    item.put(\"id\", \"8143fc4f-ec05-4c55-92fb-620c212f401e\");\n\n    // Create and add price map\n    Map\u003cString, String\u003e price = new HashMap\u003c\u003e();\n    price.put(\"value\", \"1500.00\");\n    price.put(\"currency\", \"IDR\");\n    item.put(\"price\", price);\n\n    item.put(\"quantity\", 1);\n    item.put(\"name\", \"test item name\");\n    item.put(\"brand\", \"test item brand\");\n    item.put(\"category\", \"test item category\");\n    item.put(\"merchantName\", \"Merchant Operation\");\n\n    items.add(item);\n    additionalInfo.put(\"items\", items);\n    additionalInfo.put(\"acquirer\", \"gopay\");\n    additionalInfo.put(\"customerDetails\", customerDetails);\n    additionalInfo.put(\"countryCode\", \"ID\");\n    additionalInfo.put(\"locale\", \"id_ID\");\n\n    requestBody.put(\"additionalInfo\", additionalInfo);\n\n    return requestBody;\n}\n\n/**\n * basic implementation to create payment using Qris\n */\nJSONObject snapBiResponse1 = SnapBi.qris()\n        .withBody(createQrisRequestBody())\n        .createPayment(externalId);\n```\n\n### 3.4 Get Transaction Status\nRefer to this [docs](https://docs.midtrans.com/reference/get-transaction-status-api) for more detailed information about getting the transaction status.\n```java\npublic static Map\u003cString, Object\u003e createDirectDebitStatusByReferenceNoBody\n        () {\n    // Create the top-level map\n    Map\u003cString, Object\u003e requestBody = new HashMap\u003c\u003e();\n\n    requestBody.put(\"originalReferenceNo\", \"A1202409230511097Hmk31oa4UID\");\n    requestBody.put(\"serviceCode\", \"54\");\n    requestBody.put(\"originalExternalId\", \"b8cc77cd-64c2-4edb-b083-39a320f67c06\");\n    return requestBody;\n}\n\npublic static Map\u003cString, Object\u003e createDirectDebitStatusByExternalIdBody\n        () {\n    // Create the top-level map\n    Map\u003cString, Object\u003e requestBody = new HashMap\u003c\u003e();\n\n    requestBody.put(\"originalExternalId\", \"uzi-order-testing66ce90ce90ee5\");\n    requestBody.put(\"serviceCode\", \"54\");\n    return requestBody;\n}\npublic static  Map\u003cString, String \u003e createAdditionalHeader(){\n    Map\u003cString, String\u003e headers = new HashMap\u003c\u003e();\n    headers.put(\"X-Device-id\", \"device id\");\n    headers.put(\"debug-id\", \"debug id\");\n    return headers;\n}\n\npublic static Map\u003cString, Object\u003e createVaStatusBody\n        () {\n    // Create the top-level map\n    Map\u003cString, Object\u003e additionalInfo = new HashMap\u003c\u003e();\n    additionalInfo.put(\"merchantId\", merchantId);\n\n    Map\u003cString, Object\u003e requestBody = new HashMap\u003c\u003e();\n\n    requestBody.put(\"partnerServiceId\", \"    1234\");\n    requestBody.put(\"customerNo\", \"083430\");\n    requestBody.put(\"virtualAccountNo\", \"    1234083430\");\n    requestBody.put(\"inquiryRequestId\", \"4b1da710-fbf5-425e-9648-06e40b290326\");\n    requestBody.put(\"additionalInfo\", additionalInfo);\n    return requestBody;\n}\n\n/**\n * Example code for Direct Debit getStatus using externalId\n */\nJSONObject snapBiResponse1 = SnapBi.directDebit()\n        .withBody(createDirectDebitStatusByReferenceNoBody())\n        .getStatus(externalId);\n\n/**\n * Example code for Direct Debit getStatus using referenceNo\n */\nJSONObject snapBiResponse4 = SnapBi.directDebit()\n        .withBody(createDirectDebitStatusByReferenceNoBody())\n        .getStatus(externalId);\n    \n/**\n * Example code for VA (Bank Transfer) getStatus\n */\nJSONObject snapBiResponse7 = SnapBi.va()\n        .withBody(createVaStatusBody())\n        .getStatus(externalId);\n/**\n * \n * Example code for Qris getStatus\n */\nJSONObject snapBiResponse10 = SnapBi.qris()\n        .withBody(createVaStatusBody())\n        .getStatus(externalId);     \n\n```\n\n### 3.5 Cancel Transaction\nRefer to this [docs](https://docs.midtrans.com/reference/cancel-api) for more detailed information about cancelling the payment.\n```java\npublic static Map\u003cString, Object\u003e createDirectDebitCancelByExternalIdBody\n        () {\n    // Create the top-level map\n    Map\u003cString, Object\u003e requestBody = new HashMap\u003c\u003e();\n\n    requestBody.put(\"originalExternalId\", \"67be74c3-8cf5-4af3-b62b-0715899fd713\");\n    return requestBody;\n}\n\npublic static Map\u003cString, Object\u003e createDirectCancelByReferenceNoBody\n        () {\n    // Create the top-level map\n    Map\u003cString, Object\u003e requestBody = new HashMap\u003c\u003e();\n\n    requestBody.put(\"originalReferenceNo\", \"A12024092305243239N7MuWlDCID\");\n    return requestBody;\n}\n\npublic static Map\u003cString, Object\u003e createVaCancelBody\n        () {\n    // Create the top-level map\n    Map\u003cString, Object\u003e additionalInfo = new HashMap\u003c\u003e();\n    additionalInfo.put(\"merchantId\", merchantId);\n\n    Map\u003cString, Object\u003e requestBody = new HashMap\u003c\u003e();\n\n    requestBody.put(\"partnerServiceId\", \"    1234\");\n    requestBody.put(\"customerNo\", \"741633\");\n    requestBody.put(\"virtualAccountNo\", \"    1234741633\");\n    requestBody.put(\"trxId\", \"02a9c5a3-e088-45de-8688-424b5f65c927\");\n    requestBody.put(\"additionalInfo\", additionalInfo);\n    return requestBody;\n}\n\npublic static Map\u003cString, Object\u003e createQrisCancelBody\n        () {\n    // Create the top-level map\n    Map\u003cString, Object\u003e requestBody = new HashMap\u003c\u003e();\n\n    requestBody.put(\"originalReferenceNo\", \"A120240923112046EjKURlq1QqID\");\n    requestBody.put(\"merchantId\", merchantId);\n    requestBody.put(\"reason\", \"cancel reason\");\n    return requestBody;\n}\n/**\n * Basic implementation to cancel transaction using referenceNo\n */\nJSONObject snapBiResponse1 = SnapBi.directDebit()\n        .withBody(createDirectCancelByReferenceNoBody())\n        .cancel(externalId);\n\n/**\n * Basic implementation to cancel transaction using externalId\n */\nJSONObject snapBiResponse4 = SnapBi.directDebit()\n        .withBody(createDirectDebitCancelByExternalIdBody())\n        .cancel(externalId);\n\n/**\n * Basic implementation of VA (Bank Transfer) to cancel transaction\n */\nJSONObject snapBiResponse7 = SnapBi.va()\n        .withBody(createVaCancelBody())\n        .cancel(externalId);\n\n/**\n * Basic implementation of Qris to cancel transaction\n */\nJSONObject snapBiResponse10 = SnapBi.qris()\n        .withBody(createQrisCancelBody())\n        .cancel(externalId);\n```\n\n### 3.6 Refund Transaction\nRefer to this [docs](https://docs.midtrans.com/reference/refund-api) for more detailed information about refunding the payment.\n\n```java\n public static Map\u003cString, Object\u003e createDirectDebitRefundByExternalIdBody() {\n    // Create the top-level map\n\n    Map\u003cString, Object\u003e refundAmount = new HashMap\u003c\u003e();\n    refundAmount.put(\"value\", \"100.00\");\n    refundAmount.put(\"currency\", \"IDR\");\n\n    Map\u003cString, Object\u003e requestBody = new HashMap\u003c\u003e();\n\n    requestBody.put(\"originalExternalId\", \"9d18b81c-485c-4b67-a308-7cc060dc202e\");\n    requestBody.put(\"partnerRefundNo\", \"9d18b81c-485c-4b67-a308-7cc060dc202e refund-0001\");\n    requestBody.put(\"reason\", \"some-reason\");\n    requestBody.put(\"refundAmount\", refundAmount);\n\n    return requestBody;\n}\n\npublic static Map\u003cString, Object\u003e createDirectDebitRefundByReferenceNoBody() {\n    // Create the top-level map\n    Map\u003cString, Object\u003e refundAmount = new HashMap\u003c\u003e();\n    refundAmount.put(\"value\", \"100.00\");\n    refundAmount.put(\"currency\", \"IDR\");\n\n    Map\u003cString, Object\u003e requestBody = new HashMap\u003c\u003e();\n\n    requestBody.put(\"originalReferenceNo\", \"A1202409230511097Hmk31oa4UID\");\n    requestBody.put(\"reason\", \"some-reason\");\n    requestBody.put(\"refundAmount\", refundAmount);\n    return requestBody;\n}\npublic static Map\u003cString, Object\u003e createQrisRefundBody() {\n    Map\u003cString, Object\u003e refundAmount = new HashMap\u003c\u003e();\n    refundAmount.put(\"value\", \"100.00\");\n    refundAmount.put(\"currency\", \"IDR\");\n\n    Map\u003cString, Object\u003e additionalInfo = new HashMap\u003c\u003e();\n    additionalInfo.put(\"foo\", \"bar\");\n\n    Map\u003cString, Object\u003e requestBody = new HashMap\u003c\u003e();\n    requestBody.put(\"merchantId\", merchantId);\n    requestBody.put(\"originalPartnerReferenceNo\", \"uzi-order-testing66e01a9b8c6bf\");\n    requestBody.put(\"originalReferenceNo\", \"A120240923082857KzdNmUKObJID\");\n    requestBody.put(\"partnerRefundNo\", \"refund-abc123456\");\n    requestBody.put(\"reason\", \"some-reason\");\n    requestBody.put(\"refundAmount\", refundAmount);\n    requestBody.put(\"additionalInfo\", additionalInfo);\n\n    return requestBody;\n}\n/**\n * Example code for refund using externalId\n */\nJSONObject snapBiResponse4 = SnapBi.directDebit()\n        .withBody(createDirectDebitRefundByExternalIdBody())\n        .refund(externalId);\n\n/**\n * Example code for refund using reference no\n */\nJSONObject snapBiResponse1 = SnapBi.directDebit()\n        .withBody(createDirectDebitRefundByReferenceNoBody())\n        .refund(externalId);\n    \n/**\n * Example code for refund using Qris\n */\nJSONObject snapBiResponse7 = SnapBi.qris()\n        .withBody(createQrisRefundBody())\n        .refund(externalId);\n```\n\n### 3.7 Adding additional header / override the header\n\nYou can add or override the header value, by utilizing the `withAccessTokenHeader` or `withTransactionHeader` method chain.\nRefer to this [docs](https://docs.midtrans.com/reference/core-api-snap-open-api-overview) to see the header value required by Snap-Bi , and see the default header on each payment method\n\n```java\n//function to create the additional header\npublic static  Map\u003cString, String \u003e createAdditionalHeader(){\n    Map\u003cString, String\u003e headers = new HashMap\u003c\u003e();\n    headers.put(\"X-Device-id\", \"device id\");\n    headers.put(\"debug-id\", \"debug id\");\n    return headers;\n}\n\n /**\n * Example code for Direct Debit refund using additional header\n */\nSONObject snapBiResponse3 = SnapBi.directDebit()\n        .withBody(createDirectDebitRequestBody())\n        .withAccessTokenHeader(createAdditionalHeader())\n        .withTransactionHeader(createAdditionalHeader())\n        .createPayment(externalId);\n/**\n * Example code for using additional header on creating payment using VA\n */\nJSONObject snapBiResponse3 = SnapBi.va()\n        .withBody(createVaRequestBody())\n        .withAccessTokenHeader(createAdditionalHeader())\n        .withTransactionHeader(createAdditionalHeader())\n        .createPayment(externalId);\n```\n\n### 3.8 Reusing Access Token\n\nIf you've saved your previous access token and wanted to re-use it, you can do it by utilizing the `.withAccessToken()`.\n\n```java\n/**\n * Example reusing your existing accessToken by using .withAccessToken()\n */\nJSONObject snapBiResponse2 = SnapBi.va()\n        .withBody(createVaRequestBody())\n        .withAccessToken(\"your access token\")\n        .createPayment(externalId);\n\n```\n\n### 3.9 Payment Notification\nTo implement Snap-Bi Payment Notification you can refer to this [docs](https://docs.midtrans.com/reference/payment-notification-api)\nTo verify the webhook notification that you recieve you can use this method below\n```java\n \n//the request body/ payload sent by the webhook\nString notificationPayload = \"{\\\"originalPartnerReferenceNo\\\":\\\"GP24043015193402809\\\",\\\"originalReferenceNo\\\":\\\"A120240430081940S9vu8gSjaRID\\\",\\\"merchantId\\\":\\\"G099333790\\\",\\\"amount\\\":{\\\"value\\\":\\\"102800.00\\\",\\\"currency\\\":\\\"IDR\\\"},\\\"latestTransactionStatus\\\":\\\"00\\\",\\\"transactionStatusDesc\\\":\\\"SUCCESS\\\",\\\"additionalInfo\\\":{\\\"refundHistory\\\":[]}}\"; // Sample notification body, replace with actual data you receive from Midtrans\n\n\n// to get the signature value, you need to retrieve it from the webhook header called X-Signature\nString signature = \"CgjmAyC9OZ3pB2JhBRDihL939kS86LjP1VLD1R7LgI4JkvYvskUQrPXgjhrZqU2SFkfPmLtSbcEUw21pg2nItQ0KoX582Y6Tqg4Mn45BQbxo4LTPzkZwclD4WI+aCYePQtUrXpJSTM8D32lSJQQndlloJfzoD6Rh24lNb+zjUpc+YEi4vMM6MBmS26PpCm/7FZ7/OgsVh9rlSNUsuQ/1QFpldA0F8bBNWSW4trwv9bE1NFDzliHrRAnQXrT/J3chOg5qqH0+s3E6v/W21hIrBYZVDTppyJPtTOoCWeuT1Tk9XI2HhSDiSuI3pevzLL8FLEWY/G4M5zkjm/9056LTDw==\";\n\n// to get the timeStamp value, you need to retrieve it from the webhook header called X-Timestamp\nString timeStamp = \"2024-10-07T15:45:22+07:00\";\n\n// the url path is based on the webhook url of the payment method for example for direct debit is `/v1.0/debit/notify`\nString notificationUrlPath = \"/v1.0/debit/notify\";\n/**\n * Example verifying the webhook notification\n */\nBoolean isVerified = SnapBi.notification()\n        .withNotificationPayload(notificationPayload)\n        .withSignature(signature)\n        .withTimeStamp(timeStamp)\n        .withNotificationUrlPath(notificationUrlPath)\n        .isWebhookNotificationVerified();\n```\n\n\n## 4. Examples\nExamples are available on [/examples](example) folder \nThere are:\n- [Core Api examples](example/src/main/java/com/midtrans/sample/controller/CoreApiController.java)\n- [Snap examples](example/src/main/java/com/midtrans/sample/controller/SnapController.java)\n- [Mobile SDK examples](example/src/main/java/com/midtrans/sample/controller/MobileSdkController.java)\n- [Iris examples](example/src/main/java/com/midtrans/sample/controller/IrisController.java)\n- [Sample Functional Test](library/src/test/java/com/midtrans/java)\n- [Live Demo App](https://midtrans-java.herokuapp.com/)\n\n## Get help\n\n* [Midtrans Docs](https://docs.midtrans.com)\n* [Midtrans Dashboard ](https://dashboard.midtrans.com/)\n* [SNAP documentation](http://snap-docs.midtrans.com)\n* [Core API documentation](http://api-docs.midtrans.com)\n* Can't find answer you looking for? email to [support@midtrans.com](mailto:support@midtrans.com)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmidtrans%2Fmidtrans-java","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmidtrans%2Fmidtrans-java","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmidtrans%2Fmidtrans-java/lists"}