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 associatedprice — 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 signedpayment_urlthat can be opened without dashboard login.
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
sentorsuccess. The deduction happens atomically at the moment of delivery, not at request time. - A
whatsapp_inboundtransaction 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 stillpending. 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 OKresponse, butstatusisfailed. 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.
Failed Delivery
When the vendor cannot deliver the OTP,last_balance is unchanged — your credit balance before and after the request is the same.
price is still 350 credits (showing what would have been charged), but last_balance remains 100,000 credits because no deduction occurred.
Insufficient Credits
If your credit balance is too low to cover the cost of the requested transaction, OTP.ID returns an HTTP402 error before attempting delivery.

