Skip to main content

Issue OTP

Sends a one-time code for a single purchase.

POST /api/sp/v1/dcb/purchase/otp

Request

FieldTypeNotes
msisdnstringThe subscriber's number.
shortCodestringThe short code your credential is bound to.
serviceIdintegerThe service.
spTransactionIdstringYours, unique per attempt. See Idempotency.
languagear · en · kuThe language of the message. Required.

Response

{
"requestId": "01JB2K9WQ4X7YH3M8N5P6R7T8V",
"code": "OK",
"data": { "expiresInMinutes": 10, "amount": 500, "currency": "IQD" }
}
FieldNotes
expiresInMinutesHow long the OTP stays valid. Read it rather than hard-coding it.
amountWhat the subscriber will be charged, from the service configuration.
currencyIQD.

amount is the figure to put on your confirmation screen. It is the same number the SMS quotes to the subscriber, so taking it from here rather than from your own records means the two cannot disagree.

You do not send the amount

amount is prohibited on this call. Sending it is a validation failure, not a silent override.

The price comes from the service's own configuration, not from your request, so an integration cannot charge an arbitrary sum, whatever happens to its own code. If the price needs to change, that is a service configuration change, arranged with the operator team.

Eligibility is checked here, before any message is sent

This is the deliberate part: if the purchase cannot complete, you find out now, and the subscriber is never sent a code for something that was always going to fail.

So PARENT_SUBSCRIPTION_REQUIRED, PURCHASE_DAILY_LIMIT_REACHED, PURCHASE_AMOUNT_LIMIT_REACHED and PURCHASE_CHANNEL_NOT_ENABLED can all be returned at this step, with no SMS spent.

Eligibility is checked again at Verify: the second check catches a subscriber who became ineligible in between. The two are additive, not alternatives, so do not treat passing here as a guarantee.