# IDRX Whitepaper

Welcome to IDRX Documentation.

IDRX is a stable token pegged to the value of the Indonesian Rupiah (IDR). As a cryptocurrency, IDRX offers users the benefits of blockchain technology, including security, transparency, and decentralized control. At the same time, as a stable token, IDRX offers price stability by maintaining a fixed exchange rate with the IDR, which is the national currency of Indonesia.

Embark on a journey through the intricate details of IDRX by downloading our comprehensive whitepaper. Gain insights into the technologies underpinning our platform and understand the vision that propels us forward.

{% file src="/files/4SCUX86N6NvRsY5g6ymv" %}

Thank you for joining us on this exciting exploration of IDRX, where the future of digital assets begins!


# Supported Chain and Contract Address

IDRX has been deployed on many networks. Here you will find the contract address on each network:

| Chain       | Contract Address                            | Decimals |
| ----------- | ------------------------------------------- | -------- |
| Polygon     | 0x649a2DA7B28E0D54c13D5eFf95d3A660652742cC  | 0        |
| BNB Chain   | 0x649a2DA7B28E0D54c13D5eFf95d3A660652742cC  | 0        |
| Base        | 0x18Bc5bcC660cf2B9cE3cd51a404aFe1a0cBD3C22  | 2        |
| Lisk        | 0x18Bc5bcC660cf2B9cE3cd51a404aFe1a0cBD3C22  | 2        |
| Etherlink   | 0x18bc5bcc660cf2b9ce3cd51a404afe1a0cbd3c22  | 2        |
| Kaia        | 0x18bc5bcc660cf2b9ce3cd51a404afe1a0cbd3c22  | 2        |
| World Chain | 0x18bc5bcc660cf2b9ce3cd51a404afe1a0cbd3c22  | 2        |
| Gnosis      | 0x18bc5bcc660cf2b9ce3cd51a404afe1a0cbd3c22  | 2        |
| Solana\*    | idrxZcP8xiKkYk6XGD4uz1dxEYCWSgKDHqgjsBbwDur | 2        |

\*Previous Solana token contract (idrxTdNftk6tYedPv2M7tCFHBVCpk5rkiNRd8yUArhr) has been deprecated. If you still hold tokens from this contract, you may redeem them at a 1:1 ratio, either for IDRX under the latest contract or into Rupiah. Please contact <support@idrx.co> for assistance.

### Decimals

**Decimals** is the smallest fraction of one IDRX that exists on that chain. On **Polygon and BNB Chain there is no fractional unit at all** — the smallest amount is 1 IDRX. Everywhere else IDRX goes down to 0.01.

