Skip to main content
OTP.ID operates on a prepaid billing model: you maintain a balance denominated in Indonesian Rupiah (IDR), and each successful OTP delivery draws from that balance at a fixed per-channel rate. There are no monthly fees or minimum commitments — you pay only for OTPs that are actually delivered. This page explains exactly when charges apply, what the billing-related response fields mean, and how to handle an insufficient balance.

How the Prepaid Model Works

Before sending OTPs, you top up your account balance through the OTP.ID dashboard. Your balance is stored in IDR as an integer (representing the exact Rupiah amount). Each delivery attempt has an associated price — the cost in IDR for that channel and transaction. When OTP.ID successfully delivers an OTP, the price is atomically deducted from your balance at the moment of delivery. To top up your balance, log in to the OTP.ID dashboard and follow the top-up flow. There is no API endpoint for initiating a top-up.

When Your Balance Is (and Is Not) Deducted

Not every API call results in a charge. OTP.ID only deducts your balance when value is delivered.

Balance IS deducted when:

  • The channel vendor successfully delivers the OTP — the transaction status is sent or success.
  • The deduction happens atomically at the moment of delivery, not at request time.

Balance is NOT deducted when:

  • Vendor delivery fails — the transaction is created and you receive a 200 OK response, but status is failed. No charge is applied.
  • Idempotent replay — if you repeat a request with the same external_id, OTP.ID recognises it as a duplicate and does not create a new transaction or deduct a new charge.
Even when delivery fails, OTP.ID returns HTTP 200 OK with status: "failed" in the response body. Always check the status field — a 200 response does not guarantee a charge was made or that the OTP was delivered.

Billing Fields in API Responses

Every transaction response includes two billing-related fields.

Successful Delivery

When the OTP is delivered successfully, last_balance is lower than your pre-request balance by exactly price.
In this example, the transaction cost 350 IDR. Your balance before the request was 100,000 IDR; your balance after is 99,650 IDR.

Failed Delivery

When the vendor cannot deliver the OTP, last_balance is unchanged — your balance before and after the request is the same.
Here, price is still 350 IDR (showing what would have been charged), but last_balance remains 100,000 IDR because no deduction occurred.
Use last_balance to keep a running display of your remaining credits in an internal dashboard or alerting system. If last_balance drops below a threshold you define, trigger an automated notification to top up before your balance is exhausted.

Insufficient Balance

If your balance is too low to cover the cost of the requested transaction, OTP.ID returns an HTTP 402 error before attempting delivery.
402 INSUFFICIENT_BALANCE — Your account balance is too low to send this OTP. OTP.ID will not attempt delivery, and no transaction is created.To resolve this:
  1. Log in to the OTP.ID dashboard.
  2. Navigate to the top-up section and add funds to your account.
  3. Retry the original API request once your balance has been updated.
Do not retry the request automatically in a loop — the balance will not change until you manually top up.

Billing Summary