IDRX API

Mint, redeem, and bridge IDRX (Indonesian Rupiah stablecoin), onboard users, manage bank accounts, and query rates/fees/history. API key + HMAC-SHA256 request signing; single-delivery webhooks for settlement.

OpenAPI Specification

idrx-openapi.yml Raw ↑
openapi: 3.1.0
info:
  title: IDRX API
  version: '1.0'
  description: >-
    IDRX is a stablecoin pegged 1:1 to the Indonesian Rupiah (IDR). This REST API
    lets business (organization) accounts onboard users, manage bank accounts, and
    process mint (fiat IDR -> IDRX / USDT on-chain), redeem (IDRX -> fiat IDR to a
    bank account), and bridge (move IDRX across supported EVM/Solana chains)
    transactions, plus query rates, fees, bank methods, and transaction history.
    All requests are authenticated with an API key plus an HMAC-SHA256 request
    signature. A custom `User-Agent` header is required (generic agents are blocked
    at the edge with HTTP 403 / Cloudflare 1010).
  contact:
    name: IDRX Support
    email: support@idrx.co
    url: https://docs.idrx.co
  x-apievangelist-generated: '2026-07-19'
  x-apievangelist-method: searched
  x-apievangelist-source: https://docs.idrx.co/llms.txt
servers:
  - url: https://idrx.co
    description: Production
tags:
  - name: Onboarding
    description: Onboard users and manage their bank accounts.
  - name: Transaction
    description: Mint, redeem, and bridge IDRX, and query rates/fees/history.
security:
  - idrxApiKey: []
