Send Mobile Top-Up
curl --request POST \
--url https://api.oneclickdz.com/v3/mobile/send \
--header 'Content-Type: application/json' \
--header 'X-Access-Token: <api-key>' \
--data '
{
"plan_code": "<string>",
"MSSIDN": "<string>",
"amount": 123,
"ref": "<string>"
}
'import requests
url = "https://api.oneclickdz.com/v3/mobile/send"
payload = {
"plan_code": "<string>",
"MSSIDN": "<string>",
"amount": 123,
"ref": "<string>"
}
headers = {
"X-Access-Token": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-Access-Token': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({plan_code: '<string>', MSSIDN: '<string>', amount: 123, ref: '<string>'})
};
fetch('https://api.oneclickdz.com/v3/mobile/send', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.oneclickdz.com/v3/mobile/send",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'plan_code' => '<string>',
'MSSIDN' => '<string>',
'amount' => 123,
'ref' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-Access-Token: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.oneclickdz.com/v3/mobile/send"
payload := strings.NewReader("{\n \"plan_code\": \"<string>\",\n \"MSSIDN\": \"<string>\",\n \"amount\": 123,\n \"ref\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-Access-Token", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.oneclickdz.com/v3/mobile/send")
.header("X-Access-Token", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"plan_code\": \"<string>\",\n \"MSSIDN\": \"<string>\",\n \"amount\": 123,\n \"ref\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.oneclickdz.com/v3/mobile/send")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-Access-Token"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"plan_code\": \"<string>\",\n \"MSSIDN\": \"<string>\",\n \"amount\": 123,\n \"ref\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"data": {
"topupId": "<string>",
"topupRef": "<string>"
},
"meta": {
"timestamp": "<string>"
}
}Mobile Top-Ups
Send Mobile Top-Up
Create and send a mobile top-up request
POST
/
v3
/
mobile
/
send
Send Mobile Top-Up
curl --request POST \
--url https://api.oneclickdz.com/v3/mobile/send \
--header 'Content-Type: application/json' \
--header 'X-Access-Token: <api-key>' \
--data '
{
"plan_code": "<string>",
"MSSIDN": "<string>",
"amount": 123,
"ref": "<string>"
}
'import requests
url = "https://api.oneclickdz.com/v3/mobile/send"
payload = {
"plan_code": "<string>",
"MSSIDN": "<string>",
"amount": 123,
"ref": "<string>"
}
headers = {
"X-Access-Token": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-Access-Token': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({plan_code: '<string>', MSSIDN: '<string>', amount: 123, ref: '<string>'})
};
fetch('https://api.oneclickdz.com/v3/mobile/send', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.oneclickdz.com/v3/mobile/send",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'plan_code' => '<string>',
'MSSIDN' => '<string>',
'amount' => 123,
'ref' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-Access-Token: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.oneclickdz.com/v3/mobile/send"
payload := strings.NewReader("{\n \"plan_code\": \"<string>\",\n \"MSSIDN\": \"<string>\",\n \"amount\": 123,\n \"ref\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-Access-Token", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.oneclickdz.com/v3/mobile/send")
.header("X-Access-Token", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"plan_code\": \"<string>\",\n \"MSSIDN\": \"<string>\",\n \"amount\": 123,\n \"ref\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.oneclickdz.com/v3/mobile/send")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-Access-Token"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"plan_code\": \"<string>\",\n \"MSSIDN\": \"<string>\",\n \"amount\": 123,\n \"ref\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"data": {
"topupId": "<string>",
"topupRef": "<string>"
},
"meta": {
"timestamp": "<string>"
}
}Overview
Send instant mobile top-ups to Algerian operators (Mobilis, Djezzy, Ooredoo, Pixx) with real-time status tracking.Recommended: Use unique
ref parameter to prevent duplicate orders and
enable easy tracking.Request Body
string
required
Plan code from
/mobile/plans endpoint (e.g., PREPAID_DJEZZY, PIXX_500)string
required
Phone number in format
0[567][0-9]{8} (must be string, not number)
Examples: "0778037340", "0665983439", "0556121212"integer
Top-up amount in DZD (required for dynamic plans, ignored for fixed plans)
Must be between
min_amount and max_amount from plan detailsstring
Your unique order reference for tracking (auto-generated if not provided)
Important: Prevents duplicate requests if same ref is submitted twice
Response
boolean
required
Indicates if the request was successfully submitted
object
required
Examples
curl https://api.oneclickdz.com/v3/mobile/send \
-X POST \
-H "Content-Type: application/json" \
-H "X-Access-Token: YOUR_API_KEY" \
-d '{
"plan_code": "PREPAID_DJEZZY",
"MSSIDN": "0778037340",
"amount": 500,
"ref": "order-12345"
}'
const response = await fetch("https://api.oneclickdz.com/v3/mobile/send", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Access-Token": "YOUR_API_KEY",
},
body: JSON.stringify({
plan_code: "PREPAID_DJEZZY",
MSSIDN: "0778037340",
amount: 500,
ref: "order-12345",
}),
});
const data = await response.json();
console.log(data.data.topupId);
import requests
response = requests.post(
'https://api.oneclickdz.com/v3/mobile/send',
headers={
'Content-Type': 'application/json',
'X-Access-Token': 'YOUR_API_KEY'
},
json={
'plan_code': 'PREPAID_DJEZZY',
'MSSIDN': '0778037340',
'amount': 500,
'ref': 'order-12345'
}
)
topup_id = response.json()['data']['topupId']
<?php
$data = [
'plan_code' => 'PREPAID_DJEZZY',
'MSSIDN' => '0778037340',
'amount' => 500,
'ref' => 'order-12345'
];
$ch = curl_init('https://api.oneclickdz.com/v3/mobile/send');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'X-Access-Token: YOUR_API_KEY'
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
$response = json_decode(curl_exec($ch), true);
$topupId = $response['data']['topupId'];
?>
Success Response
{
"success": true,
"data": {
"topupId": "6901616fe9e88196b4eb64b0",
"topupRef": "API-+213665983439-test-1761698159224-success"
},
"meta": {
"timestamp": "2025-10-29T00:35:59.454Z"
}
}
Error Responses
400 - Validation Errors
400 - Validation Errors
Invalid request body or parametersCommon validation errors:
{
"success": false,
"error": {
"code": "ERR_VALIDATION",
"message": "body/MSSIDN must match pattern \"^0[567][0-9]{8}$\"",
"details": {
"field": "MSSIDN",
"value": "778037340"
}
},
"requestId": "req_1730160959_xyz789"
}
- Missing
plan_codeorMSSIDN - Invalid phone number format
amountrequired for dynamic plansamountoutside min/max range- MSSIDN doesn’t match plan operator
403 - Insufficient Balance
403 - Insufficient Balance
Not enough balance for the operation
{
"success": false,
"error": {
"code": "INSUFFICIENT_BALANCE",
"message": "Your balance is insufficient for this operation",
"details": {
"required": 500,
"available": 250
}
},
"requestId": "req_1730160959_def456"
}
403 - Duplicate Reference
403 - Duplicate Reference
Reference already usedSolution: Check the status of the existing top-up using the same reference
{
"success": false,
"error": {
"code": "DUPLICATED-REF",
"message": "This reference ID is already in use."
},
"requestId": "req_1730160959_ghi789"
}
500 - Internal Error
500 - Internal Error
Server error (rare)Action: Contact support with the
{
"success": false,
"error": {
"code": "INTERNAL_ERROR",
"message": "Developer was notified and will check shortly"
},
"requestId": "req_1730160959_jkl012"
}
requestId. Do NOT refund until investigated.Preventing Duplicate Requests
The
ref field ensures the top-up is processed only once, even in case of network issues.async function sendTopUpSafe(planCode, phone, amount, orderId) {
// Use orderId as the ref for idempotency
const ref = `topup-${orderId}`;
try {
const response = await fetch("https://api.oneclickdz.com/v3/mobile/send", {
method: "POST",
headers: {
"X-Access-Token": API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({
plan_code: planCode,
MSSIDN: phone,
amount,
ref,
}),
});
const data = await response.json();
if (data.success) {
return { success: true, topupId: data.data.topupId };
}
// Handle duplicate ref - order already exists
if (data.error.code === "DUPLICATED-REF") {
const status = await checkTopUpByRef(ref);
return { success: true, topupId: status.data._id, fromExisting: true };
}
throw new Error(`${data.error.code}: ${data.error.message}`);
} catch (networkError) {
// Network error - check if order was created
const status = await checkTopUpByRef(ref);
if (status.success) {
return { success: true, topupId: status.data._id, fromExisting: true };
}
throw networkError;
}
}
Phone Number Format
Phone number must be a string, not a number. Leading zero is required.
- ✅
"0778037340"(string with leading zero) - ✅
"0665983439" - ✅
"0556121212"
- ❌
778037340(missing leading zero) - ❌
0778037340(number type instead of string) - ❌
"+213778037340"(international format) - ❌
"0778 037 340"(contains spaces)
Status Lifecycle
After sending a top-up, it goes through these states:1
PENDING
Order created and queued for processing Duration: 2-15 seconds (typical)
2
HANDLING
Currently being processed by operator Duration: 3-8 seconds (typical)
3
Final State
FULFILLED: Successfully completed ✅ REFUNDED: Failed and refunded
❌ UNKNOWN_ERROR: Uncertain state (resolves in 24h) ⚠️
Recommended Integration Flow
1
Create Order in Your DB
const order = await db.orders.create({
id: generateOrderId(),
userId: user.id,
phone: '0778037340',
amount: 500,
status: 'PROCESSING'
});
2
Deduct User Balance
await db.users.update({
id: user.id,
balance: user.balance - 500
});
3
Return Order to User
res.json({
orderId: order.id,
status: 'PROCESSING',
message: 'Top-up is being processed'
});
4
Async: Send to API
// In background job
const response = await sendTopup({
plan_code: 'PREPAID_DJEZZY',
MSSIDN: order.phone,
amount: order.amount,
ref: order.id
});
await db.orders.update({
id: order.id,
apiTopupId: response.data.topupId
});
5
Poll Status & Update
const status = await checkTopupStatus(order.id);
await db.orders.update({
id: order.id,
status: status.data.status
});
if (status.data.status === 'REFUNDED') {
await refundUserBalance(user.id, order.amount);
}
Sandbox Testing
Enable sandbox mode to test without real transactions:Normal Flow
Use any normal number (e.g.,
0778037340) Flow: PENDING (5s) → HANDLING
(15s) → FULFILLEDRefund with Message
Use:
0600000001 Returns: REFUNDED with refund_messagePlan Mismatch
Use:
0600000002 Returns: REFUNDED with suggested_offersUnknown Error
Use:
0600000003 Returns: UNKNOWN_ERROR statusSee the Mobile Top-Up Workflow
Guide for complete sandbox
testing instructions and examples.
Best Practices
Use Unique References
Always provide unique
ref to prevent duplicates and enable easy trackingValidate Before Submit
Check plan, phone format, and balance client-side to reduce errors
Handle Async
Process API calls asynchronously to avoid blocking user requests
Implement Retry Logic
Retry failed requests with exponential backoff for network errors
Related Endpoints
List Plans
Get available plans
Check by Reference
Track with your ref
Check by ID
Track with topup ID