This is a property of the token on each chain, not a display preference, so it decides which amounts you may send. A mint request whose amount is finer than the target chain allows is rejected with `400` — see [`toBeMinted`](/api/transaction-api/post-api-transaction-mint-request#parameters).


# Create Account

New to IDRX? Create an account now

To register for an IDRX account, follow these steps:

1. Visit the [home.idrx.co](https://home.idrx.co/) and click the **Get IDRX** button

   <figure><img src="/files/U5YIv5YHjqFR1t90OsRg" alt=""><figcaption></figcaption></figure>
2. If you like to create a personal account Click the **Personal Account** text. Otherwise click the **Business Account**.

   <figure><img src="/files/droBJswNpBmtAE6N43Ei" alt=""><figcaption></figcaption></figure>
3. Complete information such as email address, password, and phone number.

   <figure><img src="/files/GGwJ0NmCFXVXnyX0z0DP" alt=""><figcaption></figcaption></figure>
4. Press the **Sign Up** button.

   <figure><img src="/files/GxqhVjDoBY3isgchBG1L" alt=""><figcaption></figcaption></figure>
5. Optionally for a faster registration process, you can use your Google account or Web3 Wallet.

   <figure><img src="/files/9N5DXJtuWeWp1xKyfon2" alt=""><figcaption></figcaption></figure>


# Sign In

Login with your account to use IDRX

To log in to your IDRX account, follow these steps:

1. Visit the [home.idrx.co](https://home.idrx.co/) and click the **Get IDRX** button

   <figure><img src="/files/58q6yF2QsBSVqeY7O2AQ" alt=""><figcaption></figcaption></figure>
2. Enter the registered email address and password.

   <figure><img src="/files/Bwr0HbBhFI1eCdlPOZfN" alt=""><figcaption></figcaption></figure>
3. Press the **Login** button.

   <figure><img src="/files/SlHbpNVg04zMqyI5ZfEU" alt=""><figcaption></figcaption></figure>
4. Alternatively, you can login with your Google account or Web3 wallet.

   <figure><img src="/files/KcKnkse1uLxkmMeTTDe9" alt=""><figcaption></figcaption></figure>


# Forgot Password

Reset your password if you forget

To reset your password on IDRX, follow these steps:

1. Visit the [home.idrx.co](https://home.idrx.co/) and click the **Get IDRX** button

   <figure><img src="/files/58q6yF2QsBSVqeY7O2AQ" alt=""><figcaption></figcaption></figure>
2. Click the **Forgot Password** button

   <figure><img src="/files/cuDspasXNIQfxCReaczb" alt=""><figcaption></figcaption></figure>
3. Enter your email address and click the **Send Instruction** button

   <figure><img src="/files/9hXe2usc7h2JZsS9dFen" alt=""><figcaption></figcaption></figure>
4. Check your email inbox or spam folder. The IDRX team (<support@idrx.co>) will promptly send you a message to your account's email address. The email will contain a link to reset your password for your account.
5. Click the **Reset Password** button to continue reset your password

   <figure><img src="/files/0q6VwQ3Cxrym2JBeXdip" alt=""><figcaption></figcaption></figure>
6. Enter your new password and after that click the **Reset Password** button


# Account Verification (KYC)

Verify your account to unlock all features

Welcome to our platform! As a new user, ensuring the security of your account is a priority. Follow these simple steps to verify your account:

**Banner for Account Verification**

<figure><img src="/files/k3aRb7Zu1N7Pq70uNKcf" alt=""><figcaption></figcaption></figure>

1. Upon logging into the IDRX app, you will receive a banner prompting you to verify your account.
2. Select the "Verification" button to start the KYC process

**Providing Identification Details**

<figure><img src="/files/MYRkDfptRGegHEv24XrE" alt=""><figcaption></figcaption></figure>

3. Complete the required information, including uploading a photo of your national identification card (KTP) and a clear photo of yourself.
4. After than, click on the "Next" button to proceed with the Liveness Test.
5. Please wait for a few moments as the system processes your verification request.

**KYC Completed**

<figure><img src="/files/gVrryflr4SI4Io2Vxt1b" alt=""><figcaption></figcaption></figure>

5. Once the verification process is successful, you will be notified of the completion.

Congratulations! You've successfully verified your account, enhancing the security and trustworthiness of your experience on our platform.

If you encounter any issues during the verification process or have questions, feel free to reach out to our customer support for assistance.


# Business Account

The IDRX Business Account is a service offered to members who wish to conduct transactions using their company's bank account. **The difference between an individual account and an IDRX Business account lies in the type of account used for transactions.** For an individual account, all transactions can be carried out using a personal bank account, while for a business account, all transactions must be conducted using the company's bank account.

Here are the terms and conditions for creating an IDRX Business Account:

1. You must create an individual account on the website <https://app.idrx.co/en/signup> first. For the procedure for creating an individual account, [click here](/idrx-account/create-account).
2. Please send the required documents to **<support@idrx.co>** with the subject "IDRX Business Account Application - Your Company Name."
3. The documents needed for the creation of an IDRX Business Account include:
   1. Indonesian Company
      * The company name and email address were used to register the individual IDRX account in step 1.
      * A scanned copy of the Director's ID card.
      * Company Establishment Deed (Akta Perusahaan).
      * Company Amendment Deed, if any. (Akta Perubahaan, jika ada)
      * Ministry of Law and Human Rights Decree (SK Kemenhumkam).
      * Business Registration Number (NIB).
   2. Non-Indonesian Company
      * The company name and email address were used to register the individual IDRX account.
      * Certificate of Company Registration.
      * Corporate Profile/Certificate of Incumbency.
      * A scanned copy of the Director's Passport.
4. The verification process takes approximately 3 (three) working days after all documents have been successfully submitted.
5. The creation of the IDRX Business Account will change the status of your individual account. If the change process is successful, you will receive a notification via the registered email.
6. If you encounter any issues during the account creation process, please contact us via email at <support@idrx.co>.


# Mint IDRX

Mint new IDRX through IDR bank payments

Minting allows you to acquire IDRX by making payments in Indonesian Rupiah. The process of obtaining IDRX involves the direct minting of IDRX on the blockchain. Check [this page](https://docs.idrx.co/introduction/supported-chain-and-contract-address) to see the list of chains where IDRX is available.

By following these instructions, you will make a payment in IDR and acquire IDRX. Here's how to Mint:

{% hint style="info" %}

* The balance will be processed and credited to your wallet max 24 hours after your request is submitted.
* The minimum transaction is 20,000 IDR.
* The maximum transaction is 1,000,000,000 IDR.
* For transactions of more than 1 billion IDR, send your request to <support@idrx.co> to be processed.
* The transaction will be automatically canceled if you have not made a payment within 24 hours.
* IDRX is not responsible for deposit errors from incorrect Virtual Account numbers. Refunds for payments made to Virtual Account numbers under a different name will be processed within 14 business days.
  {% endhint %}

{% hint style="danger" %}
Use a bank account with the same name as the one on the IDRX account to transfer the payment, or your Mint request will be rejected, refunded, and subject to a refund penalty.
{% endhint %}

**Accessing the IDRX Dashboard**

1. Visit the [home.idrx.co](https://home.idrx.co/) and click the **Get IDRX** button

   <figure><img src="/files/58q6yF2QsBSVqeY7O2AQ" alt=""><figcaption></figcaption></figure>
2. Enter the registered email address and password. Then, press the **Login** button.

   <figure><img src="/files/SlHbpNVg04zMqyI5ZfEU" alt=""><figcaption></figcaption></figure>
3. Once logged in, you'll automatically in the Mint tab.

**Completing Minting Details**

4. In the Mint section, provide the following details:
   * Enter the quantity of IDRX tokens to be minted.
   * Specify the recipient wallet address.
   * Choose the IDRX network.
5. After entering the details, click on "Review Mint" to proceed.

<figure><img src="/files/FQRz9B9iCqJ7soMY0lka" alt=""><figcaption></figcaption></figure>

**Confirming the Payment**

6. You will be directed to a page for payment confirmation. Click on "Proceed Payment."

   <figure><img src="/files/HRvr3zTkHWAUQyHDt0b7" alt=""><figcaption></figcaption></figure>

**Selecting Payment Method**

7. On the payment page, choose your desired payment method and complete the payment process.

   <figure><img src="/files/ERkIs02fVy8DZLF0sqUI" alt=""><figcaption></figcaption></figure>

**Verifying Payment**

11. After making the payment, you will receive a pop-up notification confirming that the Invoice has been Paid.

    <figure><img src="/files/vAgnkAi38kfAGKsQiFUG" alt=""><figcaption></figcaption></figure>
12. Wait for a moment until the status changes to "Minted."

**Checking Minting Status**

12. Return to the IDRX app and navigate to the Transaction menu. You can also filter the transaction history by the transaction type and blockchain.

    <figure><img src="/files/B5DAIxW0ZdywbU8qOxPx" alt=""><figcaption></figcaption></figure>
13. Once the status is "Minted," the IDRX tokens will be automatically sent to the specified recipient wallet.
14. Ensure that you have imported the tokens into your wallet to view the IDRX balance.

    You can do so by clicking the "+" button

    <figure><img src="/files/AJVwhf52KrROuBkJAUSO" alt=""><figcaption></figcaption></figure>
15. If you do not receive IDRX within 24 hours, please contact IDRX customer support at **<support@idrx.co>**.

Congratulations! You have successfully minted and received IDRX tokens.


# Redeem IDR

Redeem your IDRX to IDR

Redeeming allows you to acquire Indonesian Rupiah directly to your bank account by burning IDRX tokens through the platform. Please note that if you attempt to burn IDRX tokens outside of the platform, you won't receive the associated funds in your bank account.

{% hint style="danger" %}

* Burning the IDRX token outside the IDRX platform will result in the loss of your funds.
  {% endhint %}

{% hint style="info" %}

* The balance will be processed and credited to your bank/e-wallet account max 24 hours after your request is submitted.
* The minimum transaction is 20,000 IDR.
* The Maximum transaction is 1,000,000,000 IDR.
* Redeeming IDRX <= 250 million IDR will be processed in real-time
* Redeeming IDRX 250 million IDR\<x<1 billion IDR will be processed only during office hours on Monday-Friday at 08:00-15:00 WIB
* For transactions of more than 1 billion Rupiah, send your request to <support@idrx.co> to be processed.
* IDRX is not responsible if a redeem error occurs due to an incorrect bank/e-wallet account number.
  {% endhint %}

By following these instructions, you will burn IDRX and receive IDR in your bank account. Here's how to redeem:

**Accessing the IDRX Dashboard**

1. Visit the [home.idrx.co](https://home.idrx.co/) and click the **Get IDRX** button

   <figure><img src="/files/58q6yF2QsBSVqeY7O2AQ" alt=""><figcaption></figcaption></figure>
2. Enter the registered email address and password. Then, press the **Login** button.

   <figure><img src="/files/SlHbpNVg04zMqyI5ZfEU" alt=""><figcaption></figcaption></figure>
3. Once logged in, navigate to the Redeem tab

   <figure><img src="/files/FfTuF4mi0QTgyO7Q0Z09" alt=""><figcaption></figcaption></figure>

**Connecting to Web3 Wallet**

3. Click on "Connect to Web3 wallet."

   <figure><img src="/files/oEmXkK7S5zciZsQSDF0E" alt=""><figcaption></figcaption></figure>
4. A pop-up will appear, displaying options for your Web3 wallet. Choose the wallet you are using.

   <figure><img src="/files/oagFbXUnCdG0ZJB5Y86s" alt=""><figcaption></figcaption></figure>

**Providing Redeem Detail**

5. Choose the network and enter the quantity of IDRX you wish to redeem and your bank account details. Ensure that the recipient's bank account name matches your IDRX account. Press "Review Redeem" to proceed.

   <figure><img src="/files/tfpWwTqyRyHyI7sZaIph" alt=""><figcaption></figcaption></figure>

**Confirming Redeem Process**

7. You will be see redeem detail. If everything is correct. Click on "Proceed Redeem."

   <figure><img src="/files/O0RKwdb7xY097aE1SfZD" alt=""><figcaption></figcaption></figure>
8. Sign the transaction in your wallet. Ensure you have a sufficient gass fee balance to confirm the redeem process.

   <figure><img src="/files/0F7ZdEVXlGN4Y9mAqCR4" alt=""><figcaption></figcaption></figure>

**Transaction Confirmation**

9. If the transaction is successful, you will receive a notification on your screen.

   <figure><img src="/files/otLcYgLgy2IsXt6LdXaB" alt=""><figcaption></figcaption></figure>
10. Allow some time for the balance to be successfully transferred to your account.
11. To check the redeem status, go to the Transaction page. You can also filter your transaction history by the transaction type and the blockchain

    <figure><img src="/files/MeTEMdNMS4mzfnRl2bPp" alt=""><figcaption></figcaption></figure>
12. If you do not receive IDR within 24 hours, please contact IDRX customer support at **<support@idrx.co>**.

Congratulations! You have successfully redeemed your IDRX tokens.


# Send IDRX

Send IDRX to other blockchains

Bridging allows you to transfer your IDRX tokens from one network to another. Check [this page](https://docs.idrx.co/introduction/supported-chain-and-contract-address) to see the list of chains where IDRX is available

By following these instructions, you will bridge IDRX. Here's how to Bridge IDRX:

{% hint style="info" %}

* The balance will be processed and credited to your wallet address max 24 hours after your request is submitted.
* Minimum transaction is 20,000 IDR.
  {% endhint %}

**Accessing the IDRX Dashboard**

1. Visit the [home.idrx.co](https://home.idrx.co/) and click the **Get IDRX** button

   <figure><img src="/files/58q6yF2QsBSVqeY7O2AQ" alt=""><figcaption></figcaption></figure>
2. Enter the registered email address and password. Then, press the **Login** button.

   <figure><img src="/files/SlHbpNVg04zMqyI5ZfEU" alt=""><figcaption></figcaption></figure>
3. Once logged in, navigate to the Redeem tab

   <figure><img src="/files/Muy8UpAe2gDcAR8H4Ljo" alt=""><figcaption></figcaption></figure>

**Conneting to Web3 Wallet**

4. Click on "Connect to Web3 wallet."

   <figure><img src="/files/mESOxNzS235LLHN9qOna" alt=""><figcaption></figcaption></figure>
5. A pop-up will appear, displaying options for your Web3 wallet. Choose the wallet you are using.

   <figure><img src="/files/WqCcMAiwd0lcmXdBXlGD" alt=""><figcaption></figcaption></figure>

**Selecting the Network**

6. Choose the desired blockchain network from the options provided.

   <figure><img src="/files/mwU1fjEywxhu602HOb2F" alt=""><figcaption></figcaption></figure>
7. Enter the quantity of IDRX tokens you want to convert and the recepient address.

   <figure><img src="/files/nCd9dAEOfHSntp5GqEnc" alt=""><figcaption></figcaption></figure>
8. Click on "Review Bridge" to proceed with the process.

   <figure><img src="/files/SgT4F6aSOaz50ojvRMv4" alt=""><figcaption></figcaption></figure>

**Confirming the Bridge Process**

9. You will be see redeem detail. If everything is correct. Click on "Proceed Bridge."<br>

   <figure><img src="/files/yJXamDCRGIR61R645sIa" alt=""><figcaption></figcaption></figure>
10. Sign the transaction in your wallet. Ensure you have a sufficient gass fee balance to confirm the redeem process.\
    ![](/files/ptNTbgh2LDHzWhYeqJOD)

**Transaction Confirmation**

11. If the transaction is successful, a notification will appear on your screen.

    <figure><img src="/files/C6MCos0Ez8zT0WgRJ0Ja" alt=""><figcaption></figcaption></figure>
12. To check the bridge status, go to the Dashboard and select "Bridge." Wait until the status changes to "Success."

    <figure><img src="/files/3MIB7Ap0YP0cMy5dvknK" alt=""><figcaption></figcaption></figure>

**Importing Tokens to Your Wallet**

10. Make sure you have imported the tokens into your wallet to view the updated IDRX balance. You can do so in the Mint/Redeem page and clicking the "+" button

    <figure><img src="/files/AJVwhf52KrROuBkJAUSO" alt=""><figcaption></figcaption></figure>
11. If you do not receive IDRX in the destination chain within 24 hours, please contact IDRX customer support at **<support@idrx.co>**.

Congratulations! You have successfully used the IDRX Bridge to convert your tokens.


# Fees

Table of fee structure

<table><thead><tr><th width="165.33333333333331">Category</th><th width="137">Fee</th><th>Note</th></tr></thead><tbody><tr><td>Mint</td><td>Rp0 - Rp4.000</td><td><p>Added to the amount to mint depending on the payment method and the amount of IDRX you want to mint.<br></p><ol><li><p>Minting &#x3C;= 10.000.000 IDRX</p><ol><li>Virtual Account: Rp3.000 - Rp.4.000</li><li>E-Wallet: 1.67% of the total amount<br></li></ol></li><li><p>Minting > 10,000,000 and ≤ 20,000,000 IDRX</p><ol><li>Virtual Account: Rp3.000 - Rp4.000</li><li>E-Wallet: 1.67% of the total amount<br></li></ol></li><li><p>Minting > 20.000.000 IDRX</p><ol><li>Virtual Account: Rp3.000 - Rp4.000</li></ol></li></ol></td></tr><tr><td>Redeem</td><td>Rp5.000-Rp35.000</td><td><p>Redemption fees are deducted from the amount and depend on the total IDR value you wish to redeem.</p><ol><li><p>Redeeming ≤ Rp250,000,000 IDR</p><ol><li>Fee: Rp5,000</li><li>Processing: Real-time</li></ol></li><li><p>Redeeming > Rp250,000,000 IDR and &#x3C; Rp1,000,000,000 IDR</p><ol><li>Fee: Rp35,000</li><li>Processing: RTGS Only during office hours (Monday–Friday, 08:00–15:00 WIB)</li></ol></li></ol></td></tr><tr><td>Bridge</td><td>10.000 IDRX</td><td>Deduct from the IDRX amount on the source network.</td></tr><tr><td>Refund penalty</td><td>Rp5.000</td><td>If a refund is processed, the fees are Redeem + Refund penalty.</td></tr></tbody></table>

Example:

* Alex is minting 100.000 IDRX. Alex must transfers 103.000 Rupiah to IDRX.
* Alex is redeeming 100.000 IDRX. Alex will receive 95.000 in his bank account.
* Alex is bridging 100.000 IDRX on polygon network to BSC (Binance Smart Chain). Alex will get 90.000 IDRX on BSC network.
* Alex failed to mint due to a term violation and requested a refund. Alex will receive a refund of 90,000 Rupiah in his bank account.


# Getting Started

Read and follow this guide to get access to IDRX's APIs

Our API service is only available to a special type of account. To have access to our API, create a [business account](/idrx-account/business-account) or contact us via [email](mailto:support@idrx.co). Once we verified your request, a menu called **API Key** will appear on your dashboard.

<figure><img src="/files/ZG5aCzhcRp0zlsoZwsnN" alt=""><figcaption></figcaption></figure>

To use the API, you will need to first generate an API key. To do so, click the **API Key** menu and click the **Generate API Key** button.

<figure><img src="/files/vicPVaQWotaRQw5LrEzB" alt=""><figcaption></figcaption></figure>

After the API Key is generated, make sure to save the secret key. **The secret key will not be shown again.**

<figure><img src="/files/GfqTPEmGj15a1zcqXxFK" alt=""><figcaption></figcaption></figure>

Congratulations, you have succesfully generate your first API Key. Now let's authorize your API key by generating a signature.


# Generating a Signature

Follow the tutorial to be able to use your API Key

In order to authorize your API requests, the system requires a SHA-256 hash of the payload as a signature. This signature serves as a digital seal, guaranteeing the integrity and origin of the data being transmitted.

These steps can be applied to various programming languages, as the underlying HMAC-SHA256 concept remains the same. However, please note that the specific implementation details might vary based on the programming language used.

## 1. Prepare Input Parameters

Gather the components of the API request that need to be included in the signature:

* `method`: The HTTP method of the API request (e.g., 'GET', 'POST').
* `url`: The URL of the API endpoint.
* `bodyBuffer`: a JSON string payload, which is converted into a Buffer.
* `timestamp`: A timestamp indicating when the request is being made (in miliseconds).
* `secretKey`: A secret key used for HMAC-SHA256 encryption.

## 2. **Decode the Secret Key**

Decode the base64-encoded `secretKey` to obtain the original secret.

## 3. **Create HMAC Instance**

Concatenate the components of the request in this order into a single string.

1. method,
2. URL,
3. timestamp,
4. and the request body.

Create an HMAC instance using the SHA-256 hash algorithm and the secret key. Pass the string into the HMAC instance.

## 4. Generate HMAC Digest

Generate the HMAC digest by finalizing the HMAC computation. This step produces a binary hash.

## 5. Encode the Digest

Encode the binary hash into a string representation. The encoding format should be a base64Url.

## Code Example (TypeScript)

The following is an example code implementation using Typescript:

```typescript
import * as crypto from 'crypto';

function atob(str: string) {
  return Buffer.from(str, 'base64').toString('binary');
}

export function createSignature(
  method: string,
  url: string,
  body: any,
  timestamp: string,
  secretKey: string,
) {
  const bodyBuffer = Buffer.from(JSON.stringify(body));

  const secret = atob(secretKey);

  const hmac = crypto.createHmac('sha256', secret);
  hmac.update(timestamp);
  hmac.update(method);
  hmac.update(url);

  if (bodyBuffer != null) {
    hmac.update(bodyBuffer);
  }

  const hash = hmac.digest();
  const signature = hash.toString('base64url');

  return signature;
}
```

You're all set. Include the generated signature in the API request headers.


# Onboarding API

API endpoint list for the purpose of onboarding new users.

{% content-ref url="/pages/7Ufhe5phxp6WoYwJ6UhB" %}
[POST /api/auth/onboarding](/api/onboarding-api/post-api-auth-onboarding)
{% endcontent-ref %}

{% content-ref url="/pages/RhREOrL0C80emF1zC0cO" %}
[GET /api/auth/members](/api/onboarding-api/get-api-auth-members)
{% endcontent-ref %}

{% content-ref url="/pages/CevMXlmjXj9KTAiLfdPZ" %}
[POST /api/auth/add-bank-account](/api/onboarding-api/post-api-auth-add-bank-account)
{% endcontent-ref %}

{% content-ref url="/pages/d6umSpEcgoJjufzR13dD" %}
[GET /api/auth/get-bank-accounts](/api/onboarding-api/get-api-auth-get-bank-accounts)
{% endcontent-ref %}

{% content-ref url="/pages/gLk005s8JxZ8lelo2sbR" %}
[DELETE /api/auth/delete-bank-account/:bankId](/api/onboarding-api/delete-api-auth-delete-bank-account-bankid)
{% endcontent-ref %}


# POST /api/auth/onboarding

Use this API to onboard a new user.

This API is used by an organization to onboard new users to the platform. Accounts registered in this way can skip a few steps of the KYC process. The organization can then use the API keys associated with these accounts to process mint and redeem requests. This endpoint accepts requests of type `multipart/form-data`.

## Parameters

1. **`email` (String):**

   This parameter represents the email address of the user.
2. **`fullname` (String):**

   This parameter refers to the user's full name.
3. **`address` (String):**

   This parameter refers to the user's physical address.
4. **`idNumber`(String):**

   This parameter refers to the user's ID number.
5. **`idFile`(File):**\
   This parameter represents an image file of the user's ID. Accepted file types are: `jpeg, png, jpg, webp`. File dimension should be between 256px \* 256px and 4096px \* 4096px.

## Example Request

<pre><code><strong>curl -X POST '&#x3C;https://idrx.co/api/auth/onboarding>' --header 'idrx-api-key: &#x3C;API_KEY>' --header 'idrx-api-sig: &#x3C;signature>' --header 'idrx-api-ts': &#x3C;timestamp>' --header 'Content-Type': multipart/form-data'
</strong></code></pre>

**Payload**

```json
{
  "email": "string",
  "fullname": "string",
  "address": "string",
  "idNumber": "string",
  "idFile": "file"
}
```

## Response

If the request is successful, the response will be as shown below:

```json
{
  statusCode: 201,
  message: 'success',
  data: {
    id: 1011,
    fullname: 'JOHN SMITH',
    createdAt: '2023-12-12T08:10:29.077Z',
    apiKey: '3d1c15c7afd157a6',
    apiSecret: '7bb0de01a2cf17c1094db789bfa05eb1adc185482c3ee828a7ba61b683e9b711'
  }
}
```


# GET /api/auth/members

Use this api to get members info.

This API is used by an organization to get info about members that are registered under their account.

## Example Request

```
curl -X GET '<https://idrx.co/api/auth/members>' --header 'idrx-api-key: <API_KEY>' --header 'idrx-api-sig: <signature>' --header 'idrx-api-ts': <timestamp>'
```

## Response

If the request is successful, the response will be as shown below:

```json
{
    "statusCode": 200,
    "message": "success",
    "data": [
        {
            "id": 421,
            "email": "jack.smith@gmail.com",
            "createdAt": "2023-12-27T06:33:58.173Z",
            "fullname": "JACK SMITH",
            "ApiKeys": [
                {
                    "apiKey": "{API_KEY}"
                }
            ]
        },
        {
            "id": 411,
            "email": "john.smith@gmail.com",
            "createdAt": "2023-12-19T09:58:34.357Z",
            "fullname": "JOHN SMITH",
            "ApiKeys": [
                {
                    "apiKey": "{API_KEY}"
                }
            ]
        },
        ...,
    ]
}
```


# POST /api/auth/add-bank-account

Use this API to add bank accounts.

This API is used to add a new bank account. A new deposit address associated to the bank account will also be created. Users can use the deposit address to request a redeem to the bank account.

## Parameters

1. **`bankAccountNumber` (String):**

   This parameter represents the bank account number.
2. **`bankCode` (String):**

   This parameter represents the bank code. Get a list of available banks from [this api](/api/transaction-api/get-api-transaction-method).
3. **`bankName` (String):**

   The name of the bank, as returned by the same API.
4. **`notes` (String):**

   Optional. Use it when the bank account holder name differs from the name on the IDRX account, to describe the reason for the difference.

{% hint style="warning" %}
This endpoint requires a verified account. If the account has not completed verification, the request is rejected with `401 User is not verified`.
{% endhint %}

## Example Request

<pre><code><strong>curl -X POST '&#x3C;https://idrx.co/api/auth/add-bank-account>' --header 'idrx-api-key: &#x3C;API_KEY>' --header 'idrx-api-sig: &#x3C;signature>' --header 'idrx-api-ts': &#x3C;timestamp>' --header 'Content-Type': application/json'
</strong></code></pre>

**Payload**

```json
{
  "bankAccountNumber": "string",
  "bankCode": "string",
  "bankName": "string"
}
```

## Response

If the request is successful, the response will be as shown below:

```json
{
    "statusCode": 201,
    "message": "success",
    "data": {
        "id": 108,
        "userId": 411,
        "bankAccountNumber": "5017332241",
        "bankAccountName": "JOHN SMITH",
        "bankAccountNumberHash": null,
        "bankCode": "014",
        "bankName": "BANK CENTRAL ASIA",
        "maxAmountTransfer": "100000000",
        "deleted": false,
        "DepositWalletAddress": {
            "walletAddress": "0x07C158ab29f23D0821e7D24B191c5e5d9d72738b",
            "createdAt": "2024-01-17T10:34:22.304Z"
        }
    }
}
```


# GET /api/auth/get-bank-accounts

Use this API to get bank accounts.

## Example Request

```
curl -X GET '<https://idrx.co/api/auth/get-bank-accounts>' --header 'idrx-api-key: <API_KEY>' --header 'idrx-api-sig: <signature>' --header 'idrx-api-ts': <timestamp>'
```

## Response

If the request is successful, the response will be as shown below:

```json
{
    "statusCode": 200,
    "message": "success",
    "data": [
        {
            "id": 108,
            "userId": 411,
            "bankAccountNumber": "5017332241",
            "bankAccountName": "JOHN SMITH",
            "bankAccountNumberHash": null,
            "bankCode": "014",
            "bankName": "BANK CENTRAL ASIA",
            "maxAmountTransfer": "100000000",
            "deleted": false,
            "DepositWalletAddress": {
                "walletAddress": "0x07C158ab29f23D0821e7D24B191c5e5d9d72738b",
                "createdAt": "2024-01-17T10:34:22.304Z"
            }
        },
        ...,
    ]
}
```


# DELETE /api/auth/delete-bank-account/:bankId

Use this api to delete bank accounts.

## Example Request

```
curl -X DELETE '<https://idrx.co/api/auth/delete-bank-account/108>' --header 'idrx-api-key: <API_KEY>' --header 'idrx-api-sig: <signature>' --header 'idrx-api-ts': <timestamp>'
```

## Response

If the request is successful, the response will be as shown below:

```json
{
    "statusCode": 200,
    "message": "deleted",
    "data": null
}
```


# Transaction API

API endpoint list for the purpose of making transactions.

{% content-ref url="/pages/b9u4ITETV5rovgIKQyRa" %}
[POST /api/transaction/mint-request](/api/transaction-api/post-api-transaction-mint-request)
{% endcontent-ref %}

{% content-ref url="/pages/RERC8g3TwJIlUT3s2IDl" %}
[POST /api/transaction/redeem-request](/api/transaction-api/post-api-transaction-redeem-request)
{% endcontent-ref %}

{% content-ref url="/pages/quSDKyVWVkZNQJJzHR1C" %}
[POST /api/transaction/bridge-request](/api/transaction-api/post-api-transaction-bridge-request)
{% endcontent-ref %}

{% content-ref url="/pages/JNbIGVcnTWx0nJME6DAz" %}
[GET /api/transaction/method](/api/transaction-api/get-api-transaction-method)
{% endcontent-ref %}

{% content-ref url="/pages/eerfxP4vHUVxHjia52x0" %}
[GET /api/transaction/user-transaction-history](/api/transaction-api/get-api-transaction-user-transaction-history)
{% endcontent-ref %}

{% content-ref url="/pages/HepEbdY3FsgySqTHvJNH" %}
[GET /api/transaction/rates](/api/transaction-api/get-api-transaction-rates)
{% endcontent-ref %}

{% content-ref url="/pages/W3z0UxvoZGHiT0ax7DfL" %}
[GET /api/transaction/get-additional-fees](/api/transaction-api/get-api-transaction-get-additional-fees)
{% endcontent-ref %}


# POST /api/transaction/mint-request

Use this API to request a IDRX minting transaction in one of our supported chains.

{% hint style="info" %}
Check out [this page](/introduction/supported-chain-and-contract-address) to see the list of chains where IDRX is available and [this page](/integration/processing-mint-idrx-requests/getting-other-stablecoins) to see the list of supported other stablecoins.
{% endhint %}

{% hint style="info" %}

* The balance will be processed and credited to \`**`` destinationWalletAddress` ``** max 24 hours after your request is submitted.
* Minimum transaction:
  * Minting IDRX is Rp20,000 IDR
  * Minting other stablecoins are $2 USD
* Maximum transaction:
  * Minting IDRX is 1,000,000,000 IDR.
  * Minting other stablecoins are 5,555 USD
* For transactions more than the maximum limit, please send your request to <support@idrx.co> to be processed.
* The transaction will be automatically canceled if you have not made a payment within 24 hours.
* IDRX is not responsible for deposit errors from incorrect Virtual Account numbers. Refunds for payments made to Virtual Account numbers under a different name will be processed within 14 business days.
  {% endhint %}

```
POST https://idrx.co/api/transaction/mint-request
```

### Quick start

```bash
curl -X POST 'https://idrx.co/api/transaction/mint-request' \
  -H 'idrx-api-key: <API_KEY>' \
  -H 'idrx-api-sig: <SIGNATURE>' \
  -H 'idrx-api-ts: <TIMESTAMP>' \
  -H 'Content-Type: application/json' \
  -H 'User-Agent: my-app/1.0' \
  -d '{
    "toBeMinted": "20000",
    "destinationWalletAddress": "0x7D1398C397C64368B7079bD5b3EE904aaaf8A495",
    "networkChainId": "8453",
    "returnUrl": "https://your-app.example.com/callback",
    "requestType": "idrx",
    "paymentProvider": "snap"
  }'
```

Redirect the user to `data.paymentUrl` from the response. After payment, IDRX is delivered to the wallet — usually within minutes.

> For end-to-end integration including status tracking and reconciliation, see [Processing Mint IDRX Requests](/integration/processing-mint-idrx-requests#overview).

***

### Authentication

Every request needs four headers:

| Header         | Value                                     |
| -------------- | ----------------------------------------- |
| `idrx-api-key` | Your API key                              |
| `idrx-api-sig` | HMAC-SHA256 signature (see formula below) |
| `idrx-api-ts`  | Unix timestamp in milliseconds            |
| `User-Agent`   | Custom string like `my-app/1.0` (why)     |

#### Signature formula

```
HMAC-SHA256(secret, METHOD + ":" + PATH + ":" + SHA256(body) + ":" + timestamp)
```

For GET requests with no body, use `SHA256("")`.

Full guide: [Generating a Signature](/api/generating-a-signature)

API keys are issued via:

```http
POST /api/auth/generate-api-key
```

{% hint style="warning" %}
**Custom `User-Agent` required.** Defaults from `curl`, `Python-urllib`, or generic SDK strings are blocked at the edge with HTTP `403` (Cloudflare error 1010).
{% endhint %}

***

### Parameters

| Parameter                  | Type   | Required | Description                                                                                                                                                                                              |
| -------------------------- | ------ | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `toBeMinted`               | string | ✓        | Amount to mint. Min 20,000 IDR or 2 USD. Max 1,000,000,000 IDR or 5,555 USD. Must be a whole number on Polygon and BNB Chain, and may carry at most 2 decimals on the other chains — see the note below. |
| `destinationWalletAddress` | string | ✓        | Recipient wallet on the target chain.                                                                                                                                                                    |
| `networkChainId`           | string | ✓        | Target chain ID. Supported chains →                                                                                                                                                                      |
| `returnUrl`                | string | Flow A   | HTTPS URL the customer returns to after checkout. Required for Flow A. Not used in Flow B — there is no hosted page to return from, so you may omit it.                                                  |
| `requestType`              | string | —        | `"idrx"` (default) or `"usdt"`. Other tokens →                                                                                                                                                           |
| `usdtRequested`            | string | —        | Required when `requestType` is `"usdt"`. Amount of the target stablecoin the customer expects to receive.                                                                                                |
| `expiryPeriod`             | number | —        | Payment window in minutes. Default `120`.                                                                                                                                                                |
| `productDetails`           | string | —        | Custom note on payment page. Max 255 chars.                                                                                                                                                              |
| `paymentProvider`          | string | ✓        | Set to `"snap"`.                                                                                                                                                                                         |
| `paymentMethod`            | string | —        | Flow B only. `"va"`. When set, the response carries the Virtual Account number directly and no hosted checkout page is created. Requires `channelId`.                                                    |
| `channelId`                | string | —        | Required whenever `paymentMethod` is set. The bank channel — `"MANDIRI"` or `"BRI"`.                                                                                                                     |

{% hint style="warning" %}
**`toBeMinted` cannot be finer than the token itself.** IDRX has **0 decimals on Polygon and BNB Chain** — one IDRX is the smallest unit there, so amounts must be whole numbers. On every other chain IDRX has 2 decimals. Amounts are never silently rounded for you: send `"556931.42"` to Polygon and the request is rejected with

```
400 invalid toBeMinted: IDRX on chainId 137 supports 0 decimal place(s), got 556931.42
```

Round the amount in your own system before calling this endpoint, so the figure you show the customer is the figure that gets minted. Trailing zeros are fine — `"20000.00"` is accepted anywhere, since it carries no real precision. Decimals per chain: [Supported Chain and Contract Address](/introduction/supported-chain-and-contract-address).
{% endhint %}

***

### Choosing a flow

Every mint order goes through the same endpoint, the same authentication, and the same status tracking. What differs is who renders the payment screen.

|                              | Send                                                      | You get back                             | Customer experience                                              |
| ---------------------------- | --------------------------------------------------------- | ---------------------------------------- | ---------------------------------------------------------------- |
| **Flow A — Hosted checkout** | `paymentProvider: "snap"`                                 | `checkoutUrl` (mirrored as `paymentUrl`) | Redirected to a payment page where they pick a method themselves |
| **Flow B — Direct payment**  | `paymentProvider: "snap"` + `paymentMethod` + `channelId` | The Virtual Account number               | Stays inside your app; you show the VA number yourself           |

Pick **Flow A** when you want the fastest integration, no payment UI to build, and the widest choice of payment methods. Pick **Flow B** when you own the checkout experience end to end — mobile app, white-label web, kiosk — and would rather not send the customer to a page you don't control.

***

### Flow A — Hosted checkout

#### Request

```json
{
  "toBeMinted": "20000",
  "destinationWalletAddress": "0x7D1398C397C64368B7079bD5b3EE904aaaf8A495",
  "networkChainId": "8453",
  "returnUrl": "https://your-app.example.com/callback",
  "expiryPeriod": 60,
  "requestType": "idrx",
  "paymentProvider": "snap"
}
```

#### Response

```json
{
  "statusCode": 200,
  "message": "success",
  "data": {
    "id": 1234,
    "merchantOrderId": "20260728130000",
    "reference": "SNAP-20260728130000",
    "checkoutUrl": "https://checkout.idrx.co?token=eyJhbGciOi...",
    "paymentUrl": "https://checkout.idrx.co?token=eyJhbGciOi..."
  }
}
```

`checkoutUrl` and `paymentUrl` always carry the same value — redirect the customer to either one.

1. Redirect the user to `paymentUrl`.
2. User picks a payment method and pays.
3. User is redirected to your `returnUrl`.
4. You receive a callback on settlement.

{% hint style="info" %}
**Fee handling depends on the payment method the user picks.** For VA and e-wallet, the fee is added on top of `toBeMinted` (the user pays slightly more). Other channels deduct it from the minted IDRX instead. See [Fee structure by payment method](/api/callback#fee-structure-by-payment-method) for the full matrix.
{% endhint %}

{% hint style="info" %}
**QRIS is temporarily undocumented.** QRIS remains available on the hosted checkout page and is not being withdrawn — its documentation is hidden while we carry out maintenance, and will be restored afterwards. If you need QRIS details in the meantime, contact <support@idrx.co>.
{% endhint %}

{% hint style="warning" %}
Don't rely on the `returnUrl` redirect to confirm payment. Users close browsers. Always confirm via [callback](/api/callback) or [Transaction History](/api/transaction-api/get-api-transaction-user-transaction-history).
{% endhint %}

***

### Flow B — Direct payment

Set `paymentProvider: "snap"` together with `paymentMethod` and `channelId`. The response contains the generated **Virtual Account number** directly — no redirect, no hosted page. You render the payment instructions in your own UI.

#### Request

```json
{
  "toBeMinted": "20000",
  "destinationWalletAddress": "0x7D1398C397C64368B7079bD5b3EE904aaaf8A495",
  "networkChainId": "8453",
  "requestType": "idrx",
  "expiryPeriod": 60,
  "paymentProvider": "snap",
  "paymentMethod": "va",
  "channelId": "MANDIRI"
}
```

#### Response

```json
{
  "statusCode": 200,
  "message": "success",
  "data": {
    "id": 1234,
    "merchantOrderId": "20260728130000",
    "reference": "SNAP-20260728130000",
    "checkoutUrl": "https://checkout.idrx.co?token=eyJhbGciOi...",
    "paymentUrl": "https://checkout.idrx.co?token=eyJhbGciOi...",
    "paymentMethod": "va",
    "virtualAccountNo": "8680770000001234",
    "virtualAccountName": "JOHN SMITH",
    "amount": 24000,
    "baseAmount": 20000,
    "fees": [
      { "name": "VA Mandiri", "amount": 4000 }
    ],
    "expiredDate": "2026-07-28T14:00:00.000Z"
  }
}
```

#### Response fields

| Field                        | Type   | Description                                                                                                                                              |
| ---------------------------- | ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`                         | number | Mint request ID.                                                                                                                                         |
| `merchantOrderId`            | string | Your order ID — use it for status polling and reconciliation.                                                                                            |
| `reference`                  | string | Internal payment reference, always `SNAP-<merchantOrderId>`.                                                                                             |
| `paymentMethod`              | string | Echoes the method you requested — `"va"`.                                                                                                                |
| `amount`                     | number | Total the customer must pay, in IDR. Equals `baseAmount` plus the sum of `fees`.                                                                         |
| `baseAmount`                 | number | The mint amount before channel fees.                                                                                                                     |
| `fees`                       | array  | Fee breakdown for this payment. `[]` when the channel charges no fee.                                                                                    |
| `fees[].name`                | string | Fee label.                                                                                                                                               |
| `fees[].amount`              | number | Fee amount in IDR.                                                                                                                                       |
| `expiredDate`                | string | ISO-8601 UTC timestamp when the Virtual Account stops accepting payment.                                                                                 |
| `virtualAccountNo`           | string | The account number the customer transfers to.                                                                                                            |
| `virtualAccountName`         | string | Account holder name shown in the customer's banking app.                                                                                                 |
| `checkoutUrl` / `paymentUrl` | string | The IDRX-hosted checkout page for this order. Not needed in Flow B — present so a single response shape works for both flows. Both carry the same value. |

{% hint style="warning" %}
**The customer must transfer the exact `amount`.** A Virtual Account accepts a differing amount, but the mismatch is flagged — paying less is treated as **underpaid**, paying more as **overpaid**. Either way the mint is held for manual review before IDRX is credited. Show the exact `amount` in your UI and discourage rounding.
{% endhint %}

#### Rendering the payload

Display `virtualAccountNo` as text, ideally with a copy button. The customer opens their banking app and transfers exactly `amount` to that number.

#### Supported channels

| `paymentMethod` | `channelId` | Bank         |
| --------------- | ----------- | ------------ |
| `"va"`          | `"MANDIRI"` | Bank Mandiri |
| `"va"`          | `"BRI"`     | Bank BRI     |

Any other `channelId` is rejected with `400`.

#### Errors specific to Flow B

| Status | Message                                                       | Cause                                        |
| ------ | ------------------------------------------------------------- | -------------------------------------------- |
| `400`  | `paymentMethod must be "va" or "qris" when set, got: <value>` | Unsupported `paymentMethod` — send `"va"`    |
| `400`  | `channelId is required when paymentMethod is set`             | `channelId` missing                          |
| `400`  | `Unsupported VA channel: <value>`                             | `channelId` is not enabled for your merchant |

{% hint style="info" %}
**Failed payload generation rolls the order back.** If the Virtual Account cannot be generated, the mint order created moments earlier is deleted before the error is returned. Nothing is left half-created — retry with a fresh request and you get a new `merchantOrderId`.
{% endhint %}

#### Retrieving the payment payload again

If your customer closes the app before paying and you no longer have the original response, fetch the cached payload for the same order instead of creating a new one:

```bash
curl -X GET 'https://idrx.co/api/duitku-snap/checkout/payment-payload?merchantOrderId=<MERCHANT_ORDER_ID>' \
  --header 'idrx-api-key: <API_KEY>' \
  --header 'idrx-api-sig: <SIGNATURE>' \
  --header 'idrx-api-ts: <TIMESTAMP>' \
  --header 'User-Agent: my-app/1.0'
```

The response returns the stored Virtual Account payload plus the current status:

| Field                                                | Description                                                                                                  |
| ---------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
| `id`, `merchantOrderId`, `reference`                 | Order identifiers                                                                                            |
| `paymentStatus`, `userMintStatus`, `adminMintStatus` | Current state — see [Transaction History](/api/transaction-api/get-api-transaction-user-transaction-history) |
| `paymentAmount`, `toBeMinted`                        | Amounts                                                                                                      |
| `txHash`                                             | On-chain mint hash, once minted                                                                              |
| `paymentMethod`                                      | `"va"`                                                                                                       |
| `virtualAccountNo`, `virtualAccountName`             | The Virtual Account details                                                                                  |
| `expiredDate`                                        | When the payment instrument expires                                                                          |

Only the partner that created the order can retrieve it.

{% hint style="info" %}
Re-requesting a payload for an order that already has one is safe — the same VA number is returned rather than a new one being generated.
{% endhint %}

***

### Confirming payment

Status tracking is identical in both flows — the fields, the callback, and the terminal states do not depend on how the payment was collected.

A transaction has two status fields you must track together:

| Field            | Tracks                                   |
| ---------------- | ---------------------------------------- |
| `paymentStatus`  | The fiat payment (VA or hosted checkout) |
| `userMintStatus` | The on-chain token delivery              |

#### Success state

```
paymentStatus: PAID
userMintStatus: MINTED
```

#### Terminal states

* `MINTED`
* `REFUND`
* `REJECTED`
* `paymentStatus: EXPIRED`

Confirm via [callback](/api/callback), or poll [Transaction History](/api/transaction-api/get-api-transaction-user-transaction-history) by `merchantOrderId` and stop on a terminal state.

> Full state machine, reconciliation pattern, and edge cases: [Processing Mint IDRX Requests](/integration/processing-mint-idrx-requests#step-2-track-the-status)

{% hint style="warning" %}
**Callbacks are sent once and not retried.** If your endpoint is down, you must reconcile by polling the Transaction History API. Always re-fetch the transaction before crediting users — treat the callback body as untrusted input.
{% endhint %}

***

### Errors

| Status | Cause                                                                                 | Fix                                                                                                                          |
| ------ | ------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `400`  | Invalid parameter                                                                     | Check param types and limits                                                                                                 |
| `400`  | `invalid toBeMinted: IDRX on chainId <id> supports <n> decimal place(s), got <value>` | The amount is finer than IDRX on that chain. Round it — whole numbers on Polygon and BNB Chain, at most 2 decimals elsewhere |
| `401`  | Bad signature or timestamp drift                                                      | Recompute signature; sync server clock (NTP)                                                                                 |
| `401`  | `User is not verified`                                                                | The account must complete verification before it can transact                                                                |
| `403`  | Blocked `User-Agent`                                                                  | Set custom `User-Agent` like `my-app/1.0`                                                                                    |
| `422`  | Unsupported `channelId` for merchant                                                  | Contact <support@idrx.co> to enable                                                                                          |
| `429`  | Rate limit                                                                            | Back off and retry                                                                                                           |
| `5xx`  | Server error                                                                          | Retry with backoff. Don't create a new order — recover the payload instead                                                   |

***

### See also

* [Callback](/api/callback) — webhook payload structure, fee breakdown per payment method, and reconciliation tips.
* [Processing Mint IDRX Requests](/integration/processing-mint-idrx-requests) — end-to-end mint workflow with status state machine and edge cases.
* [Transaction History API](/api/transaction-api/get-api-transaction-user-transaction-history) — query transaction state by `merchantOrderId`.
* [Generating a Signature](/api/generating-a-signature) — HMAC-SHA256 signature reference with code examples.

***

The amount the customer pays is not the same as `toBeMinted` — fees are applied on top of it, or deducted from the minted IDRX, depending on the payment method. In Flow A the final figure is shown on the checkout page; in Flow B it comes back as `amount` in the response.

Shortly after the payment is done, IDRX tokens will be minted and sent to the specified destination wallet address. In the case of "usdt" `requestType`, USDT tokens will be sent to the wallet address.

To check the status of the transaction, you can use the [Transaction History API](/api/transaction-api/get-api-transaction-user-transaction-history).


# POST /api/transaction/redeem-request

Use this API to request a IDRX redeem transaction.

{% hint style="info" %}
Check out [this page](/introduction/supported-chain-and-contract-address) to see the list of chains where IDRX is available and [this page](/integration/processing-redeem-idrx-requests/redeeming-from-other-stablecoins) to see the list of supported other stablecoins.
{% endhint %}

{% hint style="info" %}
The balance will be processed and credited to \`**`` bankAccount` ``** max 24 hours after your request is submitted.

* Minimum transaction:
  * Redeeming IDRX is Rp20,000 IDR
  * Redeeming other stablecoins are $2 USD
* Maximum transaction:
  * Redeeming IDRX is 1,000,000,000 IDR.
  * Redeeming other stablecoins are 5,555 USD
* For transactions more than the maximum limit, please send your request to <support@idrx.co> to be processed.
* IDRX is not responsible if a redeem error occurs due to an incorrect bank/e-wallet account number.
  {% endhint %}

## Parameters

1. **`txHash` (String):**

   This parameter is the transaction hash for the burning transaction of the token.
2. **`networkChainId` (String):**

   This parameter identifies the blockchain network on which the redemption transaction occurred.
3. **`amountTransfer` (String):**

   This parameterspecifies the amount of fiat currency that was transferred as part of the redemption process. It represents the monetary value equivalent to the redeemed stable tokens.
4. **`bankAccount` (String):**

   This parameter is the bank account number provided by the user or recipient, where the fiat funds are received after the redemption process.
5. **`bankCode` (String):**

   This parameter represents the code associated with the recipient's bank. It is used to identify the specific bank where the provided `bankAccount` is held. Please use the [**Get Methods API**](/api/transaction-api/get-api-transaction-method) to get a list of bank codes and bank names
6. **`bankName` (String):**

   This parameter refers to the name of the recipient's bank. Please use the [**Get Methods API**](/api/transaction-api/get-api-transaction-method) to get a list of bank codes and bank names
7. **`bankAccountName` (String):**

   This parameter represents the name associated with the recipient's bank account. It specifies the legal or account holder's name for the provided bank account number.
8. **`walletAddress` (String):**

   This parameter is the recipient's blockchain wallet address. While the fiat funds are sent to the bank account, this parameter provides the corresponding blockchain wallet address, allowing cross-verification and transparency.
9. **`notes` (String):**

   When redeeming to a bank account with a different account holder name than your IDRX account, please fill in this parameter to describe the reason or purpose of the transaction.

### Example Request

```
curl -X POST '<https://idrx.co/api/transaction/redeem-request>' --header 'idrx-api-key: <API_KEY>' --header 'idrx-api-sig: <signature>' --header 'idrx-api-ts': <timestamp>'
```

**Payload**

```json
{
  "txHash": "string",
  "networkChainId": "string",
  "amountTransfer": "string",
  "bankAccount": "string",
  "bankCode": "string",
  "bankName": "string",
  "bankAccountName": "string",
  "walletAddress": "string",
  "notes": "string"
}
```

## Response

If the request is successful, the response will be as shown below:

```json
{
  "statusCode": 201,
  "message": "success",
  "data": {
    "id": 14,
    "chainId": 80001,
    "userId": 3,
    "requester": "Test Account",
    "txHash": "0xd946812e2b0fd4796f9deceb278e37ee4d5a456f7a39c0fff05744d2956543a9",
    "fromAddress": "string",
    "amount": "100000",
    "bankName": "BANK CENTRAL ASIA",
    "bankCode": "014",
    "bankAccountNumber": "8760673566",
    "bankAccountName": "Test Account",
    "custRefNumber": "000000169595",
    "disburseId": 205337,
    "burnStatus": "REQUESTED",
    "createdAt": "2023-04-05T00:35:45.374Z",
    "updatedAt": "2023-04-05T00:35:45.374Z",
    "deleted": false
  }
}
```

## Retrying safely

Each burn transaction can only be redeemed once. If you submit a `txHash` that has already been redeemed, the request does **not** fail and does not create a second redeem — it returns `200` with a different shape:

```json
{
  "statusCode": 200,
  "message": "success",
  "data": {
    "alreadyExists": true,
    "redeemRequestId": 14
  }
}
```

This makes retries safe: if a request times out and you are unsure whether it went through, resubmit the same `txHash`. Check for `data.alreadyExists` to tell a fresh redeem (`201`) from a replay (`200`), and use `redeemRequestId` to look up the original.

To check the status of your transaction, you can use the [Transaction History API](/api/transaction-api/get-api-transaction-user-transaction-history).


# POST /api/transaction/bridge-request

Use this API to request a IDRX bridge transaction.

{% hint style="info" %}
Check [this page](https://docs.idrx.co/introduction/supported-chain-and-contract-address) to see the list of chains where IDRX is available
{% endhint %}

{% hint style="info" %}

* The balance will be processed and credited to \`**`` destinationWalletAddress` ``** max 24 hours after your request is submitted.
* Minimum transaction is 20,000 IDR.
  {% endhint %}

## Parameters

1. **`txHashBurn` (String):**

   This parameter represents the unique transaction hash or identifier associated with the burning (redeeming) of IDRX tokens.
2. **`bridgeToChainId` (Number):**

   This parameter identifies the target blockchain network where the stable tokens are being bridged.
3. **`bridgeFromChainId` (Number):**

   This parameter indicates the source blockchain network from which the stable tokens are being bridged.
4. **`amount` (String):**

   This parameter specifies the quantity or value of stable tokens being bridged.
5. **`bridgeNonce` (String):**

   This parameter is a unique identifier received from the burning transaction event. It acts as a nonce, ensuring the uniqueness of the bridging transaction.
6. **`destinationWalletAddress` (String):**

   This wallet address that will receive the bridged amount.

### Example Request

```
curl -X POST '<https://idrx.co/api/transaction/bridge-request>' --header 'idrx-api-key: <API_KEY>' --header 'idrx-api-sig: <signature>' --header 'idrx-api-ts': <timestamp>'
```

**Payload**

```json
{
  "txHashBurn": "string",
  "bridgeToChainId": 0,
  "bridgeFromChainId": 0,
  "amount": "string",
  "bridgeNonce": "string",
  "destinationWalletAddress": "string"
}
```

## Response

If the request is successful, the response will be as shown below:

```json
{
  "statusCode": 201,
  "message": "success",
  "data": {
    "id": 3,
    "userId": 1,
    "bridgeFromChainId": 80001,
    "bridgeToChainId": 97,
    "txHashBurn": "0x38ef6a20db393505fbae51f5f9ec9197013cee21bccafabf8ef37261aa2039d9",
    "txHashMint": null,
    "qredoTxId": null,
    "signedTx": null,
    "bridgeNonce": "0",
    "amount": "100000",
    "bridgeStatus": "REQUESTED",
    "deleted": false
  }
}
```

To check the status of your transaction, you can use the [Transaction History API](/api/transaction-api/get-api-transaction-user-transaction-history).


# GET /api/transaction/method

Use this API to obtain the list of appropriate bank name format and bank codes.

## Example Request

```
curl -X GET '<https://idrx.co/api/transaction/method>' --header 'idrx-api-key: <API_KEY>' --header 'idrx-api-sig: <signature>' --header 'idrx-api-ts': <timestamp>'
```

## Response

If the request is successful, the response will be as shown below:

```json
{
  "statusCode": 200,
  "message": "success",
  "data": [
    {
      "bankCode": "014",
      "bankName": "BANK CENTRAL ASIA",
      "maxAmountTransfer": "100000000"
    },
    {
      "bankCode": "002",
      "bankName": "BANK BRI",
      "maxAmountTransfer": "100000000"
    },
    {
      "bankCode": "200",
      "bankName": "BANK  BTN",
      "maxAmountTransfer": "50000000"
    },
    { .......
```


# GET /api/transaction/user-transaction-history

Use this API to obtain a list of your transaction history.

## Parameters

1. **`transactionType` (String)&#x20;**<mark style="color:red;">**Required**</mark>**: (MINT, BURN, BRIDGE, DEPOSIT\_REDEEM, SEND, USDT\_REQUEST)**

   This parameter is for selecting the type of transaction.
2. **`userMintStatus`(String):**

* NOT\_AVAILABLE : Transaction is waiting for the payment to be finished
* PROCESSING : Minting is being processed
* MINTED : Transaction is minted **(terminal)**
* REJECTED: Transaction is rejected **(terminal)**
* REFUND: Transaction is refunded **(terminal)**

3. **`paymentStatus` (String):**

* PAID : Transaction is paid
* WAITING\_FOR\_PAYMENT: Transaction is waiting for payment
* EXPIRED: The payment request is expired

4. **`burnStatus` (String):**

* PENDING: The burn transaction has not been fully confirmed on-chain yet
* REQUESTED: Transaction has been requested
* IN\_PROCESS: Transaction is being processed
* ACTION\_REQUIRED: The disbursement needs manual review by our team. This is **not** a failure — do not retry it
* SUCCESS: Redeem transaction is successful **(terminal)**
* FAILED: Redeem transaction is failed **(terminal)**
* INVALID: The request was rejected during validation **(terminal)**
* REJECTED: The request was rejected after review **(terminal)**

{% hint style="warning" %}
Only `SUCCESS`, `FAILED`, `INVALID` and `REJECTED` are terminal. If you poll until "SUCCESS or FAILED", a redeem sitting in `PENDING` or `ACTION_REQUIRED` will loop forever — treat those as still in progress and keep polling.
{% endhint %}

5. **`bridgeStatus` (String):**

* PENDING: The burn transaction has not been fully confirmed on-chain yet
* REQUESTED: Transaction has been requested
* PROCESSING: Transaction is being processed
* APPROVED: Transaction has been approved and is awaiting execution
* SUCCESS: Bridge transaction is successful **(terminal)**
* FAILED: Bridge transaction is failed **(terminal)**
* REJECTED: The request was rejected after review **(terminal)**
* EXPIRED: The request expired before it could be processed **(terminal)**

6. **`merchantOrderId`(String):**

   This parameter filters the transaction based on the merchant order ID.
7. **`originChainId`(Number):**

   This parameter filters the transaction based on the origin chain ID.
8. **`destinationChainId` (Number):**

   This parameter filters the transaction based on the target chain ID.
9. **`amountMax`(String):**

   This parameter filters the transaction based on the maximum IDRX amount transacted.
10. **`amountMin`(String):**

    This parameter filters the transaction based on the minimum IDRX amount transacted.
11. **`txHash`(String):**

    This parameter filters the transaction based on the transaction hash.
12. **`orderByDate`(String):**

    This parameter filters the date in an ascending (**ASC**) or descending (**DESC**) order.
13. **`orderByAmount`(String):**

    This parameter filters the amount in an ascending (**ASC**) or descending (**DESC**) order.
14. **`page`(String)&#x20;**<mark style="color:red;">**Required**</mark>**:**

    This parameter specifies the page number of the data to be retrieved.
15. **`take`(String)&#x20;**<mark style="color:red;">**Required**</mark>**:**

    This parameter specifies the amount of data to be retrieved per page.
16. **`transferTxHash`(String):**

    For DEPOSIT\_REDEEM type, the transfer tx hash of the USDT deposit transaction.
17. **`burnTxHash`(String):**

    For DEPOSIT\_REDEEM type, the IDRX burn tx hash of the USDT deposit transaction.

## Example Request

```
curl '<https://idrx.co/api/transaction/user-transaction-history?transactionType=BRIDGE&page=1&take=10>' --header 'idrx-api-key: <API_KEY>' --header 'idrx-api-sig: <signature>' --header 'idrx-api-ts': <timestamp>'
```

## Response

If the request is successful, the response will be as shown below:

Example for transactionType MINT:

```json
{
    "statusCode": 200,
    "message": "success",
    "metadata": {
        "page": null,
        "perPage": null,
        "pageCount": null,
        "totalCount": 1
    },
    "records": [
        {
            "id": 311,
            "paymentAmount": 54500,
            "merchantOrderId": "20231219101707",
            "productDetails": "Minting IDRX",
            "customerVaName": "JOHN SMITH",
            "email": "john.smith@gmail.com;IDRX",
            "chainId": 137,
            "destinationWalletAddress": "0x8BD53F7fF88fD895D3686fe6369a07432822d30F",
            "toBeMinted": "19860",
            "merchantUserInfo": 411,
            "createdAt": "2023-12-19T10:17:07.903Z",
            "updatedAt": "2023-12-19T10:57:15.197Z",
            "paymentStatus": "PAID",
            "expiryTimestamp": "1703197027900",
            "reference": "D11808T8GVTL81VV2U7HV",
            "txHash": "0xb8a0b017d96b49813814026cd01a3ceb169b33ab01b895c222c36c241d2ad3cb",
            "qredoTxId": "2Zl4ZG8dr5tyfdSfm6aF3PrpxU4",
            "adminMintStatus": "MINTED",
            "userMintStatus": "MINTED",
            "reportStatus": "APPROVED",
            "requestType": "",
            "userId": 101,
            "refundStatus": null,
            "fee": 140,
            "paymentCode": "IQ",
            "fees": [
              { 
                "name": "Payment Method Fee", 
                "amount": "140" 
              }
            ]
        }
    ]
}
```

Example for transactionType MINT with requestType `usdt`:

```json
{
    "statusCode": 200,
    "message": "success",
    "metadata": {
        "page": null,
        "perPage": null,
        "pageCount": null,
        "totalCount": 1
    },
    "records": [
          {
            "id": 10,
            "paymentAmount": 22320,
            "merchantOrderId": "20231004154713",
            "productDetails": "Minting IDRX",
            "customerVaName": "JOHN SMITH",
            "email": "john.smith@gmail.com;IDRX",
            "chainId": 137,
            "destinationWalletAddress": "0x4313816F7Bfcff384053C70365eb6F3a4dbDD39f",
            "toBeMinted": "19860",
            "merchantUserInfo": 1,
            "createdAt": "2023-10-04T08:47:13.910Z",
            "updatedAt": "2023-10-04T08:51:33.692Z",
            "paymentStatus": "PAID",
            "expiryTimestamp": "1696495633902",
            "reference": "DS1507923ZZSZSKOMRNDZD23",
            "txHash": "0x575f9495e3dd0d629a732e4e4c787954368350f2dc379df7d6588654bee69526",
            "qredoTxId": "2WI9cLKJm66tsZy6jhdXOfmnJmH",
            "adminMintStatus": "MINTED",
            "userMintStatus": "MINTED",
            "isApproved": true,
            "reportStatus": "NONE",
            "requestType": "usdt",
            "userId": 101,
            "refundStatus": null,
            "usdtRequest": {
                "destinationWalletAddress": "0x8bd53f7ff88fd895d3686fe6369a07432822d30f",
                "chainId": 137,
                "transferTxHash": "0x65a8bfbcf9b6de2d6115d27033d16c8bc3220fc95f3c146a13ce92ead4a54de6",
                "usdtRequested": "1.11",
                "amountIdrx": 17320,
                "amountUsdt": "1.10975",
                "swapTxHash": "0xc9629766275e50982e6b2b12f9bb87f4ac469c036dd066899e2b2a53acd76d12",
                "status": "SUCCESS"
            },
            "fee": 140,
            "paymentCode": "IQ",
            "fees": [
              { 
                "name": "Payment Method Fee", 
                "amount": "140" 
              }
            ]
        }
    ]
}
```

Example for transactionType BURN:

```json
{
    "statusCode": 200,
    "message": "success",
    "metadata": {
        "page": null,
        "perPage": null,
        "pageCount": null,
        "totalCount": 1
    },
    "records": [
        {
            "id": 121,
            "userId": 411,
            "txHash": "0xa38c057222872d8e3d106ab5f9b86b7d1d6ade72d485eb01366650e45c8a65d0",
            "amount": "16000",
            "bankName": "BANK CENTRAL ASIA",
            "bankAccountNumber": "5260759037",
            "burnStatus": "SUCCESS",
            "createdAt": "2023-12-19T11:05:42.583Z",
            "updatedAt": "2023-12-19T11:33:53.865Z",
            "bankCode": "014",
            "custRefNumber": "000028881450",
            "disburseId": 17610583,
            "fromAddress": "0x8BD53F7fF88fD895D3686fe6369a07432822d30F",
            "chainId": 137,
            "requester": "JOHN SMITH",
            "bankAccountName": "WILDAN RAMADHAN               ",
            "bankAccountNumberHash": null,
            "notes": null,
            "reportStatus": "APPROVED"
        }
    ]
}
```

Example for transactionType DEPOSIT\_REDEEM:

```json
{
    "statusCode": 200,
    "message": "success",
    "metadata": {
        "page": null,
        "perPage": null,
        "pageCount": null,
        "totalCount": 1
    },
    "records": [
        {
            "id": 8,
            "address": "0x4313816f7bfcff384053c70365eb6f3a4dbdd39f",
            "transferTxHash": "0xfba5abf029e8c7a29ee71a5a92366b5e776ee10bdcdf6df69bc512dce9742f41",
            "tokenFrom": "usdt",
            "amountFrom": "112",
            "swapTxHash": "0x3ad1724f31b146eda4ba1fe90214548180919b33df9b85f510d671f6ea5d9210",
            "amountTo": "1692000",
            "burnTxHash": "0x191967dc3cd12924027762ff9f90a069394c070baf5bf37afffa44b85b42c108",
            "status": "SUCCESS",
            "createdAt": "2024-01-09T09:15:02.048Z",
            "updatedAt": "2024-01-11T09:52:48.060Z",
            "tokenTo": "idrx",
            "toAddress": "0xddb154f503ccd047555a976b01069471a0ab4068",
            "userId": 101,
            "chainId": 137,
            "requester": "JOHN SMITH",
            "bankAccountName": "JOHN SMITH",
            "bankAccountNumber": "5260759037",
            "bankAccountNumberHash": null,
            "bankCode": "014",
            "bankName": "BANK CENTRAL ASIA",
            "amountRedeem": "1687000",
            "txType": 'USDT'
        }

    ]
}
```

Example for transactionType BRIDGE:

```json
{
  "statusCode": 200,
  "message": "success",
  "metadata": {
    "page": 1,
    "perPage": 10,
    "pageCount": 1,
    "totalCount": 3
  },
  "records": [
    {
      "id": 3,
      "userId": 1,
      "bridgeFromChainId": 80001,
      "bridgeToChainId": 97,
      "txHashBurn": "0x38ef6a20db393505fbae51f5f9ec9197013cee21bccafabf8ef37261aa2039d9",
      "txHashMint": null,
      "qredoTxId": null,
      "signedTx": null,
      "bridgeNonce": "0",
      "amount": "100000",
      "bridgeStatus": "REQUESTED",
      "deleted": false
    }
  ]
}
```


# GET /api/transaction/rates

Get current swap rates of IDRX to other tokens.

## Parameters

1. **`idrxAmount` (String):**

   The IDRX amount to sell.
2. **`usdtAmount` (String):**

   The USDT/USDC amount to sell.
3. **chainId (String):**\
   Blockchain ID.

You must provide either one of `idrxAmount` or `usdtAmount` as parameter. `chainId` will default to 137 (Polygon) if left unspecified.

## Example Request

```
curl '<https://idrx.co/api/transaction/rates?usdtAmount=15>' --header 'idrx-api-key: <API_KEY>' --header 'idrx-api-sig: <signature>' --header 'idrx-api-ts': <timestamp>'
```

## Response

If the request is successful, the response will be as shown below:

```json
{
    "statusCode": 200,
    "message": "success",
    "data": {
        "price": "17171",
        "buyAmount": "34342",
        "chainId": 56,
        "quote": {
          "expectedResult": {
            "min": 1.988408,
            "max": 2
          }
        }
    }
}
```

`buyAmount` represents the IDRX amount you would get from the specified USDT/USDC amount in the parameter.


# GET /api/transaction/get-additional-fees

Get additional fees of different transaction types.

{% hint style="info" %}

* Additional fees apply for redeeming token
  * Redeeming token worth of ≤ Rp250,000,000 IDR
    1. Fee: Rp5,000
    2. Processing: Real-time
  * Redeeming token worth of > Rp250,000,000 IDR and < Rp1,000,000,000 IDR
    1. Fee: Rp35,000
    2. Processing: Only during office hours (Monday–Friday, 08:00–15:00 WIB)
       {% endhint %}

## Parameters

1. **`feeType` (String):**

   The type of the transaction fee. Possible values are 'MINT', 'REDEEM', 'REFUND', 'BRIDGE'.
2. **`chainId` (String):**\
   Blockchain ID.
3. **`payment` (String):**

   The transaction amount. Fees are tiered by amount, so without this the response returns the base fee rather than the one that will actually apply to your transaction.
4. **`bankCode` (String):**

   The destination bank code, for `REDEEM`. Some fees depend on the receiving bank. Get the list from the [Get Methods API](/api/transaction-api/get-api-transaction-method).

{% hint style="info" %}
Pass `payment` and `bankCode` whenever you know them. The fee returned without them is not necessarily the fee that will be charged.
{% endhint %}

## Example Request

```
curl '<https://idrx.co/api/transaction/get-additional-fees?feeType=REDEEM>' --header 'idrx-api-key: <API_KEY>' --header 'idrx-api-sig: <signature>' --header 'idrx-api-ts': <timestamp>'
```

## Response

If the request is successful, the response will be as shown below:

```json
{
    "statusCode": 200,
    "message": "success",
    "data": [
        {
            "id": 1,
            "name": "Payment Gateway Fee",
            "amount": "3000",
            "isActive": true,
            "deleted": false
        }
    ]
}
```

`isActive` indicates if the fee is currently active and should be calculated in the transaction.


# Callback

Get notified when there is an update for transactions

Callback allows you to receive a notification when a minting or redemption transaction is completed. To use Callback, you must first generate an [**API Key**](/api/getting-started). Once you have your API Key, navigate to the **API Key** menu and select the **Callback URL** tab to set it up.

<figure><img src="/files/m0xAbfV8DFuARhHyM15H" alt=""><figcaption></figcaption></figure>

Enter your Mint and Redeem Callback URLs. You may use a single endpoint for both callbacks if preferred. Once done, click the **Save Callback URL** button to confirm.

<figure><img src="/files/RgY2hkzeyuxfzkrI5ZtA" alt=""><figcaption></figcaption></figure>

You’ll see a notification in the bottom-right corner once the Callback URL is successfully saved.

<figure><img src="/files/RgY2hkzeyuxfzkrI5ZtA" alt=""><figcaption></figcaption></figure>

You can then use the endpoint to receive callbacks in your logs whenever there’s an update to your mint or redeem transactions. Please refer to the example below.

### Delivery rules

These rules apply to both mint and redeem callbacks:

* **One callback per terminal state.** The mint callback fires once when `adminMintStatus` transitions to `MINTED`. If your endpoint is unreachable, the callback is **not** retried automatically — respond with `2xx` quickly and process asynchronously on your side.
* **No signature on the outgoing webhook.** Reconcile by `merchantOrderId` against your own state. Treat the request as untrusted until you've matched it and re-verified via Transaction History API.
* **Body is `application/json`.** Headers are minimal — only the standard `Content-Type`.
* **Two mint flavours:**
  * **IDRX mint** — when `requestType` is empty or `"idrx"`. Fires after IDRX is minted on-chain.
  * **USDT onramp** — when `requestType` is `"usdt"`. Fires after the IDRX→USDT swap and USDT transfer to the destination wallet succeed.

{% hint style="warning" %}
Since callbacks are not retried, missed deliveries must be reconciled by polling the Transaction History API using `merchantOrderId`.
{% endhint %}

***

## Mint callback

### Payload structure

Every mint callback body has these top-level fields:

| Field                        | Type           | Description                                                                           |
| ---------------------------- | -------------- | ------------------------------------------------------------------------------------- |
| `id`                         | number         | Internal MintRequest ID                                                               |
| `paymentAmount`              | number         | Amount the user paid in IDR (before fees)                                             |
| `toBeMinted`                 | string         | IDRX amount minted (= `paymentAmount` minus deducted fees)                            |
| `merchantOrderId`            | string         | Your order ID                                                                         |
| `destinationWalletAddress`   | string         | Wallet that received the IDRX or USDT                                                 |
| `chainId`                    | number         | EVM chain ID                                                                          |
| `paymentStatus`              | enum           | `WAITING_FOR_PAYMENT` / `PAID` / `EXPIRED`                                            |
| `userMintStatus`             | enum           | `PROCESSING` / `MINTED` / `NOT_AVAILABLE`                                             |
| `adminMintStatus`            | enum           | Internal operational state. Informational only — build your logic on `userMintStatus` |
| `txHash`                     | string         | On-chain mint transaction hash                                                        |
| `reference`                  | string         | Payment gateway reference                                                             |
| `requestType`                | string         | `null` / `"idrx"` / `"usdt"`                                                          |
| `customerVaName`             | string         | Source account name                                                                   |
| `paymentProviderId`          | number \| null | Internal payment routing reference. Informational only                                |
| `returnUrl`                  | string \| null | Echoed back from original request                                                     |
| `expiryTimestamp`            | string         | Unix epoch milliseconds                                                               |
| `isApproved`                 | boolean        | Multisig approval flag                                                                |
| `reportStatus`               | enum           | `NONE` / `REJECTED` / `PROCESSING` / `APPROVED`                                       |
| `processByUserId`            | number \| null | Admin processor                                                                       |
| `qredoTxId`                  | string \| null | Safe multisig transaction hash                                                        |
| `signedTx`                   | string \| null | Solana signed transaction blob                                                        |
| `deleted`                    | boolean        | Soft-delete flag                                                                      |
| `createdAt`                  | ISO 8601       | Creation timestamp                                                                    |
| `updatedAt`                  | ISO 8601       | Last updated timestamp                                                                |
| `TransactionHistory`         | object         | Payment gateway notification                                                          |
| `MintRequestTransactionFees` | array          | Fee breakdown                                                                         |
| `usdtRequest`                | object \| null | USDT swap details                                                                     |

{% hint style="info" %}
The callback payload and all status fields are identical whether the order was created through [Flow A or Flow B](/api/transaction-api/post-api-transaction-mint-request#choosing-a-flow).
{% endhint %}

***

### `TransactionHistory` sub-object

```jsonc
{
  "id": 21468,
  "merchantCode": "D11808",
  "amount": "55000",
  "merchantOrderId": "20260508154603",
  "productDetail": "Deposit USD",
  "additionalParam": "toBeMinted: 55000 destinationWalletAddress: 0x...",
  "resultCode": "00",
  "signature": "4f9cabb4aac2b04fbc02a3b039a906fc",
  "paymentCode": "BR",
  "merchantUserId": 5002,
  "reference": "D11808261VSEBJBL43V2ZIW",
  "spUserHash": null,
  "issuerCode": null,
  "settlementDate": "2026-05-09",
  "publisherOrderId": "BR26BOLMOR7DDYK18WA",
  "sourceAccount": "",
  "deleted": false,
  "createdAt": "2026-05-08T15:47:58.487Z",
  "updatedAt": "2026-05-08T15:47:58.487Z"
}
```

***

### `MintRequestTransactionFees` array

```jsonc
{
  "name": "Payment Method Fee",
  "amount": "609"
}
```

{% hint style="warning" %}
An empty array (`[]`) means the payment channel charges no IDRX-layer fee.\
This is expected behaviour, not missing data.
{% endhint %}

***

### `usdtRequest` sub-object (USDT onramp only)

```jsonc
{
  "id": 13397,
  "mintRequestId": 33685,
  "merchantOrderId": "20260508154603",
  "destinationWalletAddress": "0xadbe359255d723a5ad3706395b446aed5cf285e6",
  "chainId": 8453,
  "amountIdrx": 55000,
  "usdtRequested": "3.174996",
  "amountUsdt": "3.174996",
  "swapTxHash": "0x8a4b781e8c8694bc68906bb85206da174fe3550776e72cbe806f19931732030d",
  "txHash": "0x55b16ff8100f12e9c611f13a7848d16917b477a5d838172c26e3b0d6da1e8617",
  "status": "SUCCESS",
  "deleted": false,
  "createdAt": "2026-05-08T15:46:03.272Z",
  "updatedAt": "2026-05-08T15:49:04.769Z"
}
```

***

## Fee structure by payment method

Two patterns exist depending on the channel:

* **Fee added on top at checkout**
  * `paymentAmount === toBeMinted`
  * `MintRequestTransactionFees = []`
* **Fee deducted from minted IDRX**
  * `toBeMinted` is lower than `paymentAmount`
  * A fee row appears in `MintRequestTransactionFees`

| Channel | `paymentCode` | IDRX fee  | Charged how  | Effect           |
| ------- | ------------- | --------- | ------------ | ---------------- |
| BNI VA  | `IQ`          | 3,000 IDR | Added on top | Fees array empty |
| BRI VA  | `BR`          | 3,000 IDR | Added on top | Fees array empty |
| OVO     | `OV`          | 1.67%     | Added on top | Fees array empty |
| DANA    | `DA`          | 1.67%     | Added on top | Fees array empty |

{% hint style="info" %}
**QRIS is temporarily undocumented.** QRIS remains a supported payment method and is not being withdrawn — its documentation is hidden while we carry out maintenance, and will be restored afterwards. If you need QRIS details in the meantime, contact <support@idrx.co>.
{% endhint %}

***

### Worked example — 100,000 IDR top-up

| Channel       | User pays | IDRX delivered | `paymentAmount` | `toBeMinted` | Fees |
| ------------- | --------- | -------------- | --------------- | ------------ | ---- |
| BRI VA (`BR`) | 103,000   | 100,000        | `100000`        | `"100000"`   | `[]` |
| OVO (`OV`)    | 101,670   | 100,000        | `100000`        | `"100000"`   | `[]` |

Universal reconciliation formula:

```ts
const idrxFee =
  body.paymentAmount -
  parseInt(body.toBeMinted, 10);
```

***

## Mint examples

### IDRX mint via BRI VA (`BR`)

```json
{
  "id": 33687,
  "paymentAmount": 100000,
  "toBeMinted": "100000",
  "merchantOrderId": "20260509093000",
  "destinationWalletAddress": "0xA3aE7A9562E6DDdc693be0c34013637730E2bA00",
  "chainId": 8453,
  "paymentStatus": "PAID",
  "userMintStatus": "MINTED",
  "adminMintStatus": "MINTED",
  "txHash": "0x4b1f8d...c91e72",
  "reference": "D11808261VKLMNO78PQRS",
  "requestType": "idrx",
  "MintRequestTransactionFees": []
}
```

{% hint style="info" %}
Empty `MintRequestTransactionFees` on VA payments is expected behaviour.
{% endhint %}

***

### USDT onramp variant

When `requestType === "usdt"`:

* Callback fires after the IDRX → USDT swap completes
* Payload shape is identical
* `usdtRequest` becomes populated

```json
{
  "id": 13397,
  "mintRequestId": 33685,
  "merchantOrderId": "20260508154603",
  "destinationWalletAddress": "0xadbe359255d723a5ad3706395b446aed5cf285e6",
  "chainId": 8453,
  "amountIdrx": 55000,
  "usdtRequested": "3.174996",
  "amountUsdt": "3.174996",
  "swapTxHash": "0x8a4b781e8c8694bc68906bb85206da174fe3550776e72cbe806f19931732030d",
  "txHash": "0x55b16ff8100f12e9c611f13a7848d16917b477a5d838172c26e3b0d6da1e8617",
  "status": "SUCCESS"
}
```

***

## Reconciliation tips

```ts
// Universal fee calculation
const idrxFee =
  body.paymentAmount -
  parseInt(body.toBeMinted, 10);

// IDRX delivered
const idrxMinted =
  body.usdtRequest
    ? null
    : body.toBeMinted;

// USDT delivered
const usdtDelivered =
  body.usdtRequest?.amountUsdt;

// Effective exchange rate
const rate =
  body.usdtRequest?.amountUsdt
    ? body.paymentAmount /
      parseFloat(body.usdtRequest.amountUsdt)
    : null;
```

For high-value transactions, verify on-chain delivery using `txHash`.

***

## Status handling

Build your logic on `userMintStatus`, together with `paymentStatus`.

| `userMintStatus` | Meaning                 | Action         |
| ---------------- | ----------------------- | -------------- |
| `MINTED`         | Tokens delivered        | Mark success   |
| `REFUND`         | Payment refunded        | Mark cancelled |
| `REJECTED`       | Request rejected        | Mark cancelled |
| `PROCESSING`     | Delivery in flight      | Keep waiting   |
| `NOT_AVAILABLE`  | No minting activity yet | Keep waiting   |

Also treat `paymentStatus: EXPIRED` as terminal — the payment window closed before the customer paid.

{% hint style="info" %}
`adminMintStatus` is an internal operational field. It appears in the payload for reference, but its values can change as our operational process changes — don't build integration logic around it.
{% endhint %}

***

## Redeem callback

### IDRX

```json
{
  id: 1234,
  chainId: 56,
  userId: 1234,
  requester: 'NUR MUHAMMAD LUTHFI',
  txHash: '0xabcdefghijk',
  fromAddress: '0xlmnopqrstuvwxyz',
  amount: '15000',
  bankName: 'BANK JAGO',
  bankCode: '542',
  bankAccountNumber: '123456789',
  bankAccountName: 'NUR MUHAMMAD LUTHFI',
  bankAccountNumberHash: null,
  custRefNumber: '123456789',
  disburseId: 123456789,
  burnStatus: 'SUCCESS',
  createdAt: '2025-07-29T10:48:50.417Z',
  updatedAt: '2025-07-29T10:49:54.691Z',
  deleted: false,
  reportStatus: 'NONE',
  notes: ' | ',
  RedeemRequestTransactionFees: [
    {
      id: 1234,
      name: 'Payment Gateway Fee',
      amount: '5000',
      redeemRequestId: 3456,
      deleted: false
    }
  ]
}
```

***

### USDT / USDC / USDT0

```json
{
  id: 4593,
  chainId: 1135,
  userId: 2255,
  requester: 'NUR MUHAMMAD LUTHFI',
  txHash: '0x8359c8901667923ee0d214fd5100e0b99daea63d5acda2de276cff584461f16c',
  fromAddress: '0x55360Fe4179936e88c321f6e3bd23Ef34E916110',
  amount: '36219',
  bankName: 'GOPAY',
  bankCode: '1011',
  bankAccountNumber: '08123456789',
  bankAccountName: 'GOPAY Nxx Mxxxxxxx Lxxxxx',
  bankAccountNumberHash: null,
  custRefNumber: '000045642625',
  disburseId: 30098713,
  burnStatus: 'SUCCESS',
  createdAt: '2025-08-01T06:50:53.109Z',
  updatedAt: '2025-08-01T06:51:52.473Z',
  deleted: false,
  reportStatus: 'NONE',
  notes: null,
  RedeemRequestTransactionFees: [
    {
      id: 3217,
      name: 'Payment Gateway Fee',
      amount: '5000',
      redeemRequestId: 5943,
      deleted: false
    }
  ],
  depositRedeemRequest: {
    id: 208,
    chainId: 1135,
    userId: 2255,
    address: '0x1095bBe769fDab716A823d0f7149CAD713d20A13',
    toAddress: '0x55360Fe4179936e88c321f6e3bd23Ef34E916110',
    transferTxHash: '0x3e36838c61f3c9f2009d71b1b53dafc1d8eb280bf490e58ab08dee9767dcc842',
    tokenFrom: 'usdt',
    amountFrom: '2.511252',
    tokenTo: 'idrx',
    amountTo: '41219',
    swapTxHash: '0x15187b051f8f6b9da02470cf548f395199429442c445a52ebee44698fad9de93',
    burnTxHash: '0x8359c8901667923ee0d214fd5100e0b99daea63d5acda2de276cff584461f16c',
    status: 'SUCCESS',
    createdAt: '2025-08-01T06:49:06.406Z',
    updatedAt: '2025-08-01T06:50:53.118Z',
    deleted: false
  }
}
```

***

## See also

* [POST /api/transaction/mint-request](/api/transaction-api/post-api-transaction-mint-request) — how mint orders are created.
* [Processing Mint IDRX Requests](/integration/processing-mint-idrx-requests) — end-to-end mint flow with reconciliation pattern.
* [Transaction History API](/api/transaction-api/get-api-transaction-user-transaction-history) — pull state by `merchantOrderId` if a webhook is missed.


# Overview

This section will describe a general flow that an organization might use in utilizing our API.

{% content-ref url="/pages/ToK3C45kVi0XLIrkGh70" %}
[Onboarding a new user](/integration/onboarding-a-new-user)
{% endcontent-ref %}

{% content-ref url="/pages/GjTEX0QC4gXgbA4yGK2X" %}
[Managing bank accounts](/integration/managing-bank-accounts)
{% endcontent-ref %}

{% content-ref url="/pages/se1XX3CgPPnxWocP4lMV" %}
[Processing Mint IDRX Requests](/integration/processing-mint-idrx-requests)
{% endcontent-ref %}

{% content-ref url="/pages/E3xpRuxavV5quYIe2EON" %}
[Processing Redeem IDRX Requests](/integration/processing-redeem-idrx-requests)
{% endcontent-ref %}

{% content-ref url="/pages/HLtxqehmHF30MuyTS6zC" %}
[Processing Bridge IDRX Request](/integration/processing-bridge-idrx-request)
{% endcontent-ref %}


# Onboarding a new user

A typical flow to onboard new users

You can use the [Onboarding API](/api/onboarding-api) to onboard new users to the platform. A new user registered through the api will be a special type of user that's managed under the organization. This type of user does not need to complete certain steps in the KYC flow to simplify the onboarding process.

Firstly, you need to setup your API access. You can read more about that [here](/api/getting-started).

Then, you can use the `POST /api/auth/onboarding` endpoint to register the new user. Here is an example.

```typescript
import { createSignature } from "./createSignature";
const axios = require('axios');

const apiKey = "{YOUR API KEY}";
const secret = "{YOUR SECRET}";

async function onboarding() {
  const path = "https://idrx.co/api/auth/onboarding";

  const form = new FormData();
  form.append("email"    , "john.smith@email.com");
  form.append("fullname" , "JOHN SMITH");
  form.append("address"  , "123 MAIN STREET, APT 1. HARRISBURG. PA 17101-0000");
  form.append("idNumber" , "83123997");
  form.append("idFile"   , fs.createReadStream('./path/to/id_file/83123997.png'));

  const bufferReq = Buffer.from(JSON.stringify(form), 'base64').toString('utf8');
  const timestamp = Math.round((new Date()).getTime()).toString();
  const sig = createSignature('POST', path, bufferReq, timestamp, secret);

  const res = await axios.post(path, form, {
    headers: {
      'Content-Type': 'multipart/form-data',
      'idrx-api-key': apiKey,
      'idrx-api-sig': sig,
      'idrx-api-ts' : timestamp,
    },
  });

  console.log('res.data: ');
  console.log(res.data);
}

onboarding();
```

Please note that the parameters shown are just an example. When onboarding a new user, you must use valid and verifiable data. After a successful operation, you will get a response as follows:

```json
{
  statusCode: 201,
  message: "success",
  data: {
    id: 1011,
    fullname: "JOHN SMITH",
    createdAt: "2023-12-12T08:10:29.077Z",
    apiKey: "fd1c15cb1fd157c7",
    apiSecret: "11b0de01a2cf17c1094db789bfa05eb1adc185482c3ee828a7ba617b83e9b711"
  }
}
```

You can then use the API keys to process requests for the specified user.

{% hint style="warning" %}
**Onboarding is not the same as being verified.** Onboarding through this API skips several steps of the KYC flow, but the account still has to reach a verified state before it can transact. Until then, mint, redeem, bridge and bank-account endpoints reject the request with `401 User is not verified`.

Read-only endpoints such as [Transaction History](/api/transaction-api/get-api-transaction-user-transaction-history) and [Get Methods](/api/transaction-api/get-api-transaction-method) work regardless.
{% endhint %}


# Managing bank accounts

List, add and delete bank accounts.

## Add a new bank account

Here's an example code to add a new bank account.

```typescript
import { createSignature } from "./createSignature";
const axios = require('axios');

const apiKey = "{YOUR API KEY}";
const secret = "{YOUR SECRET}";

async function addBankAccount() {
  const path = "https://idrx.co/api/auth/add-bank-account";

  const req = {
    "bankAccountNumber" : "{BANK ACCOUNT NUMBER}",
    "bankCode"          : "{BANK CODE}",
  };
  const bufferReq = Buffer.from(JSON.stringify(req), 'base64').toString('utf8');
  const timestamp = Math.round((new Date()).getTime()).toString();
  const sig = createSignature('POST', path, bufferReq, timestamp, secret);

  const res = await axios.post(path, req, {
    headers: {
      'Content-Type': 'application/json',
      'idrx-api-key': apiKey,
      'idrx-api-sig': sig,
      'idrx-api-ts' : timestamp,
    },
  });

  console.log('res.data: ');
  console.log(JSON.stringify(res.data, null, 4));
}

addBankAccount();
```

You can get a list of available bank codes from [this api](/api/transaction-api/get-api-transaction-method).

After a successful request, you will get a response as follows:

```typescript
{
    "statusCode": 201,
    "message": "success",
    "data": {
        "id": 108,
        "userId": 411,
        "bankAccountNumber": "5017332241",
        "bankAccountName": "JOHN SMITH",
        "bankAccountNumberHash": null,
        "bankCode": "014",
        "bankName": "BANK CENTRAL ASIA",
        "maxAmountTransfer": "100000000",
        "deleted": false,
        "DepositWalletAddress": {
            "walletAddress": "0x07C158ab29f23D0821e7D24B191c5e5d9d72738b",
            "createdAt": "2024-01-17T10:34:22.304Z"
        }
    }
}
```

Notice that a deposit wallet address is also included. Users can send funds to this deposit address to request a redeem to the associated bank account.

To list currently registered bank accounts, you can use [this api](/api/onboarding-api/get-api-auth-get-bank-accounts).

## Delete a bank account

Here's an example code to delete an existing bank account.

```typescript
import { createSignature } from "./createSignature";
const axios = require('axios');

const apiKey = "{YOUR API KEY}";
const secret = "{YOUR SECRET}";

async function deleteBank(bankId: string) {
  const path = "https://idrx.co/api/auth/delete-bank-account/"+bankId;

  const bufferReq = Buffer.from('', 'base64').toString('utf8');
  const timestamp = Math.round((new Date()).getTime()).toString();
  const sig = createSignature('GET', path, bufferReq, timestamp, secret);

  const res = await axios.delete(path, {
    headers: {
      'Content-Type': 'application/json',
      'idrx-api-key': apiKey,
      'idrx-api-sig': sig,
    },
  });

  console.log('res.data: ');
  console.log(JSON.stringify(res.data, null, 4));
}

deleteBank('108');
```

After a successful request, you will get a response as follows:

```typescript
{
    "statusCode": 200,
    "message": "deleted",
    "data": null
}
```


# Processing Mint IDRX Requests

The typical flow to process mint requests from your user

Using a user account's API key, you can process mint requests for the specified user. To do so, you can use the `POST /api/transaction/mint-request` endpoint. Here is an example implementation.

{% hint style="info" %}
Check [this page](https://docs.idrx.co/introduction/supported-chain-and-contract-address) to see the list of chains where IDRX is available
{% endhint %}

{% hint style="info" %}

* The balance will be processed and credited to \`**`` destinationWalletAddress` ``** max 24 hours after your request is submitted.
* Minimum transaction for IDRX is Rp20,000 IDR
* Maximum transaction for IDRX is 1,000,000,000 IDR.
* For transactions more than the maximum limit, please send your request to <support@idrx.co> to be processed.
* The transaction will be automatically canceled if you have not made a payment within 24 hours.
* IDRX is not responsible for deposit errors from incorrect Virtual Account numbers. Refunds for payments made to Virtual Account numbers under a different name will be processed within 14 business days.
  {% endhint %}

### Overview

A mint request flows through two independent state machines:

1. **Payment** — tracked by `paymentStatus`. Reflects the state of the fiat payment (Virtual Account or hosted checkout).
2. **Minting** — tracked by `userMintStatus`. Reflects the on-chain delivery of IDRX (or other token) to the destination wallet.

Both fields are returned by the [Transaction History API](/api/transaction-api/get-api-transaction-user-transaction-history) and must be tracked together to determine the final outcome.

### Step 1 — Create the Mint Request

Use your API key to call:

```http
POST /api/transaction/mint-request
```

#### Example Implementation

```typescript
import { createSignature } from "./createSignature";
const axios = require("axios");

const apiKey = "{YOUR API KEY}";
const secret = "{YOUR SECRET}";

async function mintRequest() {
  const path = "https://idrx.co/api/transaction/mint-request";

  const req = {
    toBeMinted: "51500",
    destinationWalletAddress: "0x8BD53F7fF88fD895D3686fe6369a07432822d30F",
    expiryPeriod: 60,
    networkChainId: "137",
    returnUrl: "https://your-app.example.com/callback",
    requestType: "idrx",
    paymentProvider: "snap"
  };

  const bufferReq = Buffer
    .from(JSON.stringify(req), "base64")
    .toString("utf8");

  const timestamp = Date.now().toString();

  const sig = createSignature(
    "POST",
    path,
    bufferReq,
    timestamp,
    secret
  );

  const res = await axios.post(path, req, {
    headers: {
      "Content-Type": "application/json",
      "idrx-api-key": apiKey,
      "idrx-api-sig": sig,
      "idrx-api-ts": timestamp,
      "User-Agent": "my-app/1.0"
    }
  });

  console.log(res.data);

  return res.data.data.merchantOrderId;
}
```

#### Example Response

```json
{
  "statusCode": 200,
  "message": "success",
  "data": {
    "id": 1234,
    "merchantOrderId": "20260728130000",
    "reference": "SNAP-20260728130000",
    "checkoutUrl": "https://checkout.idrx.co?token=eyJhbGciOi...",
    "paymentUrl": "https://checkout.idrx.co?token=eyJhbGciOi..."
  }
}
```

{% hint style="info" %}
Store `merchantOrderId` in your database — it is required for status tracking and reconciliation.
{% endhint %}

The user then completes payment using `paymentUrl`.

The steps above use the hosted checkout page (**Flow A**). If you want to own the payment screens yourself — mobile app, white-label web, kiosk — use **Flow B** instead: send `paymentProvider: "snap"` with `paymentMethod` and `channelId`, and the Virtual Account number comes back directly in the mint response. Everything after that point (status tracking, callbacks, reconciliation) is identical to what is described below.

See [Flow B — Direct payment](/api/transaction-api/post-api-transaction-mint-request#flow-b-direct-payment).

***

### Step 2 — Track the Status

Query Transaction History using `merchantOrderId`.

#### Example Request

```typescript
import { createSignature } from "./createSignature";
const axios = require("axios");

const apiKey = "{YOUR API KEY}";
const secret = "{YOUR SECRET}";

async function getMintStatus(merchantOrderId: string) {
  const path =
    `https://idrx.co/api/transaction/user-transaction-history` +
    `?transactionType=MINT` +
    `&merchantOrderId=${merchantOrderId}` +
    `&page=1&take=1`;

  const bufferReq = Buffer
    .from("", "base64")
    .toString("utf8");

  const timestamp = Date.now().toString();

  const sig = createSignature(
    "GET",
    path,
    bufferReq,
    timestamp,
    secret
  );

  const res = await axios.get(path, {
    headers: {
      "Content-Type": "application/json",
      "idrx-api-key": apiKey,
      "idrx-api-sig": sig,
      "idrx-api-ts": timestamp,
      "User-Agent": "my-app/1.0"
    }
  });

  return res.data.records[0];
}
```

#### Example Response

```json
{
  "statusCode": 200,
  "message": "success",
  "metadata": {
    "page": 1,
    "perPage": 1,
    "pageCount": 1,
    "totalCount": 1
  },
  "records": [
    {
      "id": 311,
      "paymentAmount": 54500,
      "merchantOrderId": "20231219101707",
      "productDetails": "Minting IDRX",
      "customerVaName": "JOHN SMITH",
      "destinationWalletAddress": "0x8BD53F7fF88fD895D3686fe6369a07432822d30F",
      "toBeMinted": "51500",
      "chainId": 137,
      "createdAt": "2023-12-19T10:17:07.903Z",
      "paymentStatus": "WAITING_FOR_PAYMENT",
      "userMintStatus": "NOT_AVAILABLE",
      "adminMintStatus": "REQUESTED",
      "expiryTimestamp": "1703197027900",
      "reference": "D11808T8GVTL81VV2U7HV",
      "txHash": null,
      "requestType": "",
      "refundStatus": null
    }
  ]
}
```

The two fields that matter for integrations are:

| Field            | Purpose                   |
| ---------------- | ------------------------- |
| `paymentStatus`  | Fiat payment status       |
| `userMintStatus` | Blockchain minting status |

{% hint style="warning" %}
`adminMintStatus` is an internal operational field and is not part of the public API contract.\
Do not build integration logic around it.
{% endhint %}

***

### paymentStatus Values

| Value                 | Meaning                                            |
| --------------------- | -------------------------------------------------- |
| `WAITING_FOR_PAYMENT` | Mint request created and awaiting payment          |
| `PAID`                | Payment confirmed                                  |
| `EXPIRED`             | Payment window expired before payment was received |

***

### userMintStatus Values

| Value           | Meaning                                   |
| --------------- | ----------------------------------------- |
| `NOT_AVAILABLE` | No minting activity yet                   |
| `PROCESSING`    | Payment confirmed and minting in progress |
| `MINTED`        | Tokens successfully delivered             |
| `REJECTED`      | Request rejected after review             |
| `REFUND`        | Payment refunded                          |

{% hint style="info" %}
`userMintStatus` never becomes `FAILED`.\
Failed mint attempts are retried internally until resolved.
{% endhint %}

***

### Transaction Lifecycle

| Stage            | `paymentStatus`       | `userMintStatus` | Terminal |
| ---------------- | --------------------- | ---------------- | -------- |
| Awaiting payment | `WAITING_FOR_PAYMENT` | `NOT_AVAILABLE`  | No       |
| Paid, minting    | `PAID`                | `PROCESSING`     | No       |
| Success          | `PAID`                | `MINTED`         | Yes      |
| Payment expired  | `EXPIRED`             | `NOT_AVAILABLE`  | Yes      |
| Refunded         | `PAID`                | `REFUND`         | Yes      |
| Rejected         | `PAID`                | `REJECTED`       | Yes      |

#### Lifecycle Diagram

```
WAITING_FOR_PAYMENT / NOT_AVAILABLE
        |
        |-- customer pays --------> PAID / PROCESSING ---> PAID / MINTED
        |                                  |
        |                                  |---> PAID / REFUND
        |                                  |
        |                                  |---> PAID / REJECTED
        |
        |-- payment expires -----> EXPIRED / NOT_AVAILABLE
```

***

### Step 3 — Reconcile

There are two ways to know a transaction has reached its final state:

1. **Webhook callback** (recommended) — your backend receives an HTTP POST when the transaction settles. See [Webhook Callback.](/api/callback)
2. **Polling** — call the Transaction History endpoint from Step 2 until you reach a terminal state.

A reference reconciliation loop:

```typescript
async function reconcileMint(merchantOrderId: string) {
  const TERMINAL_PAYMENT = ["EXPIRED"];

  const TERMINAL_MINT = [
    "MINTED",
    "REFUND",
    "REJECTED"
  ];

  while (true) {
    const tx = await getMintStatus(merchantOrderId);

    if (TERMINAL_PAYMENT.includes(tx.paymentStatus)) {
      return {
        outcome: "EXPIRED",
        tx
      };
    }

    if (TERMINAL_MINT.includes(tx.userMintStatus)) {
      return {
        outcome: tx.userMintStatus,
        tx
      };
    }

    await new Promise(r => setTimeout(r, 5000));
  }
}
```

{% hint style="warning" %}
Always re-fetch transaction state from Transaction History before crediting users.\
Treat webhook payloads as untrusted input.
{% endhint %}

***

### Edge Case — Payment Succeeded but Mint Still Processing

If:

```
paymentStatus = PAID
userMintStatus = PROCESSING
```

persists longer than a few minutes, the blockchain delivery did not complete on the first attempt.

The transaction is still being handled internally by IDRX operations.

The final outcome will eventually become one of:

* `MINTED`
* `REFUND`

Do not timeout the transaction on your side.

Continue polling until a terminal state is reached.

***

### Edge Case — Customer Pays After Expiry

If a customer pays after `expiryPeriod` has elapsed, the bank network will usually reverse the payment automatically.

Late payments are not credited.

Create a new mint request if the customer wants to retry.

***

### Edge Case — Wrong Sender Name

For VA payments, the bank sender name must match the customer name registered on the IDRX account.

Mismatched payments are refunded within 14 business days.

***

### Recommended Polling Cadence

* Poll every `5 seconds` during the first 5 minutes
* Then back off to every `30 seconds`
* Stop polling after reaching a terminal state
* Prefer webhook callbacks for production systems

After a successful payment, IDRX tokens will be minted to the specified wallet address. To check the status of the transaction, you can use the [Transaction History API](/api/transaction-api/get-api-transaction-user-transaction-history). Next, we will explore on processing redeem requests.


# Getting other stablecoins

A brief explanation on minting IDRX to get other tokens.

You can use IDRX to get other stablecoins, such as USDT and USDC. IDRX partners with third-party providers to enable the acquisition of other stablecoins using Indonesian Rupiah. The process involves minting IDRX and swapping it into the desired token on-chain through the partner’s API. Below is the list of supported tokens and partner APIs for each network:

<table><thead><tr><th>Network<select><option value="J8lvkEn668oH" label="Polygon" color="blue"></option><option value="Zr58hT1IBOVl" label="Base" color="blue"></option><option value="2qbzDFuItSCn" label="World Chain" color="blue"></option><option value="W3QsfpIQQOyA" label="BNB Chain" color="blue"></option><option value="oLcgBxho9Go7" label="Lisk" color="blue"></option><option value="4HEvZY8q2rlH" label="Kaia" color="blue"></option></select></th><th>Token<select><option value="IpwKnC4yWI1q" label="USDT" color="blue"></option><option value="BJxUFSNMABw1" label="USDC" color="blue"></option><option value="4AMkv4KaOS2p" label="WLD" color="blue"></option><option value="UPAmJxQVqJFe" label="USDT0" color="blue"></option></select></th><th>Partner API</th></tr></thead><tbody><tr><td><span data-option="J8lvkEn668oH">Polygon</span></td><td><span data-option="IpwKnC4yWI1q">USDT</span></td><td><a href="https://0x.org/">0x</a></td></tr><tr><td><span data-option="W3QsfpIQQOyA">BNB Chain</span></td><td><span data-option="IpwKnC4yWI1q">USDT</span></td><td><a href="https://0x.org/">0x</a></td></tr><tr><td><span data-option="4HEvZY8q2rlH">Kaia</span></td><td><span data-option="IpwKnC4yWI1q">USDT</span></td><td><a href="http://li.fi/">Li.fi</a></td></tr><tr><td><span data-option="oLcgBxho9Go7">Lisk</span></td><td><span data-option="UPAmJxQVqJFe">USDT0</span></td><td><a href="http://li.fi/">Li.fi</a></td></tr><tr><td><span data-option="Zr58hT1IBOVl">Base</span></td><td><span data-option="BJxUFSNMABw1">USDC</span></td><td><a href="http://li.fi/">Li.fi</a></td></tr></tbody></table>

Before doing this, you might want to check the current rate. You can use [this api](/api/transaction-api/get-api-transaction-rates) to get the current rates. Here's an example code to get current rates.

{% hint style="info" %}

* The balance will be processed and credited to \`**`` destinationWalletAddress` ``** max 24 hours after your request is submitted.
* Minimum transaction for other stablecoins are $2 USD
* Maximum transaction for other stablecoins are 5,555 USD
* For transactions more than the maximum limit, please send your request to <support@idrx.co> to be processed.
* The transaction will be automatically canceled if you have not made a payment within 24 hours.
* IDRX is not responsible for deposit errors from incorrect Virtual Account numbers. Refunds for payments made to Virtual Account numbers under a different name will be processed within 14 business days.
  {% endhint %}

```typescript
import { createSignature } from "./createSignature";
const axios = require('axios');

const apiKey = "{YOUR API KEY}";
const secret = "{YOUR SECRET}";

async function getRates() {
  const path = "https://idrx.co/api/transaction/rates?idrxAmount=15000";

  const bufferReq = Buffer.from('', 'base64').toString('utf8');
  const timestamp = Math.round((new Date()).getTime()).toString();
  const sig = createSignature('GET', path, bufferReq, timestamp, secret);

  const res = await axios.get(path, {
    headers: {
      'Content-Type': 'application/json',
      'idrx-api-key': apiKey,
      'idrx-api-sig': sig,
      'idrx-api-ts' : timestamp,
    },
  });

  console.log('res.data: ');
  console.log(JSON.stringify(res.data, null, 4));
}

getRates();
```

After a successful request, you will get a response as follows:

```typescript
{
    "statusCode": 200,
    "message": "success",
    "data": {
        "price":"0.000062",
        "buyAmount":"0.932311",
        "chainId":137
    }
}
```

## Get Other Stablecoin

You can mint IDRX and get other stablecoins such as USDT and USDC by following [this guide](/integration/processing-mint-idrx-requests). The only thing that you need to change is the `requestType` parameter set to `usdt`. See the table at the top of this page for the tokens available on each network.

To check the status of the transaction, you can use the [Transaction History API](/api/transaction-api/get-api-transaction-user-transaction-history).


# Processing Redeem IDRX Requests

The typical flow to process redeem requests from your user

To do a redeem, you must first perform a **burn** transaction on the blockchain, then use the hash of that transaction as a parameter in the `POST /api/transaction/redeem-request` endpoint.

Here is an example code to perform a burn transaction. In this example, we will be using Alchemy as the RPC provider, and Polygon as the blockchain. Please note that for the bank account hash, the format is `{bankName}_{bankAccountNumber}`.

{% hint style="info" %}
Check [this page](https://docs.idrx.co/introduction/supported-chain-and-contract-address) to see the list of chains where IDRX is available
{% endhint %}

{% hint style="info" %}

* The balance will be processed and credited to **`bankAccount`** max 24 hours after your request is submitted.
* The minimum transaction is 20,000 IDR.
* The Maximum transaction is 1,000,000,000 IDR.
* Redeeming IDRX <= 250 million IDR will be processed in real-time
* Redeeming IDRX 250 million IDR\<x<1 billion IDR will be processed only during office hours on Monday-Friday at 08:00-15:00 WIB
* For transactions of more than 1 billion Rupiah, send your request to <support@idrx.co> to be processed.
* IDRX is not responsible if a redeem error occurs due to an incorrect bank/e-wallet account number.
  {% endhint %}

{% tabs %}
{% tab title="ethers" %}

```typescript
import sha256 from 'crypto-js/sha256';
const { ethers } = require("ethers");
const idrxAbi = [{"inputs": [], "stateMutability": "nonpayable", "type": "constructor" }, {"anonymous": false, "inputs": [{"indexed": false, "internalType": "address", "name": "_user", "type": "address" } ], "name": "AddedBlackList", "type": "event" }, {"anonymous": false, "inputs": [{"indexed": false, "internalType": "address", "name": "previousAdmin", "type": "address" }, {"indexed": false, "internalType": "address", "name": "newAdmin", "type": "address" } ], "name": "AdminChanged", "type": "event" }, {"anonymous": false, "inputs": [{"indexed": true, "internalType": "address", "name": "owner", "type": "address" }, {"indexed": true, "internalType": "address", "name": "spender", "type": "address" }, {"indexed": false, "internalType": "uint256", "name": "value", "type": "uint256" } ], "name": "Approval", "type": "event" }, {"anonymous": false, "inputs": [{"indexed": true, "internalType": "address", "name": "beacon", "type": "address" } ], "name": "BeaconUpgraded", "type": "event" }, {"anonymous": false, "inputs": [{"indexed": false, "internalType": "address", "name": "_user", "type": "address" }, {"indexed": false, "internalType": "uint256", "name": "_amount", "type": "uint256" }, {"indexed": false, "internalType": "uint256", "name": "amountAfterCut", "type": "uint256" }, {"indexed": false, "internalType": "uint256", "name": "toChain", "type": "uint256" }, {"indexed": false, "internalType": "uint256", "name": "_bridgeNonce", "type": "uint256" }, {"indexed": false, "internalType": "uint256", "name": "platformFee", "type": "uint256" } ], "name": "BurnBridge", "type": "event" }, {"anonymous": false, "inputs": [{"indexed": false, "internalType": "address", "name": "_user", "type": "address" }, {"indexed": false, "internalType": "uint256", "name": "amount", "type": "uint256" }, {"indexed": false, "internalType": "string", "name": "hashedAccountNumber", "type": "string" } ], "name": "BurnWithAccountNumber", "type": "event" }, {"anonymous": false, "inputs": [{"indexed": false, "internalType": "address", "name": "_blackListedUser", "type": "address" }, {"indexed": false, "internalType": "uint256", "name": "_balance", "type": "uint256" } ], "name": "DestroyedBlackFunds", "type": "event" }, {"anonymous": false, "inputs": [{"indexed": false, "internalType": "uint8", "name": "version", "type": "uint8" } ], "name": "Initialized", "type": "event" }, {"anonymous": false, "inputs": [{"indexed": false, "internalType": "address", "name": "_user", "type": "address" }, {"indexed": false, "internalType": "uint256", "name": "_amount", "type": "uint256" }, {"indexed": false, "internalType": "uint256", "name": "amountAfterCut", "type": "uint256" }, {"indexed": false, "internalType": "uint256", "name": "fromChain", "type": "uint256" }, {"indexed": false, "internalType": "uint256", "name": "fromBridgeNonce", "type": "uint256" }, {"indexed": false, "internalType": "uint256", "name": "platformFee", "type": "uint256" } ], "name": "MintBridge", "type": "event" }, {"anonymous": false, "inputs": [{"indexed": false, "internalType": "address", "name": "account", "type": "address" } ], "name": "Paused", "type": "event" }, {"anonymous": false, "inputs": [{"indexed": false, "internalType": "address", "name": "_platformFeeRecipient", "type": "address" }, {"indexed": false, "internalType": "uint64", "name": "_burnBridgeFee", "type": "uint64" }, {"indexed": false, "internalType": "uint64", "name": "_mintBridgeFee", "type": "uint64" } ], "name": "PlatformFeeInfoUpdated", "type": "event" }, {"anonymous": false, "inputs": [{"indexed": false, "internalType": "address", "name": "_user", "type": "address" } ], "name": "RemovedBlackList", "type": "event" }, {"anonymous": false, "inputs": [{"indexed": true, "internalType": "bytes32", "name": "role", "type": "bytes32" }, {"indexed": true, "internalType": "bytes32", "name": "previousAdminRole", "type": "bytes32" }, {"indexed": true, "internalType": "bytes32", "name": "newAdminRole", "type": "bytes32" } ], "name": "RoleAdminChanged", "type": "event" }, {"anonymous": false, "inputs": [{"indexed": true, "internalType": "bytes32", "name": "role", "type": "bytes32" }, {"indexed": true, "internalType": "address", "name": "account", "type": "address" }, {"indexed": true, "internalType": "address", "name": "sender", "type": "address" } ], "name": "RoleGranted", "type": "event" }, {"anonymous": false, "inputs": [{"indexed": true, "internalType": "bytes32", "name": "role", "type": "bytes32" }, {"indexed": true, "internalType": "address", "name": "account", "type": "address" }, {"indexed": true, "internalType": "address", "name": "sender", "type": "address" } ], "name": "RoleRevoked", "type": "event" }, {"anonymous": false, "inputs": [{"indexed": true, "internalType": "address", "name": "from", "type": "address" }, {"indexed": true, "internalType": "address", "name": "to", "type": "address" }, {"indexed": false, "internalType": "uint256", "name": "value", "type": "uint256" } ], "name": "Transfer", "type": "event" }, {"anonymous": false, "inputs": [{"indexed": false, "internalType": "address", "name": "account", "type": "address" } ], "name": "Unpaused", "type": "event" }, {"anonymous": false, "inputs": [{"indexed": true, "internalType": "address", "name": "implementation", "type": "address" } ], "name": "Upgraded", "type": "event" }, {"inputs": [], "name": "BLACKLIST_ROLE", "outputs": [{"internalType": "bytes32", "name": "", "type": "bytes32" } ], "stateMutability": "view", "type": "function" }, {"inputs": [], "name": "DEFAULT_ADMIN_ROLE", "outputs": [{"internalType": "bytes32", "name": "", "type": "bytes32" } ], "stateMutability": "view", "type": "function" }, {"inputs": [], "name": "MINTER_ROLE", "outputs": [{"internalType": "bytes32", "name": "", "type": "bytes32" } ], "stateMutability": "view", "type": "function" }, {"inputs": [], "name": "PAUSER_ROLE", "outputs": [{"internalType": "bytes32", "name": "", "type": "bytes32" } ], "stateMutability": "view", "type": "function" }, {"inputs": [], "name": "PLATFORM_FEE_SETTER_ROLE", "outputs": [{"internalType": "bytes32", "name": "", "type": "bytes32" } ], "stateMutability": "view", "type": "function" }, {"inputs": [], "name": "UPGRADER_ROLE", "outputs": [{"internalType": "bytes32", "name": "", "type": "bytes32" } ], "stateMutability": "view", "type": "function" }, {"inputs": [{"internalType": "address", "name": "", "type": "address" } ], "name": "_balances", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256" } ], "stateMutability": "view", "type": "function" }, {"inputs": [], "name": "_bridgeNonce", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256" } ], "stateMutability": "view", "type": "function" }, {"inputs": [], "name": "_totalSupply", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256" } ], "stateMutability": "view", "type": "function" }, {"inputs": [{"internalType": "address", "name": "_evilUser", "type": "address" } ], "name": "addBlackList", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, {"inputs": [{"internalType": "address", "name": "owner", "type": "address" }, {"internalType": "address", "name": "spender", "type": "address" } ], "name": "allowance", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256" } ], "stateMutability": "view", "type": "function" }, {"inputs": [{"internalType": "address", "name": "spender", "type": "address" }, {"internalType": "uint256", "name": "amount", "type": "uint256" } ], "name": "approve", "outputs": [{"internalType": "bool", "name": "", "type": "bool" } ], "stateMutability": "nonpayable", "type": "function" }, {"inputs": [{"internalType": "address", "name": "account", "type": "address" } ], "name": "balanceOf", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256" } ], "stateMutability": "view", "type": "function" }, {"inputs": [{"internalType": "uint256", "name": "amount", "type": "uint256" } ], "name": "burn", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, {"inputs": [{"internalType": "uint256", "name": "amount", "type": "uint256" }, {"internalType": "uint256", "name": "toChain", "type": "uint256" } ], "name": "burnBridge", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, {"inputs": [{"internalType": "address", "name": "account", "type": "address" }, {"internalType": "uint256", "name": "amount", "type": "uint256" } ], "name": "burnFrom", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, {"inputs": [{"internalType": "uint256", "name": "amount", "type": "uint256" }, {"internalType": "string", "name": "accountNumber", "type": "string" } ], "name": "burnWithAccountNumber", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, {"inputs": [], "name": "decimals", "outputs": [{"internalType": "uint8", "name": "", "type": "uint8" } ], "stateMutability": "view", "type": "function" }, {"inputs": [{"internalType": "address", "name": "spender", "type": "address" }, {"internalType": "uint256", "name": "subtractedValue", "type": "uint256" } ], "name": "decreaseAllowance", "outputs": [{"internalType": "bool", "name": "", "type": "bool" } ], "stateMutability": "nonpayable", "type": "function" }, {"inputs": [{"internalType": "address", "name": "_blackListedUser", "type": "address" } ], "name": "destroyBlackFunds", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, {"inputs": [{"internalType": "uint256", "name": "", "type": "uint256" }, {"internalType": "uint256", "name": "", "type": "uint256" } ], "name": "fromChainNonceUsed", "outputs": [{"internalType": "bool", "name": "", "type": "bool" } ], "stateMutability": "view", "type": "function" }, {"inputs": [{"internalType": "address", "name": "_maker", "type": "address" } ], "name": "getBlackListStatus", "outputs": [{"internalType": "bool", "name": "", "type": "bool" } ], "stateMutability": "view", "type": "function" }, {"inputs": [], "name": "getPlatformFeeInfo", "outputs": [{"internalType": "address", "name": "", "type": "address" }, {"internalType": "uint64", "name": "", "type": "uint64" }, {"internalType": "uint64", "name": "", "type": "uint64" } ], "stateMutability": "view", "type": "function" }, {"inputs": [{"internalType": "bytes32", "name": "role", "type": "bytes32" } ], "name": "getRoleAdmin", "outputs": [{"internalType": "bytes32", "name": "", "type": "bytes32" } ], "stateMutability": "view", "type": "function" }, {"inputs": [{"internalType": "bytes32", "name": "role", "type": "bytes32" }, {"internalType": "address", "name": "account", "type": "address" } ], "name": "grantRole", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, {"inputs": [{"internalType": "bytes32", "name": "role", "type": "bytes32" }, {"internalType": "address", "name": "account", "type": "address" } ], "name": "hasRole", "outputs": [{"internalType": "bool", "name": "", "type": "bool" } ], "stateMutability": "view", "type": "function" }, {"inputs": [{"internalType": "address", "name": "spender", "type": "address" }, {"internalType": "uint256", "name": "addedValue", "type": "uint256" } ], "name": "increaseAllowance", "outputs": [{"internalType": "bool", "name": "", "type": "bool" } ], "stateMutability": "nonpayable", "type": "function" }, {"inputs": [], "name": "initialize", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, {"inputs": [{"internalType": "address", "name": "", "type": "address" } ], "name": "isBlackListed", "outputs": [{"internalType": "bool", "name": "", "type": "bool" } ], "stateMutability": "view", "type": "function" }, {"inputs": [], "name": "maxPlatformFee", "outputs": [{"internalType": "uint64", "name": "", "type": "uint64" } ], "stateMutability": "view", "type": "function" }, {"inputs": [{"internalType": "address", "name": "to", "type": "address" }, {"internalType": "uint256", "name": "amount", "type": "uint256" } ], "name": "mint", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, {"inputs": [{"internalType": "address", "name": "to", "type": "address" }, {"internalType": "uint256", "name": "amount", "type": "uint256" }, {"internalType": "uint256", "name": "fromChain", "type": "uint256" }, {"internalType": "uint256", "name": "fromChainBridgeNonce", "type": "uint256" } ], "name": "mintBridge", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, {"inputs": [], "name": "name", "outputs": [{"internalType": "string", "name": "", "type": "string" } ], "stateMutability": "view", "type": "function" }, {"inputs": [], "name": "pause", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, {"inputs": [], "name": "paused", "outputs": [{"internalType": "bool", "name": "", "type": "bool" } ], "stateMutability": "view", "type": "function" }, {"inputs": [], "name": "proxiableUUID", "outputs": [{"internalType": "bytes32", "name": "", "type": "bytes32" } ], "stateMutability": "view", "type": "function" }, {"inputs": [{"internalType": "address", "name": "_clearedUser", "type": "address" } ], "name": "removeBlackList", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, {"inputs": [{"internalType": "bytes32", "name": "role", "type": "bytes32" }, {"internalType": "address", "name": "account", "type": "address" } ], "name": "renounceRole", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, {"inputs": [{"internalType": "bytes32", "name": "role", "type": "bytes32" }, {"internalType": "address", "name": "account", "type": "address" } ], "name": "revokeRole", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, {"inputs": [{"internalType": "address", "name": "_platformFeeRecipient", "type": "address" }, {"internalType": "uint64", "name": "_burnBridgeFee", "type": "uint64" }, {"internalType": "uint64", "name": "_mintBridgeFee", "type": "uint64" } ], "name": "setPlatformFeeInfo", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, {"inputs": [{"internalType": "bytes4", "name": "interfaceId", "type": "bytes4" } ], "name": "supportsInterface", "outputs": [{"internalType": "bool", "name": "", "type": "bool" } ], "stateMutability": "view", "type": "function" }, {"inputs": [], "name": "symbol", "outputs": [{"internalType": "string", "name": "", "type": "string" } ], "stateMutability": "view", "type": "function" }, {"inputs": [], "name": "totalSupply", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256" } ], "stateMutability": "view", "type": "function" }, {"inputs": [{"internalType": "address", "name": "to", "type": "address" }, {"internalType": "uint256", "name": "amount", "type": "uint256" } ], "name": "transfer", "outputs": [{"internalType": "bool", "name": "", "type": "bool" } ], "stateMutability": "nonpayable", "type": "function" }, {"inputs": [{"internalType": "address", "name": "from", "type": "address" }, {"internalType": "address", "name": "to", "type": "address" }, {"internalType": "uint256", "name": "amount", "type": "uint256" } ], "name": "transferFrom", "outputs": [{"internalType": "bool", "name": "", "type": "bool" } ], "stateMutability": "nonpayable", "type": "function" }, {"inputs": [], "name": "unpause", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, {"inputs": [{"internalType": "address", "name": "newImplementation", "type": "address" } ], "name": "upgradeTo", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, {"inputs": [{"internalType": "address", "name": "newImplementation", "type": "address" }, {"internalType": "bytes", "name": "data", "type": "bytes" } ], "name": "upgradeToAndCall", "outputs": [], "stateMutability": "payable", "type": "function" } ];

const ALCHEMY_POLYGON_NETWORK = "matic";
const ALCHEMY_API_KEY = "{ALCHEMY API KEY}";
const WALLET_PRIVATE_KEY = "{WALLET PRIVATE KEY}";
const IDRX_CONTRACT_ADDRESS = "0x649a2DA7B28E0D54c13D5eFf95d3A660652742cC";

const provider = new ethers.providers.AlchemyProvider(ALCHEMY_POLYGON_NETWORK, ALCHEMY_API_KEY);
const signer = new ethers.Wallet(WALLET_PRIVATE_KEY, provider);

async function burnIdrx() {
    const amount = "21000";
    const bankAccountNumber = "BANK CENTRAL ASIA_7255759001"; // example bank account. format: {bankName}_{bankAccountNumber}
    const hashBankAccountNumber = await sha256(bankAccountNumber).toString();

    const idrxContract = new ethers.Contract(IDRX_CONTRACT_ADDRESS, idrxAbi, provider);
    const idrxContractSigner = idrxContract.connect(signer);
    const tx = await idrxContractSigner.burnWithAccountNumber(amount, hashBankAccountNumber);
    const txHash = tx.hash;

    console.log('txHash: ');
    console.log(txHash);
}

burnIdrx();
```

{% endtab %}

{% tab title="viem" %}

```typescript
import { createPublicClient, createWalletClient, http, parseAbi, sha256, toBytes } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { polygon } from "viem/chains";

const idrxAbi = parseAbi([
  "function burnWithAccountNumber(uint256 amount, string accountNumber)",
  "function balanceOf(address account) view returns (uint256)",
  "function decimals() view returns (uint8)",
  "event BurnWithAccountNumber(address _user, uint256 amount, string hashedAccountNumber)",
]);

const ALCHEMY_API_KEY = "{ALCHEMY API KEY}";
const WALLET_PRIVATE_KEY = "{WALLET PRIVATE KEY}";
const IDRX_CONTRACT_ADDRESS = "0x649a2DA7B28E0D54c13D5eFf95d3A660652742cC";

const transport = http(`https://polygon-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}`);
const account = privateKeyToAccount(WALLET_PRIVATE_KEY);

const publicClient = createPublicClient({ chain: polygon, transport });
const walletClient = createWalletClient({ account, chain: polygon, transport });

async function burnIdrx() {
  const amount = 21000n;
  const bankAccountNumber = "BANK CENTRAL ASIA_7255759001"; // format: {bankName}_{bankAccountNumber}

  const hashBankAccountNumber = sha256(toBytes(bankAccountNumber)).slice(2);

  const { request } = await publicClient.simulateContract({
    address: IDRX_CONTRACT_ADDRESS,
    abi: idrxAbi,
    functionName: "burnWithAccountNumber",
    args: [amount, hashBankAccountNumber],
    account,
  });

  const txHash = await walletClient.writeContract(request);

  console.log("txHash: ");
  console.log(txHash);

  const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
  console.log("status:", receipt.status);

  return txHash;
}

burnIdrx().catch(console.error);
```

{% endtab %}
{% endtabs %}

After the burning transaction is confirmed on the blockchain, you can use the transaction hash obtained from that transaction to do a redeem request. To get the appropriate `bankCode` and `bankName`, you can refer to [Transactions Methods API](/api/transaction-api/get-api-transaction-method).

```typescript
import { createSignature } from "./createSignature";
const axios = require('axios');

const apiKey = "{YOUR API KEY}";
const secret = "{YOUR SECRET}";

async function redeemRequest() {
  const path = "https://idrx.co/api/transaction/redeem-request";

  const req = {
    "txHash": "0xa38c057222872d8e3d106ab5f9b86b7d1d6ade72d485eb01366650e45c8a65d1",
    "networkChainId": "137",
    "amountTransfer": "21000",
    "bankAccount": "7255759001",
    "bankCode": "014",
    "bankName": "BANK CENTRAL ASIA",
    "bankAccountName": "JOHN SMITH",
    "walletAddress": "0x8BD53F7fF88fD895D3686fe6369a07432822d30F",
  };
  const bufferReq = Buffer.from(JSON.stringify(req), 'base64').toString('utf8');
  const timestamp = Math.round((new Date()).getTime()).toString();
  const sig = createSignature('POST', path, bufferReq, timestamp, secret);

  const res = await axios.post(path, req, {
    headers: {
      'Content-Type': 'application/json',
      'idrx-api-key': apiKey,
      'idrx-api-sig': sig,
      'idrx-api-ts' : timestamp,
    },
  });

  console.log('res.data: ');
  console.log(res.data);
}

redeemRequest();
```

After a successful request, you will get a response as follows:

```json
{
  statusCode: 201,
  message: 'success',
  data: {
    id: 100,
    chainId: 137,
    userId: 411,
    requester: 'JOHN SMITH',
    txHash: '0xa38c057222872d8e3d106ab5f9b86b7d1d6ade72d485eb01366650e45c8a65d1',
    fromAddress: '0x8BD53F7fF88fD895D3686fe6369a07432822d30F',
    amount: '16000',
    bankName: 'BANK CENTRAL ASIA',
    bankCode: '014',
    bankAccountNumber: '7255759001',
    bankAccountName: 'JOHN SMITH',
    bankAccountNumberHash: null,
    custRefNumber: '000028880723',
    disburseId: 17610206,
    burnStatus: 'REQUESTED',
    createdAt: '2023-12-19T11:05:42.583Z',
    updatedAt: '2023-12-19T11:05:42.583Z',
    deleted: false,
    reportStatus: 'NONE',
    notes: null
  }
}
```

To check the status of the transaction, you can use the [Transaction History API](/api/transaction-api/get-api-transaction-user-transaction-history). The redeem request will be then processed shortly after. IDR will be transferred to the specified bank account number.

\
When redeeming to an e-wallet, the destination field must be filled with the registered e-wallet phone number. The phone number must use the local format starting with `08xx`, with no spaces, dashes, or any special characters.

For example, a valid entry would be `081234567890`. Submissions that do not follow this format will be rejected and the redemption request will not be processed.


# Redeeming from other stablecoins

Redeem IDR to a bank account from other tokens.

You can receive IDR to a bank account by redeeming other stablecoins, such as USDT and USDC. IDRX partners with third-party providers to enable the redemption of other stablecoins to Indonesian Rupiah. The process involves swapping the stablecoin through the partner’s API into IDRX and then burning it on-chain. Below is the list of supported tokens and partner APIs for each network:

<table><thead><tr><th>Network<select><option value="J8lvkEn668oH" label="Polygon" color="blue"></option><option value="Zr58hT1IBOVl" label="Base" color="blue"></option><option value="2qbzDFuItSCn" label="World Chain" color="blue"></option><option value="W3QsfpIQQOyA" label="BNB Chain" color="blue"></option><option value="oLcgBxho9Go7" label="Lisk" color="blue"></option><option value="6Z0KzLKWEXhp" label="Kaia" color="blue"></option></select></th><th>Token<select><option value="IpwKnC4yWI1q" label="USDT" color="blue"></option><option value="BJxUFSNMABw1" label="USDC" color="blue"></option><option value="4AMkv4KaOS2p" label="WLD" color="blue"></option><option value="UPAmJxQVqJFe" label="USDT0" color="blue"></option></select></th><th>Partner API</th></tr></thead><tbody><tr><td><span data-option="J8lvkEn668oH">Polygon</span></td><td><span data-option="IpwKnC4yWI1q">USDT</span></td><td><a href="https://0x.org/">0x</a></td></tr><tr><td><span data-option="W3QsfpIQQOyA">BNB Chain</span></td><td><span data-option="IpwKnC4yWI1q">USDT</span></td><td><a href="https://0x.org/">0x</a></td></tr><tr><td><span data-option="6Z0KzLKWEXhp">Kaia</span></td><td><span data-option="IpwKnC4yWI1q">USDT</span></td><td><a href="http://li.fi/">Li.fi</a></td></tr><tr><td><span data-option="oLcgBxho9Go7">Lisk</span></td><td><span data-option="UPAmJxQVqJFe">USDT0</span></td><td><a href="http://li.fi/">Li.fi</a></td></tr><tr><td><span data-option="Zr58hT1IBOVl">Base</span></td><td><span data-option="BJxUFSNMABw1">USDC</span></td><td><a href="http://li.fi/">Li.fi</a></td></tr></tbody></table>

Each bank account has a deposit address that is associated with it. You can send funds to this address to request a redemption to the bank account. Here's an example code to list your currently registered bank accounts.

{% hint style="info" %}

* The balance will be processed and credited to \`**`` bankAccount` ``** max 24 hours after your request is submitted.
* The minimum transaction is 2 USD.
* The maximum transaction is 5,555 USD
* Redeeming other stablecoins <= 5,555 USD will be processed in real-time
* For transactions of more than 5,555 USD send your request to <support@idrx.co> to be processed.
* IDRX is not responsible if a redeem error occurs due to an incorrect bank/e-wallet account number.
  {% endhint %}

```typescript
import { createSignature } from "./createSignature";
const axios = require('axios');

const apiKey = "{YOUR API KEY}";
const secret = "{YOUR SECRET}";

async function getBankAccounts() {
  const path = "https://idrx.co/api/auth/get-bank-accounts";

  const bufferReq = Buffer.from('', 'base64').toString('utf8');
  const timestamp = Math.round((new Date()).getTime()).toString();
  const sig = createSignature('GET', path, bufferReq, timestamp, secret);

  const res = await axios.get(path, {
    headers: {
      'Content-Type': 'application/json',
      'idrx-api-key': apiKey,
      'idrx-api-sig': sig,
      'idrx-api-ts' : timestamp,
    },
  });

  console.log('res.data: ');
  console.log(JSON.stringify(res.data, null, 4));
}

getBankAccounts();
```

After a successful request, you will get a response as follows:

```typescript
{
    "statusCode": 200,
    "message": "success",
    "data": [
        {
            "id": 108,
            "userId": 411,
            "bankAccountNumber": "5017332241",
            "bankAccountName": "JOHN SMITH",
            "bankAccountNumberHash": null,
            "bankCode": "014",
            "bankName": "BANK CENTRAL ASIA",
            "maxAmountTransfer": "100000000",
            "deleted": false,
            "DepositWalletAddress": {
                "walletAddress": "0x07C158ab29f23D0821e7D24B191c5e5d9d72738b",
                "createdAt": "2024-01-17T10:34:22.304Z"
            }
        },
        ...,
    ]
}
```

You can then send the other tokens to the wallet address associated with the bank account to initiate the process of redeeming IDR to the bank account. To get information about swap rates, you can use [this api](/api/transaction-api/get-api-transaction-rates).


# Processing Bridge IDRX Request

The typical flow to process bridge requests from your user

To bridge IDRX, first execute a **burnBridge** transaction on the source blockchain. Then, use the resulting transaction hash as the value for the **txHashBurn** parameter in the `POST /api/transaction/bridge-request` endpoint.

Here’s an example code snippet to perform a **burnBridge** transaction. In this example, we will bridge **IDRX** from the Polygon network to BSC network.

{% hint style="info" %}
Check [this page](https://docs.idrx.co/introduction/supported-chain-and-contract-address) to see the list of chains where IDRX is available
{% endhint %}

{% hint style="info" %}

* The balance will be processed and credited to **`destinationWalletAddress`** max 24 hours after your request is submitted.
* The minimum transaction is 20,000 IDR.
* IDRX is not responsible if an error occurs due to an incorrect wallet address.
  {% endhint %}

{% tabs %}
{% tab title="ethers" %}

```typescript
import * as sha256 from 'sha256';
const { ethers } = require("ethers");
const idrxAbi = [{"inputs": [], "stateMutability": "nonpayable", "type": "constructor" }, {"anonymous": false, "inputs": [{"indexed": false, "internalType": "address", "name": "_user", "type": "address" } ], "name": "AddedBlackList", "type": "event" }, {"anonymous": false, "inputs": [{"indexed": false, "internalType": "address", "name": "previousAdmin", "type": "address" }, {"indexed": false, "internalType": "address", "name": "newAdmin", "type": "address" } ], "name": "AdminChanged", "type": "event" }, {"anonymous": false, "inputs": [{"indexed": true, "internalType": "address", "name": "owner", "type": "address" }, {"indexed": true, "internalType": "address", "name": "spender", "type": "address" }, {"indexed": false, "internalType": "uint256", "name": "value", "type": "uint256" } ], "name": "Approval", "type": "event" }, {"anonymous": false, "inputs": [{"indexed": true, "internalType": "address", "name": "beacon", "type": "address" } ], "name": "BeaconUpgraded", "type": "event" }, {"anonymous": false, "inputs": [{"indexed": false, "internalType": "address", "name": "_user", "type": "address" }, {"indexed": false, "internalType": "uint256", "name": "_amount", "type": "uint256" }, {"indexed": false, "internalType": "uint256", "name": "amountAfterCut", "type": "uint256" }, {"indexed": false, "internalType": "uint256", "name": "toChain", "type": "uint256" }, {"indexed": false, "internalType": "uint256", "name": "_bridgeNonce", "type": "uint256" }, {"indexed": false, "internalType": "uint256", "name": "platformFee", "type": "uint256" } ], "name": "BurnBridge", "type": "event" }, {"anonymous": false, "inputs": [{"indexed": false, "internalType": "address", "name": "_user", "type": "address" }, {"indexed": false, "internalType": "uint256", "name": "amount", "type": "uint256" }, {"indexed": false, "internalType": "string", "name": "hashedAccountNumber", "type": "string" } ], "name": "BurnWithAccountNumber", "type": "event" }, {"anonymous": false, "inputs": [{"indexed": false, "internalType": "address", "name": "_blackListedUser", "type": "address" }, {"indexed": false, "internalType": "uint256", "name": "_balance", "type": "uint256" } ], "name": "DestroyedBlackFunds", "type": "event" }, {"anonymous": false, "inputs": [{"indexed": false, "internalType": "uint8", "name": "version", "type": "uint8" } ], "name": "Initialized", "type": "event" }, {"anonymous": false, "inputs": [{"indexed": false, "internalType": "address", "name": "_user", "type": "address" }, {"indexed": false, "internalType": "uint256", "name": "_amount", "type": "uint256" }, {"indexed": false, "internalType": "uint256", "name": "amountAfterCut", "type": "uint256" }, {"indexed": false, "internalType": "uint256", "name": "fromChain", "type": "uint256" }, {"indexed": false, "internalType": "uint256", "name": "fromBridgeNonce", "type": "uint256" }, {"indexed": false, "internalType": "uint256", "name": "platformFee", "type": "uint256" } ], "name": "MintBridge", "type": "event" }, {"anonymous": false, "inputs": [{"indexed": false, "internalType": "address", "name": "account", "type": "address" } ], "name": "Paused", "type": "event" }, {"anonymous": false, "inputs": [{"indexed": false, "internalType": "address", "name": "_platformFeeRecipient", "type": "address" }, {"indexed": false, "internalType": "uint64", "name": "_burnBridgeFee", "type": "uint64" }, {"indexed": false, "internalType": "uint64", "name": "_mintBridgeFee", "type": "uint64" } ], "name": "PlatformFeeInfoUpdated", "type": "event" }, {"anonymous": false, "inputs": [{"indexed": false, "internalType": "address", "name": "_user", "type": "address" } ], "name": "RemovedBlackList", "type": "event" }, {"anonymous": false, "inputs": [{"indexed": true, "internalType": "bytes32", "name": "role", "type": "bytes32" }, {"indexed": true, "internalType": "bytes32", "name": "previousAdminRole", "type": "bytes32" }, {"indexed": true, "internalType": "bytes32", "name": "newAdminRole", "type": "bytes32" } ], "name": "RoleAdminChanged", "type": "event" }, {"anonymous": false, "inputs": [{"indexed": true, "internalType": "bytes32", "name": "role", "type": "bytes32" }, {"indexed": true, "internalType": "address", "name": "account", "type": "address" }, {"indexed": true, "internalType": "address", "name": "sender", "type": "address" } ], "name": "RoleGranted", "type": "event" }, {"anonymous": false, "inputs": [{"indexed": true, "internalType": "bytes32", "name": "role", "type": "bytes32" }, {"indexed": true, "internalType": "address", "name": "account", "type": "address" }, {"indexed": true, "internalType": "address", "name": "sender", "type": "address" } ], "name": "RoleRevoked", "type": "event" }, {"anonymous": false, "inputs": [{"indexed": true, "internalType": "address", "name": "from", "type": "address" }, {"indexed": true, "internalType": "address", "name": "to", "type": "address" }, {"indexed": false, "internalType": "uint256", "name": "value", "type": "uint256" } ], "name": "Transfer", "type": "event" }, {"anonymous": false, "inputs": [{"indexed": false, "internalType": "address", "name": "account", "type": "address" } ], "name": "Unpaused", "type": "event" }, {"anonymous": false, "inputs": [{"indexed": true, "internalType": "address", "name": "implementation", "type": "address" } ], "name": "Upgraded", "type": "event" }, {"inputs": [], "name": "BLACKLIST_ROLE", "outputs": [{"internalType": "bytes32", "name": "", "type": "bytes32" } ], "stateMutability": "view", "type": "function" }, {"inputs": [], "name": "DEFAULT_ADMIN_ROLE", "outputs": [{"internalType": "bytes32", "name": "", "type": "bytes32" } ], "stateMutability": "view", "type": "function" }, {"inputs": [], "name": "MINTER_ROLE", "outputs": [{"internalType": "bytes32", "name": "", "type": "bytes32" } ], "stateMutability": "view", "type": "function" }, {"inputs": [], "name": "PAUSER_ROLE", "outputs": [{"internalType": "bytes32", "name": "", "type": "bytes32" } ], "stateMutability": "view", "type": "function" }, {"inputs": [], "name": "PLATFORM_FEE_SETTER_ROLE", "outputs": [{"internalType": "bytes32", "name": "", "type": "bytes32" } ], "stateMutability": "view", "type": "function" }, {"inputs": [], "name": "UPGRADER_ROLE", "outputs": [{"internalType": "bytes32", "name": "", "type": "bytes32" } ], "stateMutability": "view", "type": "function" }, {"inputs": [{"internalType": "address", "name": "", "type": "address" } ], "name": "_balances", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256" } ], "stateMutability": "view", "type": "function" }, {"inputs": [], "name": "_bridgeNonce", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256" } ], "stateMutability": "view", "type": "function" }, {"inputs": [], "name": "_totalSupply", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256" } ], "stateMutability": "view", "type": "function" }, {"inputs": [{"internalType": "address", "name": "_evilUser", "type": "address" } ], "name": "addBlackList", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, {"inputs": [{"internalType": "address", "name": "owner", "type": "address" }, {"internalType": "address", "name": "spender", "type": "address" } ], "name": "allowance", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256" } ], "stateMutability": "view", "type": "function" }, {"inputs": [{"internalType": "address", "name": "spender", "type": "address" }, {"internalType": "uint256", "name": "amount", "type": "uint256" } ], "name": "approve", "outputs": [{"internalType": "bool", "name": "", "type": "bool" } ], "stateMutability": "nonpayable", "type": "function" }, {"inputs": [{"internalType": "address", "name": "account", "type": "address" } ], "name": "balanceOf", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256" } ], "stateMutability": "view", "type": "function" }, {"inputs": [{"internalType": "uint256", "name": "amount", "type": "uint256" } ], "name": "burn", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, {"inputs": [{"internalType": "uint256", "name": "amount", "type": "uint256" }, {"internalType": "uint256", "name": "toChain", "type": "uint256" } ], "name": "burnBridge", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, {"inputs": [{"internalType": "address", "name": "account", "type": "address" }, {"internalType": "uint256", "name": "amount", "type": "uint256" } ], "name": "burnFrom", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, {"inputs": [{"internalType": "uint256", "name": "amount", "type": "uint256" }, {"internalType": "string", "name": "accountNumber", "type": "string" } ], "name": "burnWithAccountNumber", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, {"inputs": [], "name": "decimals", "outputs": [{"internalType": "uint8", "name": "", "type": "uint8" } ], "stateMutability": "view", "type": "function" }, {"inputs": [{"internalType": "address", "name": "spender", "type": "address" }, {"internalType": "uint256", "name": "subtractedValue", "type": "uint256" } ], "name": "decreaseAllowance", "outputs": [{"internalType": "bool", "name": "", "type": "bool" } ], "stateMutability": "nonpayable", "type": "function" }, {"inputs": [{"internalType": "address", "name": "_blackListedUser", "type": "address" } ], "name": "destroyBlackFunds", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, {"inputs": [{"internalType": "uint256", "name": "", "type": "uint256" }, {"internalType": "uint256", "name": "", "type": "uint256" } ], "name": "fromChainNonceUsed", "outputs": [{"internalType": "bool", "name": "", "type": "bool" } ], "stateMutability": "view", "type": "function" }, {"inputs": [{"internalType": "address", "name": "_maker", "type": "address" } ], "name": "getBlackListStatus", "outputs": [{"internalType": "bool", "name": "", "type": "bool" } ], "stateMutability": "view", "type": "function" }, {"inputs": [], "name": "getPlatformFeeInfo", "outputs": [{"internalType": "address", "name": "", "type": "address" }, {"internalType": "uint64", "name": "", "type": "uint64" }, {"internalType": "uint64", "name": "", "type": "uint64" } ], "stateMutability": "view", "type": "function" }, {"inputs": [{"internalType": "bytes32", "name": "role", "type": "bytes32" } ], "name": "getRoleAdmin", "outputs": [{"internalType": "bytes32", "name": "", "type": "bytes32" } ], "stateMutability": "view", "type": "function" }, {"inputs": [{"internalType": "bytes32", "name": "role", "type": "bytes32" }, {"internalType": "address", "name": "account", "type": "address" } ], "name": "grantRole", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, {"inputs": [{"internalType": "bytes32", "name": "role", "type": "bytes32" }, {"internalType": "address", "name": "account", "type": "address" } ], "name": "hasRole", "outputs": [{"internalType": "bool", "name": "", "type": "bool" } ], "stateMutability": "view", "type": "function" }, {"inputs": [{"internalType": "address", "name": "spender", "type": "address" }, {"internalType": "uint256", "name": "addedValue", "type": "uint256" } ], "name": "increaseAllowance", "outputs": [{"internalType": "bool", "name": "", "type": "bool" } ], "stateMutability": "nonpayable", "type": "function" }, {"inputs": [], "name": "initialize", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, {"inputs": [{"internalType": "address", "name": "", "type": "address" } ], "name": "isBlackListed", "outputs": [{"internalType": "bool", "name": "", "type": "bool" } ], "stateMutability": "view", "type": "function" }, {"inputs": [], "name": "maxPlatformFee", "outputs": [{"internalType": "uint64", "name": "", "type": "uint64" } ], "stateMutability": "view", "type": "function" }, {"inputs": [{"internalType": "address", "name": "to", "type": "address" }, {"internalType": "uint256", "name": "amount", "type": "uint256" } ], "name": "mint", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, {"inputs": [{"internalType": "address", "name": "to", "type": "address" }, {"internalType": "uint256", "name": "amount", "type": "uint256" }, {"internalType": "uint256", "name": "fromChain", "type": "uint256" }, {"internalType": "uint256", "name": "fromChainBridgeNonce", "type": "uint256" } ], "name": "mintBridge", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, {"inputs": [], "name": "name", "outputs": [{"internalType": "string", "name": "", "type": "string" } ], "stateMutability": "view", "type": "function" }, {"inputs": [], "name": "pause", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, {"inputs": [], "name": "paused", "outputs": [{"internalType": "bool", "name": "", "type": "bool" } ], "stateMutability": "view", "type": "function" }, {"inputs": [], "name": "proxiableUUID", "outputs": [{"internalType": "bytes32", "name": "", "type": "bytes32" } ], "stateMutability": "view", "type": "function" }, {"inputs": [{"internalType": "address", "name": "_clearedUser", "type": "address" } ], "name": "removeBlackList", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, {"inputs": [{"internalType": "bytes32", "name": "role", "type": "bytes32" }, {"internalType": "address", "name": "account", "type": "address" } ], "name": "renounceRole", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, {"inputs": [{"internalType": "bytes32", "name": "role", "type": "bytes32" }, {"internalType": "address", "name": "account", "type": "address" } ], "name": "revokeRole", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, {"inputs": [{"internalType": "address", "name": "_platformFeeRecipient", "type": "address" }, {"internalType": "uint64", "name": "_burnBridgeFee", "type": "uint64" }, {"internalType": "uint64", "name": "_mintBridgeFee", "type": "uint64" } ], "name": "setPlatformFeeInfo", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, {"inputs": [{"internalType": "bytes4", "name": "interfaceId", "type": "bytes4" } ], "name": "supportsInterface", "outputs": [{"internalType": "bool", "name": "", "type": "bool" } ], "stateMutability": "view", "type": "function" }, {"inputs": [], "name": "symbol", "outputs": [{"internalType": "string", "name": "", "type": "string" } ], "stateMutability": "view", "type": "function" }, {"inputs": [], "name": "totalSupply", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256" } ], "stateMutability": "view", "type": "function" }, {"inputs": [{"internalType": "address", "name": "to", "type": "address" }, {"internalType": "uint256", "name": "amount", "type": "uint256" } ], "name": "transfer", "outputs": [{"internalType": "bool", "name": "", "type": "bool" } ], "stateMutability": "nonpayable", "type": "function" }, {"inputs": [{"internalType": "address", "name": "from", "type": "address" }, {"internalType": "address", "name": "to", "type": "address" }, {"internalType": "uint256", "name": "amount", "type": "uint256" } ], "name": "transferFrom", "outputs": [{"internalType": "bool", "name": "", "type": "bool" } ], "stateMutability": "nonpayable", "type": "function" }, {"inputs": [], "name": "unpause", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, {"inputs": [{"internalType": "address", "name": "newImplementation", "type": "address" } ], "name": "upgradeTo", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, {"inputs": [{"internalType": "address", "name": "newImplementation", "type": "address" }, {"internalType": "bytes", "name": "data", "type": "bytes" } ], "name": "upgradeToAndCall", "outputs": [], "stateMutability": "payable", "type": "function" } ];

const ALCHEMY_POLYGON_NETWORK = "matic";
const ALCHEMY_API_KEY = "{ALCHEMY API KEY}";
const WALLET_PRIVATE_KEY = "{WALLET PRIVATE KEY}";
const IDRX_CONTRACT_ADDRESS = "0x649a2DA7B28E0D54c13D5eFf95d3A660652742cC";

const provider = new ethers.providers.AlchemyProvider(ALCHEMY_POLYGON_NETWORK, ALCHEMY_API_KEY);
const signer = new ethers.Wallet(WALLET_PRIVATE_KEY, provider);

async function burnBridge() {
    const amount = "21500"; // raw amount
    const destinationChainId = "56"; // destination chain id (BSC)

    const idrxContract = new ethers.Contract(IDRX_CONTRACT_ADDRESS, idrxAbi, provider);
    const idrxContractSigner = idrxContract.connect(signer);
    const tx = await idrxContractSigner.burnBridge(amount, destinationChainId);
    const txHash = tx.hash;

    console.log('txHash: ');
    console.log(txHash);
}

burnBridge();
```

{% endtab %}

{% tab title="viem" %}

```typescript
import { createPublicClient, createWalletClient, http, parseAbi } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { polygon } from "viem/chains";
 
const idrxAbi = parseAbi([
  "function burnBridge(uint256 amount, uint256 toChain)",
  "function balanceOf(address account) view returns (uint256)",
  "function decimals() view returns (uint8)",
  "event BurnBridge(address _user, uint256 _amount, uint256 amountAfterCut, uint256 toChain, uint256 _bridgeNonce, uint256 platformFee)",
]);
 
const ALCHEMY_API_KEY = "{ALCHEMY API KEY}";
const WALLET_PRIVATE_KEY = "{WALLET PRIVATE KEY}";
const IDRX_CONTRACT_ADDRESS = "0x649a2DA7B28E0D54c13D5eFf95d3A660652742cC";
 
const transport = http(`https://polygon-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}`);
const account = privateKeyToAccount(WALLET_PRIVATE_KEY);
 
const publicClient = createPublicClient({ chain: polygon, transport });
const walletClient = createWalletClient({ account, chain: polygon, transport });
 
async function burnBridge() {
  const amount = 21500n;
  const destinationChainId = 56n; 
 
  const { request } = await publicClient.simulateContract({
    address: IDRX_CONTRACT_ADDRESS,
    abi: idrxAbi,
    functionName: "burnBridge",
    args: [amount, destinationChainId],
    account,
  });
 
  const txHash = await walletClient.writeContract(request);
 
  console.log("txHash: ");
  console.log(txHash);
 
  const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
  console.log("status:", receipt.status);
 
  return txHash;
}
 
burnBridge().catch(console.error);
```

{% endtab %}
{% endtabs %}

After the **burnBridge** transaction is confirmed on the source blockchain, use the resulting transaction hash as the value for the **txHashBurn** parameter when making a bridge request.

```typescript
import { createSignature } from "./createSignature";
const axios = require('axios');

const apiKey = "{API_KEY}";
const secret = "{API_SECRET}";

async function bridgeRequest() {
  const path = "https://idrx.co/api/transaction/bridge-request";

  const req = {
    "txHashBurn": "0x5d18bfc66cb345a03fcd1fab7c4edee12a065ab20b4ba5ebf005828116d62f8a",
    "bridgeToChainId": 56,
    "bridgeFromChainId": 137,
    "amount": "21500",
    "bridgeNonce": "26", // get this from the log of the burn transaction
    "destinationWalletAddress": "0x4313816F7Bfcff384053C70365eb6F3a4dbDD39f"
  };
  const bufferReq = Buffer.from(JSON.stringify(req), 'base64').toString('utf8');
  const timestamp = Math.round((new Date()).getTime()).toString();
  const sig = createSignature('POST', path, bufferReq, timestamp, secret);

  const res = await axios.post(path, req, {
    headers: {
      'Content-Type': 'application/json',
      'idrx-api-key': apiKey,
      'idrx-api-sig': sig,
      'idrx-api-ts' : timestamp,
    },
  });

  console.log('res.data: ');
  console.log(res.data);
}

bridgeRequest();



```

After a successful request, you will get a response as follows:

```typescript
{
  "statusCode": 201,
  "message": "success",
  "data": {
    "id": 3,
    "userId": 1,
    "bridgeFromChainId": 137,
    "bridgeToChainId": 56,
    "txHashBurn": "0x5d18bfc66cb345a03fcd1fab7c4edee12a065ab20b4ba5ebf005828116d62f8a",
    "txHashMint": null,
    "qredoTxId": null,
    "signedTx": null,
    "bridgeNonce": "26",
    "amount": "21500",
    "bridgeStatus": "REQUESTED",
    "deleted": false
  }
}
```

To check the status of the transaction, you can use the [Transaction History API](/api/transaction-api/get-api-transaction-user-transaction-history). The bridge request will then be processed shortly after, and the IDRX will be sent to the destination wallet address.