paths:
  /api/auth/generate-api-key:
    post:
      operationId: generateApiKey
      tags: [Onboarding]
      summary: Generate an API key
      description: Issue an API key/secret pair for an account. Store the secret securely; it is used to sign requests.
      responses:
        '201':
          description: API key issued.
  /api/auth/onboarding:
    post:
      operationId: onboardUser
      tags: [Onboarding]
      summary: Onboard a new user
      description: >-
        Used by an organization to onboard a new user. Accounts registered this way
        skip part of the KYC process. Accepts `multipart/form-data`.
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              required: [email, fullname, address, idNumber, idFile]
              properties:
                email:
                  type: string
                  format: email
                fullname:
                  type: string
                address:
                  type: string
                idNumber:
                  type: string
                idFile:
                  type: string
                  format: binary
                  description: 'Image of the user ID (jpeg, png, jpg, webp; 256x256 to 4096x4096).'
      responses:
        '201':
          description: User onboarded.
          content:
            application/json:
              schema:
                type: object
                properties:
                  statusCode: { type: integer, example: 201 }
                  message: { type: string, example: success }
                  data:
                    type: object
                    properties:
                      id: { type: integer }
                      fullname: { type: string }
                      createdAt: { type: string, format: date-time }
                      apiKey: { type: string }
                      apiSecret: { type: string }
        '400': { $ref: '#/components/responses/BadRequest' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
  /api/auth/members:
    get:
      operationId: getMembers
      tags: [Onboarding]
      summary: Get members
      description: Get info about the members registered under the organization account.
      responses:
        '200':
          description: Member list.
          content:
            application/json:
              schema:
                type: object
                properties:
                  statusCode: { type: integer }
                  message: { type: string }
                  data:
                    type: array
                    items:
                      type: object
                      properties:
                        id: { type: integer }
                        email: { type: string, format: email }
                        createdAt: { type: string, format: date-time }
                        fullname: { type: string }
                        ApiKeys:
                          type: array
                          items:
                            type: object
                            properties:
                              apiKey: { type: string }
        '401': { $ref: '#/components/responses/Unauthorized' }
  /api/auth/add-bank-account:
    post:
      operationId: addBankAccount
      tags: [Onboarding]
      summary: Add a bank account
      description: >-
        Add a new bank account. A deposit wallet address associated with the bank
        account is also created; users can send IDRX to that address to redeem to
        the bank account.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [bankAccountNumber, bankCode]
              properties:
                bankAccountNumber: { type: string }
                bankCode:
                  type: string
                  description: Bank code from GET /api/transaction/method.
      responses:
        '201':
          description: Bank account added.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/BankAccountEnvelope' }
        '400': { $ref: '#/components/responses/BadRequest' }
        '401': { $ref: '#/components/responses/Unauthorized' }
  /api/auth/get-bank-accounts:
    get:
      operationId: getBankAccounts
      tags: [Onboarding]
      summary: Get bank accounts
      description: List the bank accounts registered under the account.
      responses:
        '200':
          description: Bank account list.
          content:
            application/json:
              schema:
                type: object
                properties:
                  statusCode: { type: integer }
                  message: { type: string }
                  data:
                    type: array
                    items: { $ref: '#/components/schemas/BankAccount' }
        '401': { $ref: '#/components/responses/Unauthorized' }
  /api/auth/delete-bank-account/{bankId}:
    delete:
      operationId: deleteBankAccount
      tags: [Onboarding]
      summary: Delete a bank account
      parameters:
        - name: bankId
          in: path
          required: true
          schema: { type: integer }
      responses:
        '200':
          description: Bank account deleted.
          content:
            application/json:
              schema:
                type: object
                properties:
                  statusCode: { type: integer, example: 200 }
                  message: { type: string, example: deleted }
                  data: { type: 'null' }
        '401': { $ref: '#/components/responses/Unauthorized' }
  /api/transaction/mint-request:
    post:
      operationId: createMintRequest
      tags: [Transaction]
      summary: Create a mint request
      description: >-
        Request an IDRX (or USDT) mint on a supported chain, paid with fiat IDR.
        Returns a hosted-checkout `paymentUrl` to redirect the user to. Min 20,000
        IDR / 2 USD; max 1,000,000,000 IDR / 5,555 USD. Confirm settlement via the
        callback or Transaction History (do not trust the returnUrl redirect).
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [toBeMinted, destinationWalletAddress, networkChainId, returnUrl]
              properties:
                toBeMinted: { type: string, description: Amount to mint. }
                destinationWalletAddress: { type: string }
                networkChainId: { type: string, description: Target EVM/Solana chain ID. }
                returnUrl: { type: string, format: uri }
                requestType:
                  type: string
                  enum: [idrx, usdt]
                  default: idrx
                expiryPeriod: { type: integer, default: 120, description: Payment window in minutes. }
                productDetails: { type: string, maxLength: 255 }
                customerDetail:
                  type: object
                  properties:
                    firstName: { type: string, maxLength: 50 }
                    lastName: { type: string, maxLength: 50 }
                    email: { type: string, format: email }
      responses:
        '200':
          description: Mint request created; redirect user to paymentUrl.
          content:
            application/json:
              schema:
                type: object
                properties:
                  statusCode: { type: integer }
                  message: { type: string }
                  data:
                    type: object
                    properties:
                      id: { type: string }
                      merchantOrderId: { type: string }
                      merchantCode: { type: string }
                      reference: { type: string }
                      paymentUrl: { type: string, format: uri }
                      amount: { type: string, description: Amount after fees the user pays. }
                      statusCode: { type: string }
                      statusMessage: { type: string }
        '400': { $ref: '#/components/responses/BadRequest' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '422': { $ref: '#/components/responses/Unprocessable' }
        '429': { $ref: '#/components/responses/RateLimited' }
  /api/transaction/redeem-request:
    post:
      operationId: createRedeemRequest
      tags: [Transaction]
      summary: Create a redeem request
      description: >-
        Redeem IDRX back to fiat IDR to a bank account, referencing the on-chain
        burn transaction hash. Funds credited within max 24 hours.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [txHash, networkChainId, amountTransfer, bankAccount, bankCode, bankName, bankAccountName, walletAddress]
              properties:
                txHash: { type: string, description: Hash of the token burn transaction. }
                networkChainId: { type: string }
                amountTransfer: { type: string }
                bankAccount: { type: string }
                bankCode: { type: string }
                bankName: { type: string }
                bankAccountName: { type: string }
                walletAddress: { type: string }
                notes: { type: string }
      responses:
        '200':
          description: Redeem request created.
          content:
            application/json:
              schema:
                type: object
                properties:
                  statusCode: { type: integer }
                  message: { type: string }
                  data: { $ref: '#/components/schemas/RedeemRequest' }
        '400': { $ref: '#/components/responses/BadRequest' }
        '401': { $ref: '#/components/responses/Unauthorized' }
  /api/transaction/bridge-request:
    post:
      operationId: createBridgeRequest
      tags: [Transaction]
      summary: Create a bridge request
      description: Bridge IDRX from a source chain to a destination chain, referencing the burn tx hash and bridge nonce. Min 20,000 IDR.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [txHashBurn, bridgeToChainId, bridgeFromChainId, amount, bridgeNonce, destinationWalletAddress]
              properties:
                txHashBurn: { type: string }
                bridgeToChainId: { type: integer }
                bridgeFromChainId: { type: integer }
                amount: { type: string }
                bridgeNonce: { type: string }
                destinationWalletAddress: { type: string }
      responses:
        '201':
          description: Bridge request created.
          content:
            application/json:
              schema:
                type: object
                properties:
                  statusCode: { type: integer }
                  message: { type: string }
                  data: { $ref: '#/components/schemas/BridgeRequest' }
        '400': { $ref: '#/components/responses/BadRequest' }
        '401': { $ref: '#/components/responses/Unauthorized' }
  /api/transaction/method:
    get:
      operationId: getBankMethods
      tags: [Transaction]
      summary: Get bank methods
      description: Get the list of supported bank names, bank codes, and max transfer amounts.
      responses:
        '200':
          description: Bank method list.
          content:
            application/json:
              schema:
                type: object
                properties:
                  statusCode: { type: integer }
                  message: { type: string }
                  data:
                    type: array
                    items:
                      type: object
                      properties:
                        bankCode: { type: string }
                        bankName: { type: string }
                        maxAmountTransfer: { type: string }
        '401': { $ref: '#/components/responses/Unauthorized' }
  /api/transaction/user-transaction-history:
    get:
      operationId: getTransactionHistory
      tags: [Transaction]
      summary: Get transaction history
      description: List the account's mint/redeem/bridge transaction history. Poll by merchantOrderId to reconcile terminal states.
      responses:
        '200':
          description: Transaction history.
          content:
            application/json:
              schema:
                type: object
                properties:
                  statusCode: { type: integer }
                  message: { type: string }
                  data:
                    type: array
                    items: { type: object }
        '401': { $ref: '#/components/responses/Unauthorized' }
  /api/transaction/rates:
    get:
      operationId: getRates
      tags: [Transaction]
      summary: Get swap rates
      description: >-
        Get current swap rates of IDRX to other tokens. Provide either idrxAmount
        or usdtAmount. chainId defaults to 137 (Polygon).
      parameters:
        - name: idrxAmount
          in: query
          schema: { type: string }
          description: IDRX amount to sell (provide this or usdtAmount).
        - name: usdtAmount
          in: query
          schema: { type: string }
          description: USDT/USDC amount to sell (provide this or idrxAmount).
        - name: chainId
          in: query
          schema: { type: string, default: '137' }
      responses:
        '200':
          description: Rate quote.
          content:
            application/json:
              schema:
                type: object
                properties:
                  statusCode: { type: integer }
                  message: { type: string }
                  data:
                    type: object
                    properties:
                      price: { type: string }
                      buyAmount: { type: string }
                      chainId: { type: integer }
                      quote: { type: object }
        '401': { $ref: '#/components/responses/Unauthorized' }
  /api/transaction/get-additional-fees:
    get:
      operationId: getAdditionalFees
      tags: [Transaction]
      summary: Get additional fees
      description: Get additional fees for a transaction type (MINT, REDEEM, REFUND) on a chain.
      parameters:
        - name: feeType
          in: query
          required: true
          schema: { type: string, enum: [MINT, REDEEM, REFUND] }
        - name: chainId
          in: query
          schema: { type: string }
      responses:
        '200':
          description: Additional fee list.
          content:
            application/json:
              schema:
                type: object
                properties:
                  statusCode: { type: integer }
                  message: { type: string }
                  data:
                    type: array
                    items:
                      type: object
                      properties:
                        id: { type: integer }
                        name: { type: string }
                        amount: { type: string }
                        isActive: { type: boolean }
                        deleted: { type: boolean }
        '401': { $ref: '#/components/responses/Unauthorized' }
webhooks:
  mintCallback:
    post:
      operationId: mintCallback
      summary: Mint transaction callback
      description: >-
        Fires once when a mint transaction reaches a terminal state (adminMintStatus
        MINTED). Not retried. No signature on the outgoing webhook; reconcile by
        merchantOrderId and re-verify via Transaction History before crediting users.
      requestBody:
        content:
          application/json:
            schema: { $ref: '#/components/schemas/MintCallback' }
      responses:
        '200':
          description: Return 2xx quickly and process asynchronously.
  redeemCallback:
    post:
      operationId: redeemCallback
      summary: Redeem transaction callback
      description: Fires once when a redeem transaction reaches a terminal state. Not retried; reconcile by merchantOrderId.
      requestBody:
        content:
          application/json:
            schema: { type: object }
      responses:
        '200':
          description: Return 2xx quickly and process asynchronously.
components:
  securitySchemes:
    idrxApiKey:
      type: apiKey
      in: header
      name: idrx-api-key
      description: >-
        API key issued by IDRX. Each request must also carry `idrx-api-sig` (an
        HMAC-SHA256 signature) and `idrx-api-ts` (Unix ms timestamp), plus a custom
        `User-Agent`. Signature = HMAC-SHA256(secret, METHOD + ":" + PATH + ":" +
        SHA256(body) + ":" + timestamp).
  responses:
    BadRequest:
      description: Invalid parameter — check param types and limits.
      content:
        application/json:
          schema: { $ref: '#/components/schemas/Error' }
    Unauthorized:
      description: Bad signature or timestamp drift — recompute signature and sync clock (NTP).
      content:
        application/json:
          schema: { $ref: '#/components/schemas/Error' }
    Forbidden:
      description: Blocked User-Agent — set a custom User-Agent like my-app/1.0 (Cloudflare 1010).
      content:
        application/json:
          schema: { $ref: '#/components/schemas/Error' }
    Unprocessable:
      description: Unsupported channelId for merchant — contact support@idrx.co to enable.
      content:
        application/json:
          schema: { $ref: '#/components/schemas/Error' }
    RateLimited:
      description: Rate limit — back off and retry.
      content:
        application/json:
          schema: { $ref: '#/components/schemas/Error' }
  schemas:
    Error:
      type: object
      properties:
        statusCode: { type: integer }
        message: { type: string }
        data: { type: 'null' }
    BankAccount:
      type: object
      properties:
        id: { type: integer }
        userId: { type: integer }
        bankAccountNumber: { type: string }
        bankAccountName: { type: string }
        bankAccountNumberHash: { type: [string, 'null'] }
        bankCode: { type: string }
        bankName: { type: string }
        maxAmountTransfer: { type: string }
        deleted: { type: boolean }
        DepositWalletAddress:
          type: object
          properties:
            walletAddress: { type: string }
            createdAt: { type: string, format: date-time }
    BankAccountEnvelope:
      type: object
      properties:
        statusCode: { type: integer }
        message: { type: string }
        data: { $ref: '#/components/schemas/BankAccount' }
    RedeemRequest:
      type: object
      properties:
        id: { type: integer }
        chainId: { type: integer }
        userId: { type: integer }
        requester: { type: string }
        txHash: { type: string }
        fromAddress: { type: string }
        amount: { type: string }
        bankName: { type: string }
        bankCode: { type: string }
        bankAccountNumber: { type: string }
        bankAccountName: { type: string }
        custRefNumber: { type: string }
        disburseId: { type: integer }
        burnStatus: { type: string, enum: [REQUESTED, PROCESSING, PROCESSED, REJECTED] }
        createdAt: { type: string, format: date-time }
        updatedAt: { type: string, format: date-time }
        deleted: { type: boolean }
    BridgeRequest:
      type: object
      properties:
        id: { type: integer }
        userId: { type: integer }
        bridgeFromChainId: { type: integer }
        bridgeToChainId: { type: integer }
        txHashBurn: { type: string }
        txHashMint: { type: [string, 'null'] }
        qredoTxId: { type: [string, 'null'] }
        signedTx: { type: [string, 'null'] }
        bridgeNonce: { type: string }
        amount: { type: string }
        bridgeStatus: { type: string, enum: [REQUESTED, PROCESSING, PROCESSED, REJECTED] }
        deleted: { type: boolean }
    MintCallback:
      type: object
      properties:
        id: { type: integer }
        paymentAmount: { type: number }
        toBeMinted: { type: string }
        merchantOrderId: { type: string }
        destinationWalletAddress: { type: string }
        chainId: { type: integer }
        paymentStatus: { type: string, enum: [WAITING_FOR_PAYMENT, PAID, EXPIRED] }
        userMintStatus: { type: string, enum: [PROCESSING, MINTED, NOT_AVAILABLE] }
        adminMintStatus: { type: string, enum: [REQUESTED, PROCESSING, MINTED, REJECTED] }
        txHash: { type: string }
        reference: { type: string }
        requestType: { type: [string, 'null'] }
        customerVaName: { type: string }
        paymentProviderId: { type: integer }
        returnUrl: { type: [string, 'null'] }
        expiryTimestamp: { type: string }
        isApproved: { type: boolean }
        reportStatus: { type: string, enum: [NONE, PENDING, RESOLVED] }
        createdAt: { type: string, format: date-time }
        updatedAt: { type: string, format: date-time }
        TransactionHistory: { type: object }
        MintRequestTransactionFees:
          type: array
          items:
            type: object
            properties:
              name: { type: string }
              amount: { type: string }
        usdtRequest: { type: [object, 'null'] }