Issue OTP
Sends a one-time code for a single purchase.
POST /api/sp/v1/dcb/purchase/otp
Request
| Field | Type | Notes |
|---|---|---|
msisdn | string | The subscriber's number. |
shortCode | string | The short code your credential is bound to. |
serviceId | integer | The service. |
spTransactionId | string | Yours, unique per attempt. See Idempotency. |
language | ar · en · ku | The language of the message. Required. |
Response
{
"requestId": "01JB2K9WQ4X7YH3M8N5P6R7T8V",
"code": "OK",
"data": { "expiresInMinutes": 10, "amount": 500, "currency": "IQD" }
}
| Field | Notes |
|---|---|
expiresInMinutes | How long the OTP stays valid. Read it rather than hard-coding it. |
amount | What the subscriber will be charged, from the service configuration. |
currency | IQD. |
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.