Check Status by ID
curl --request GET \
--url https://api.oneclickdz.com/v3/mobile/check-id/{id} \
--header 'X-Access-Token: <api-key>'import requests
url = "https://api.oneclickdz.com/v3/mobile/check-id/{id}"
headers = {"X-Access-Token": "<api-key>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {'X-Access-Token': '<api-key>'}};
fetch('https://api.oneclickdz.com/v3/mobile/check-id/{id}', 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/check-id/{id}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"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"
"net/http"
"io"
)
func main() {
url := "https://api.oneclickdz.com/v3/mobile/check-id/{id}"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("X-Access-Token", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.oneclickdz.com/v3/mobile/check-id/{id}")
.header("X-Access-Token", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.oneclickdz.com/v3/mobile/check-id/{id}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["X-Access-Token"] = '<api-key>'
response = http.request(request)
puts response.read_body{
"success": true,
"data": {
"_id": "<string>",
"ref": "<string>",
"status": "<string>",
"plan_code": "<string>",
"MSSIDN": "<string>",
"topup_amount": 123,
"balance_amount": 123,
"created_at": "<string>",
"refund_message": "<string>",
"suggested_offers": [
{
"typename": "<string>",
"plan_code": "<string>",
"amount": 123
}
],
"follow_orderid": "<string>",
"retry_orderid": "<string>"
},
"meta": {
"timestamp": "<string>"
}
}Mobile Top-Ups
Check Status by ID
Check mobile top-up status using internal top-up ID
GET
/
v3
/
mobile
/
check-id
/
{id}
Check Status by ID
curl --request GET \
--url https://api.oneclickdz.com/v3/mobile/check-id/{id} \
--header 'X-Access-Token: <api-key>'import requests
url = "https://api.oneclickdz.com/v3/mobile/check-id/{id}"
headers = {"X-Access-Token": "<api-key>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {'X-Access-Token': '<api-key>'}};
fetch('https://api.oneclickdz.com/v3/mobile/check-id/{id}', 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/check-id/{id}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"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"
"net/http"
"io"
)
func main() {
url := "https://api.oneclickdz.com/v3/mobile/check-id/{id}"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("X-Access-Token", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.oneclickdz.com/v3/mobile/check-id/{id}")
.header("X-Access-Token", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.oneclickdz.com/v3/mobile/check-id/{id}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["X-Access-Token"] = '<api-key>'
response = http.request(request)
puts response.read_body{
"success": true,
"data": {
"_id": "<string>",
"ref": "<string>",
"status": "<string>",
"plan_code": "<string>",
"MSSIDN": "<string>",
"topup_amount": 123,
"balance_amount": 123,
"created_at": "<string>",
"refund_message": "<string>",
"suggested_offers": [
{
"typename": "<string>",
"plan_code": "<string>",
"amount": 123
}
],
"follow_orderid": "<string>",
"retry_orderid": "<string>"
},
"meta": {
"timestamp": "<string>"
}
}Overview
Track mobile top-up status using thetopupId returned from the send endpoint. Generally, our servers will process your request in about 5-30 seconds.
Important: It’s mandatory to understand all possible statuses to properly handle updating and notifying your users.
Path Parameters
string
required
Internal top-up ID from
/mobile/send responseResponse
boolean
required
Indicates if the request was successful
object
required
Show properties
Show properties
string
required
Top-up identifier
string
Your custom reference (if provided)
string
required
Current status:
PENDING, HANDLING, FULFILLED, REFUNDED, or
UNKNOWN_ERRORstring
required
Plan code used
string
required
Phone number
number
required
Top-up amount in DZD
number
required
Amount deducted from your balance
string
required
Creation timestamp (ISO 8601)
string
Arabic message for end-user (only if REFUNDED or UNKNOWN_ERROR)
array
string
Follow-up order ID if order was redirected
string
Retry order ID if order was retried
Status Values
PENDING
PENDING
The
PENDING status indicates that the order has been created and is currently in the queue, awaiting processing by one of our servers. It will be processed as soon as possible.Typical duration: 2-15 secondsAction: Continue polling every 5-10 secondsHANDLING
HANDLING
The
HANDLING status indicates that the order is currently being processed by one of our servers.Typical duration: 3-8 secondsAction: Continue polling every 5-10 secondsFULFILLED
FULFILLED
The
FULFILLED status indicates that the mobile top-up has been successfully sent. ✅Action: Update order status to completed, notify userREFUNDED
REFUNDED
The
REFUNDED status indicates that the mobile top-up has been refunded. ❌Fields available:refund_message: Show this to user (in Arabic)suggested_offers: Alternative plans (if plan mismatch)
UNKNOWN_ERROR
UNKNOWN_ERROR
The Action:
UNKNOWN_ERROR status indicates that the mobile top-up might have been successful or failed. The status will update within 1 to 12 hours to either FULFILLED or REFUNDED after manual check by our support team. We will be notified immediately and no action from your part is required. ⚠️Such errors happen due to the nature of AT Commands and unexpected behaviors from operators (new messages, network issues, etc.).YOU SHOULD NOT REFUND THE AMOUNT to your user at this status!
- Show
refund_messageto user - DO NOT refund immediately
- Set a daily cronjob to check UNKNOWN_ERROR orders and update to FULFILLED or REFUNDED
- Check again after 24 hours
- Then handle refunds if status becomes REFUNDED
Examples
curl https://api.oneclickdz.com/v3/mobile/check-id/6901616fe9e88196b4eb64b0 \
-H "X-Access-Token: YOUR_API_KEY"
const topupId = "6901616fe9e88196b4eb64b0";
const response = await fetch(
`https://api.oneclickdz.com/v3/mobile/check-id/${topupId}`,
{ headers: { "X-Access-Token": "YOUR_API_KEY" } }
);
const { data } = await response.json();
console.log(data.status);
import requests
topup_id = '6901616fe9e88196b4eb64b0'
response = requests.get(
f'https://api.oneclickdz.com/v3/mobile/check-id/{topup_id}',
headers={'X-Access-Token': 'YOUR_API_KEY'}
)
status = response.json()['data']['status']
<?php
$topupId = '6901616fe9e88196b4eb64b0';
$ch = curl_init("https://api.oneclickdz.com/v3/mobile/check-id/{$topupId}");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Access-Token: YOUR_API_KEY']);
$response = json_decode(curl_exec($ch), true);
$status = $response['data']['status'];
?>
Fulfilled Response
{
"success": true,
"data": {
"_id": "6901616fe9e88196b4eb64b0",
"ref": "order-12345",
"status": "FULFILLED",
"plan_code": "PREPAID_DJEZZY",
"MSSIDN": "0778037340",
"topup_amount": 500,
"balance_amount": 490,
"created_at": "2025-10-29T00:35:59.378Z"
},
"meta": {
"timestamp": "2025-10-29T00:36:15.606Z"
},
"requestId": "req_1730160975_abc123"
}
Refunded Response
{
"success": true,
"data": {
"_id": "6901616fe9e88196b4eb64b0",
"ref": "order-12345",
"status": "REFUNDED",
"plan_code": "PREPAID_DJEZZY",
"MSSIDN": "0778037340",
"topup_amount": 500,
"balance_amount": 490,
"created_at": "2025-10-29T00:35:59.378Z",
"refund_message": "الرصيد المطلوب غير متوفر لهذا الرقم"
},
"meta": {
"timestamp": "2025-10-29T00:36:15.606Z"
},
"requestId": "req_1730160975_def456"
}
Refunded with Suggested Offers
When the plan code doesn’t match the phone number type, you’ll receive suggested alternatives:{
"success": true,
"data": {
"_id": "6901616fe9e88196b4eb64b0",
"ref": "order-12345",
"status": "REFUNDED",
"plan_code": "PREPAID_DJEZZY",
"MSSIDN": "0778037340",
"topup_amount": 500,
"balance_amount": 490,
"created_at": "2025-10-29T00:35:59.378Z",
"refund_message": "هذا العرض غير متوافق مع هذا الرقم جرب فاتورة",
"suggested_offers": [
{
"typename": "📋 FACTURE | فاتورة",
"plan_code": "FACTURE_DJEZZY",
"amount": 500
}
]
},
"meta": {
"timestamp": "2025-10-29T00:36:15.606Z"
},
"requestId": "req_1730160975_ghi789"
}
PLEASE NOTE:
suggested_offers is an array and can contain multiple items, for example when you send GETMENU plans.Polling Strategy
Syncing Our API with Your Backend
1
Start Polling
Begin checking status immediately after sending top-up. One simple approach is setting an interval of 5-10 seconds on your frontend to check the status. Once the status is FULFILLED, REFUNDED, or UNKNOWN_ERROR, clear the interval and stop sending requests.
const topupId = response.data.topupId;
const status = await pollStatus(topupId);
2
Poll Interval
Check every 5-10 seconds while PENDING or HANDLING. This approach will keep requests minimal (5-10 per transaction).On each GET request from your users, you can read the status in your database. Only if the status is not
FULFILLED, REFUNDED, or UNKNOWN_ERROR, send a check request to our API, update your database, then reply to your user.async function pollStatus(topupId, maxAttempts = 60) {
for (let i = 0; i < maxAttempts; i++) {
const { data } = await checkTopupStatus(topupId);
if (['FULFILLED', 'REFUNDED', 'UNKNOWN_ERROR'].includes(data.status)) {
return data;
}
await sleep(5000); // Wait 5 seconds
}
throw new Error('Timeout');
}
3
Handle Result
Update order based on final status
if (status === 'FULFILLED') {
await markOrderComplete(orderId);
} else if (status === 'REFUNDED') {
await refundUser(orderId);
await notifyUser(refund_message);
} else if (status === 'UNKNOWN_ERROR') {
await markForReview(orderId);
// DO NOT refund yet - wait for daily cronjob
}
Complete Polling Example
async function pollTopupStatus(topupId) {
const maxAttempts = 60; // 5 minutes max
const pollInterval = 5000; // 5 seconds
for (let i = 0; i < maxAttempts; i++) {
const response = await fetch(
`https://api.oneclickdz.com/v3/mobile/check-id/${topupId}`,
{ headers: { "X-Access-Token": process.env.API_KEY } }
);
const { data } = await response.json();
// Final states
if (["FULFILLED", "REFUNDED", "UNKNOWN_ERROR"].includes(data.status)) {
return data;
}
// Still processing
console.log(`Attempt ${i + 1}: Status is ${data.status}`);
await new Promise((resolve) => setTimeout(resolve, pollInterval));
}
throw new Error("Polling timeout after 5 minutes");
}
// Usage
try {
const result = await pollTopupStatus("6901616fe9e88196b4eb64b0");
console.log("Final status:", result.status);
} catch (error) {
console.error("Polling failed:", error.message);
}
import requests
import time
def poll_topup_status(topup_id, max_attempts=60, poll_interval=5):
"""Poll top-up status until completion or timeout"""
url = f'https://api.oneclickdz.com/v3/mobile/check-id/{topup_id}'
headers = {'X-Access-Token': 'YOUR_API_KEY'}
for attempt in range(max_attempts):
response = requests.get(url, headers=headers)
data = response.json()['data']
# Check if final state
if data['status'] in ['FULFILLED', 'REFUNDED', 'UNKNOWN_ERROR']:
return data
# Still processing
print(f"Attempt {attempt + 1}: Status is {data['status']}")
time.sleep(poll_interval)
raise TimeoutError('Polling timeout after 5 minutes')
# Usage
try:
result = poll_topup_status('6901616fe9e88196b4eb64b0')
print(f"Final status: {result['status']}")
except TimeoutError as e:
print(f"Error: {e}")
Handling UNKNOWN_ERROR
Do NOT refund immediately when status is UNKNOWN_ERROR!
UNKNOWN_ERROR status indicates uncertainty about whether the top-up succeeded or failed. This happens due to the nature of AT Commands and unexpected behaviors from operators (new messages, network issues, etc.).
1
Show Message
Display
refund_message to user explaining the delayExample message: “هذه العملية حالتها غير معروفة، يرجى التأكد مع عميلك، ولن نتحمل أي مسؤولية عن أي خسائر. إذا فشلت العملية بالفعل، فلا تقلق، سيتم استرداد أموالك خلال 24 ساعة”2
Mark for Review
Flag the order for manual review or automated recheck. We will be notified immediately and no action from your part is required.
3
Automated Recheck
Set up daily cronjob to check uncertain orders. The status will update within 1-12 hours (up to 24h) to either FULFILLED or REFUNDED after manual check by our support team.
// Daily at midnight
cron.schedule('0 0 * * *', async () => {
const uncertainOrders = await db.orders.find({
status: 'UNKNOWN_ERROR',
createdAt: { $lt: new Date(Date.now() - 24*60*60*1000) }
});
for (const order of uncertainOrders) {
const status = await checkTopupStatus(order.apiTopupId);
await updateOrderStatus(order.id, status.data.status);
// Now handle refund if status is REFUNDED
if (status.data.status === 'REFUNDED') {
await processRefund(order);
}
}
});
4
Final Resolution
Status will update to FULFILLED or REFUNDED within 24 hours. Only then should you process refunds if the final status is REFUNDED.
Best Practices
Cache Status
Store status in your database to minimize API calls. Only query our API when status is not final (PENDING/HANDLING).
Stop on Final State
Don’t poll after FULFILLED, REFUNDED, or UNKNOWN_ERROR
Timeout Protection
Set maximum polling attempts (typically 60 = 5 minutes)
Error Handling
Handle network errors with retry logic
Show Arabic Messages
Always display refund_message to users - it’s in Arabic and explains the issue
Offer Alternatives
When suggested_offers is present, update your UI to show these plans instead of all plans
Handling Refunds
Arefund_message (Arabic message) will be added to the top-up operation, and you should show it as-is to your client.
Example scenarios:
Wrong Phone Number
If your client types a wrong phone number:refund_message: "رقم الهاتف خاطئ، يرجى التأكد مع العميل"
Plan Mismatch
If trying to send PREPAID_DJEZZY to a facture (postpaid) phone number:{
"refund_message": "هذا العرض غير متوافق مع هذا الرقم جرب فاتورة",
"suggested_offers": [
{
"typename": "📋 FACTURE | فاتورة",
"plan_code": "FACTURE_DJEZZY",
"amount": 500
}
]
}
Suggested Offers Array
Thesuggested_offers array shows the correct plans for the phone number. Update your app UI to represent these new plans instead of showing all plans.
suggested_offers is an array and can contain multiple items, especially when you send GETMENU requests.Sandbox Testing
Enable the sandbox at your settings page to test requests without affecting your balance. All operations will emulate a real operation:1
Normal Flow
Any normal phone number:
- First 5 seconds: status
PENDING - First 15 seconds: status
HANDLING - Then: status
FULFILLED
2
Test Refund with Message
Phone: 0600000001Test REFUNDED status with
refund_message that should be shown to client3
Test Refund with Suggestions
Phone: 0600000002Test REFUNDED status with
refund_message and suggested_offers4
Test Unknown Error
Phone: 0600000003Test
UNKNOWN_ERROR status to ensure your daily cronjob logic works correctlyRelated Endpoints
Check by Reference
Track using your custom reference
Send Top-Up
Create a new top-up

