# Processing Mint IDRX Requests

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&#x20;
{% 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 (VA, QRIS, 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.md) 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"
  };

  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": {
    "merchantCode": "D11808",
    "reference": "D11808T8GVTL81VV2U7HV",
    "paymentUrl": "https://app-prod.duitku.com/redirect_checkout?reference=D11808T8GVTL81VV2U7HV",
    "amount": "54500.00",
    "statusCode": "00",
    "statusMessage": "SUCCESS",
    "merchantOrderId": "20231219101707"
  }
}
```

{% hint style="info" %}
`amount` is the final amount paid by the user after fees.\
Store `merchantOrderId` in your database — it is required for status tracking and reconciliation.
{% endhint %}

The user then completes payment using `paymentUrl`.

For mobile or white-label integrations that skip the hosted checkout page, see:

* `Flow B — Direct Payment` : [Link](/api/transaction-api/post-api-transaction-mint-request.md#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.md)
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.md). Next, we will explore on processing redeem requests.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.idrx.co/integration/processing-mint-idrx-requests.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
