Skip to main content
OTP.ID operates on a prepaid billing model: you maintain a credit balance, and each successful OTP delivery draws from those credits at a per-channel rate (your account may have custom rates per channel — the price field in each response always shows the rate that applies to you). There are no monthly fees or minimum commitments — you pay only for OTPs that are actually delivered (with one exception: whatsapp_inbound, which is charged when the transaction is created — see below). This page explains exactly when credits are deducted, what the billing-related response fields mean, and how to handle insufficient credits.

How the Prepaid Model Works

Before sending OTPs, you top up your credits through the OTP.ID dashboard. Your credit balance is stored as an integer number of credits. Each delivery attempt has an associated price — the number of credits charged for that channel and transaction. When OTP.ID successfully delivers an OTP, the price is atomically deducted from your credit balance at the moment of delivery. You can top up credits in two ways:
  • From the OTP.ID dashboard at https://app.otp.id.
  • From your server with POST /v3/topups, which returns a signed payment_url that can be opened without dashboard login.
Top-up payment links expire after 3 hours. QRIS and Virtual Account instructions are displayed on OTP.ID itself, so users do not need to leave your payment page for an external Tokopay checkout.

When Credits Are (and Are Not) Deducted

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

Credits ARE 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.
  • A whatsapp_inbound transaction is created — this channel has no outbound delivery, so the charge applies up front when the transaction (and its token) is issued, while the status is still pending. The charge is not refunded if the user never sends the verification message.

Credits are 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 credit balance by exactly price.
In this example, the transaction cost 350 credits. Your credit balance before the request was 100,000 credits; your credit balance after is 99,650 credits.

Failed Delivery

When the vendor cannot deliver the OTP, last_balance is unchanged — your credit balance before and after the request is the same.
Here, price is still 350 credits (showing what would have been charged), but last_balance remains 100,000 credits 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 credits are exhausted.

Insufficient Credits

If your credit 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 — You do not have enough credits 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. Open the Isi Kredit (top-up) page and add credits to your account.
  3. Retry the original API request once your credits have been updated.
Do not retry the request automatically in a loop — your credits will not change until you manually top up.

Billing Summary