Skip to main content

Overview

This guide shows you exactly what to change when migrating from OneClickDz Flexy API v2 to v3. Each example shows your current v2 code, lists what to change, and shows the v3 result. Available in multiple languages: JavaScript/Node.js, PHP, and Python examples included.
API v2 Deprecation: API v2 will be deprecated on October 30, 2026. Please migrate before this date to avoid service interruption.

What’s New in v3

Standardized Responses

All responses wrapped in {(success, data, meta, requestId)} structure

Better Error Handling

Structured errors with codes, messages, and details for easier debugging

Enhanced Debugging

Every response includes timestamps and unique request IDs

Cleaner Endpoints

Logical grouping: /mobile/*, /internet/*, /gift-cards/*, /account/*

Separate API Keys

Generate dedicated sandbox keys for testing while keeping your production key

IP Whitelisting

Add IP restrictions directly from the settings page for enhanced security

Quick Migration Checklist

1

Generate Sandbox API Key (Optional)

Create a sandbox API key from your dashboard settings page for testing v3 before migrating production
2

Configure IP Whitelist (Optional)

Add IP restrictions for enhanced security directly from settings
3

Update Authentication Header

Change from authorization to X-Access-Token in all API requests
4

Update Response Handling

Access data through result.data instead of directly from the response
5

Update Error Handling

Check result.success boolean and handle structured result.error object
6

Update Endpoint Paths

Map v2 paths to new v3 paths (see complete reference table below)
7

Update Pagination Logic

Access pagination info from result.data.pagination instead of root level

Choose Your Migration Strategy

Good News: Both v2 and v3 APIs work simultaneously until v2 deprecation. Your current production API key works with both v2 and v3 endpoints, giving you flexibility in how you migrate.
Base URL Change: v3 uses a new base URL: - v2: https://flexy-api.oneclickdz.com/v2 - v3: https://api.oneclickdz.com/v3
New Security Features: v3 introduces separate sandbox API key management for testing, plus IP whitelisting directly from your dashboard settings page. Your production key continues to work with both v2 and v3.
Choose the approach that fits your needs:

🆕 Fresh Start

Best for: Complete rebuild or new projects
  • Generate sandbox key for testing from settings
  • Configure IP whitelist for production key
  • Test everything in sandbox with v3
  • Use production key when ready to go live
✅ Clean slate, no legacy code ✅ Enhanced security with IP restrictions

🔄 Gradual Migration

Best for: Existing production systems
  • Keep using current production key for v2 endpoints
  • Generate sandbox key to test v3 endpoints safely
  • Migrate endpoints one by one to v3
  • Run v2 and v3 side-by-side with same production key
✅ Zero downtime, less risk ✅ Migrate at your own pace
Recommended: Most teams choose gradual migration to minimize risk. You can update critical endpoints first while keeping others on v2.

Smart Migration: Start with Gift Cards

Pro Tip: If you’re interested in gift cards, integrate them on v3 first! You don’t need to migrate your existing mobile and internet top-ups to start using gift cards on v3. This gives you a low-risk way to test v3 while keeping your critical operations on v2. Use your sandbox key to test, then switch to production when ready.
Suggested Migration Order:
  1. Phase 1: Integrate gift cards on v3 (if applicable)
    • Generate sandbox key for testing
    • Use /v3/gift-cards/* endpoints in sandbox
    • Test thoroughly, then use production key
    • Keep mobile/internet on v2
  2. Phase 2: Migrate account & validation endpoints
    • /v3/validate
    • /v3/account/balance
    • /v3/account/transactions
  3. Phase 3: Migrate mobile top-ups gradually
    • Test with low-volume operations first
    • Monitor for issues
    • Scale up migration
  4. Phase 4: Migrate internet top-ups
    • Complete before deprecation deadline
This approach lets you migrate at your own pace until the deprecation date while taking advantage of new v3 features.

The 3 Main Changes

1. Authentication Header

What to change: Rename the header from authorization to X-Access-Token
New Key Management: v3 allows you to generate a separate sandbox API key for testing from your dashboard settings. You can also add IP whitelist restrictions for enhanced security. Your existing production API key works with both v2 and v3 endpoints.
  • JavaScript
  • PHP
  • Python
// Your current v2 code:
fetch("https://flexy-api.oneclickdz.com/v2/plans/listAll", {
  headers: {
    authorization: "YOUR_API_KEY",
  },
});
Changes needed:
  • ❌ Remove: authorization: "YOUR_API_KEY"
  • ✅ Add: X-Access-Token: "YOUR_API_KEY"
  • ✅ Update: Base URL to https://api.oneclickdz.com/v3
The authentication mechanism remains the same - only the header name changes. Your existing API key works with both v2 and v3.
  • JavaScript
  • PHP
  • Python
// Updated v3 code:
fetch("https://api.oneclickdz.com/v3/mobile/plans", {
  headers: {
    "X-Access-Token": "YOUR_API_KEY",
  },
});

2. Response Structure

What to change: All responses are now wrapped in a standard structure
  • JavaScript
  • PHP
  • Python
// Your current v2 code:
const response = await fetch("https://flexy-api.oneclickdz.com/v2/account/balance", {
  headers: { authorization: API_KEY },
});
const data = await response.json();
console.log("Balance:", data.balance); // Direct access
Changes needed:
  • ❌ Remove: Direct access to data.balance
  • ✅ Add: Check result.success first
  • ✅ Add: Access through result.data.balance
  • ✅ Bonus: Use result.requestId for debugging
  • ✅ Bonus: Use result.meta.timestamp for timing info
Breaking Change: In v3, you must always check the success boolean before accessing data. Direct field access will cause errors if the request failed.
  • JavaScript
  • PHP
  • Python
// Updated v3 code:
const response = await fetch("https://api.oneclickdz.com/v3/account/balance", {
  headers: { "X-Access-Token": API_KEY },
});
const result = await response.json();

if (result.success) {
console.log("Balance:", result.data.balance);
console.log("Request ID:", result.requestId); // For debugging
console.log("Timestamp:", result.meta.timestamp); // Response time
} else {
console.error("Error:", result.error.message);
}


3. Error Handling

What to change: Errors are now structured objects with codes
  • JavaScript
  • PHP
  • Python
// Your current v2 code:
const response = await fetch("https://flexy-api.oneclickdz.com/v2/topup/sendTopup", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    authorization: API_KEY,
  },
  body: JSON.stringify(data),
});

const result = await response.json();
if (result.error) {
  console.error("Error:", result.message); // Simple string
}
Changes needed:
  • ❌ Remove: Checking result.error string
  • ✅ Add: Check result.success === false
  • ✅ Add: Access result.error.code and result.error.message
  • ✅ Add: Handle different error codes with switch/if statements
  • ✅ Add: Log result.requestId for support tickets
Pro Tip: Always save the requestId when logging errors. Our support team needs this to trace issues in our system.
  • JavaScript
  • PHP
  • Python
// Updated v3 code:
const response = await fetch("https://api.oneclickdz.com/v3/mobile/send", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "X-Access-Token": API_KEY,
  },
  body: JSON.stringify(data),
});

const result = await response.json();

if (!result.success) {
console.error(`Error [${result.error.code}]: ${result.error.message}`);
console.log("Request ID:", result.requestId);

// Handle specific errors
switch (result.error.code) {
case "INSUFFICIENT_BALANCE":
alert("Please top up your account");
break;
case "ERR_PHONE":
alert(`Invalid phone number: ${result.error.message}`);
if (result.error.details?.pattern) {
console.log("Expected format:", result.error.details.pattern);
}
break;
case "DUPLICATED_REF":
alert("This order reference was already used");
break;
default:
alert("An error occurred. Please try again.");
}
}


Step-by-Step Migration Examples

Example 1: Get Mobile Plans

Step 1 - Your current v2 code:
  • JavaScript
  • PHP
  • Python
const response = await fetch("https://flexy-api.oneclickdz.com/v2/plans/listAll", {
  headers: {
    authorization: API_KEY,
  },
});

const data = await response.json();
const dynamicPlans = data.dymanicPlans; // Note: typo in v2
const fixedPlans = data.fixedPlans;
Step 2 - What to change:
  1. Change base URL: https://flexy-api.oneclickdz.comhttps://api.oneclickdz.com
  2. Change endpoint: /v2/plans/listAll/v3/mobile/plans
  3. Change header: authorizationX-Access-Token
  4. Add success check: if (result.success)
  5. Access through data: data.dymanicPlansresult.data.dynamicPlans (typo fixed!)
MUST Fix: v3 fixes the typo in “dymanicPlans” to “dynamicPlans”. Update your code to use the correct spelling.
Step 3 - Your new v3 code:
  • JavaScript
  • PHP
  • Python
const response = await fetch("https://api.oneclickdz.com/v3/mobile/plans", {
  headers: {
    "X-Access-Token": API_KEY,
  },
});

const result = await response.json();
if (result.success) {
const dynamicPlans = result.data.dynamicPlans; // Typo fixed!
const fixedPlans = result.data.fixedPlans;
}


Example 2: Send Mobile Top-Up

Step 1 - Your current v2 code:
  • JavaScript
  • PHP
  • Python
const response = await fetch("https://flexy-api.oneclickdz.com/v2/topup/sendTopup", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    authorization: API_KEY,
  },
  body: JSON.stringify({
    plan_code: "PREPAID_DJEZZY",
    MSSIDN: "0778037340",
    amount: 500,
    ref: "order-123",
  }),
});

const data = await response.json();
console.log("Topup ID:", data.topupId);
console.log("New Balance:", data.newBalance);
Step 2 - What to change:
  1. Change base URL: https://flexy-api.oneclickdz.comhttps://api.oneclickdz.com
  2. Change endpoint: /v2/topup/sendTopup/v3/mobile/send
  3. Change header: authorizationX-Access-Token
  4. Add success check: if (result.success)
  5. Access through data: data.topupIdresult.data.topupId
  6. Add comprehensive error handling
Important: Always handle errors when sending top-ups. Network issues, insufficient balance, or invalid data can cause failures. Save the requestId for tracking.
Step 3 - Your new v3 code:
  • JavaScript
  • PHP
  • Python
const response = await fetch("https://api.oneclickdz.com/v3/mobile/send", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "X-Access-Token": API_KEY,
  },
  body: JSON.stringify({
    plan_code: "PREPAID_DJEZZY",
    MSSIDN: "0778037340",
    amount: 500,
    ref: "order-123",
  }),
});

const result = await response.json();
if (result.success) {
console.log("✅ Top-up sent successfully!");
console.log("Topup ID:", result.data.topupId);
console.log("New Balance:", result.data.newBalance);
console.log("Request ID:", result.requestId);
} else {
console.error(`❌ Error [${result.error.code}]: ${result.error.message}`);
console.error("Request ID:", result.requestId);
}


Example 3: Check Top-Up Status

Step 1 - Your current v2 code:
  • JavaScript
  • PHP
  • Python
const response = await fetch(
  "https://flexy-api.oneclickdz.com/v2/topup/checkStatus/REF/order-123",
  {
    headers: { authorization: API_KEY },
  }
);

const data = await response.json();
console.log("Status:", data.topup.status);
console.log("Phone:", data.topup.MSSIDN);
Step 2 - What to change:
  1. Change base URL: https://flexy-api.oneclickdz.comhttps://api.oneclickdz.com
  2. Change endpoint: /v2/topup/checkStatus/REF/:ref/v3/mobile/check-ref/:ref
  3. Change header: authorizationX-Access-Token
  4. Add success check: if (result.success)
  5. Access directly: data.topup.statusresult.data.status (no more nested topup object)
  6. Handle new refund information fields
New Feature: v3 includes detailed refund information with suggested alternative offers when a top-up is refunded.
Step 3 - Your new v3 code:
  • JavaScript
  • PHP
  • Python
const response = await fetch(
  "https://api.oneclickdz.com/v3/mobile/check-ref/order-123",
  {
    headers: { "X-Access-Token": API_KEY },
  }
);

const result = await response.json();
if (result.success) {
console.log("Status:", result.data.status);
console.log("Phone:", result.data.MSSIDN);

// New in v3: Enhanced refund information
if (result.data.status === "REFUNDED") {
console.log("❌ Top-up was refunded");
console.log("Reason:", result.data.refund_message);
if (result.data.suggested_offers) {
console.log("💡 Try these offers instead:");
console.log(result.data.suggested_offers);
}
} else if (result.data.status === "FULFILLED") {
console.log("✅ Top-up completed successfully");
}
}


Example 4: List Transactions with Pagination

Step 1 - Your current v2 code:
  • JavaScript
  • PHP
  • Python
const response = await fetch(
  "https://flexy-api.oneclickdz.com/v2/account/transactions?page=1&pageSize=20",
  {
    headers: { authorization: API_KEY },
  }
);

const data = await response.json();
console.log("Transactions:", data.transactions);
console.log("Total:", data.totalResults);
console.log("Page:", data.currentPage);
console.log("Pages:", data.totalPages);
Step 2 - What to change:
  1. Change base URL: https://flexy-api.oneclickdz.comhttps://api.oneclickdz.com
  2. Change version: /v2/account/transactions/v3/account/transactions
  3. Change header: authorizationX-Access-Token
  4. Add success check: if (result.success)
  5. Access items: data.transactionsresult.data.items
  6. Access pagination: Root level fields → result.data.pagination object
Breaking Change: Pagination structure has moved from root level to data.pagination. Update all list/pagination logic.
Step 3 - Your new v3 code:
  • JavaScript
  • PHP
  • Python
const response = await fetch(
  "https://api.oneclickdz.com/v3/account/transactions?page=1&pageSize=20",
  {
    headers: { "X-Access-Token": API_KEY },
  }
);

const result = await response.json();
if (result.success) {
console.log("Transactions:", result.data.items);
console.log("Total:", result.data.pagination.totalResults);
console.log("Page:", result.data.pagination.page);
console.log("Pages:", result.data.pagination.totalPages);
console.log("Page Size:", result.data.pagination.pageSize);
}


Example 5: Check Internet Products

Step 1 - Your current v2 code:
  • JavaScript
  • PHP
  • Python
const response = await fetch(
  "https://flexy-api.oneclickdz.com/v2/internet/checkCards/ADSL",
  {
    headers: { authorization: API_KEY },
  }
);

const cards = await response.json(); // Direct array
cards.forEach((card) => {
  console.log(`${card.value} DA - Available: ${card.available}`);
});
Step 2 - What to change:
  1. Change base URL: https://flexy-api.oneclickdz.comhttps://api.oneclickdz.com
  2. Change endpoint: /v2/internet/checkCards/:type/v3/internet/products?type=:type
  3. Change from path param to query param: /ADSL?type=ADSL
  4. Change header: authorizationX-Access-Token
  5. Add success check: if (result.success)
  6. Access array: Direct array → result.data.products
API Design: v3 uses query parameters instead of path parameters for type selection, making it easier to add filters in the future.
Step 3 - Your new v3 code:
  • JavaScript
  • PHP
  • Python
const response = await fetch(
  "https://api.oneclickdz.com/v3/internet/products?type=ADSL",
  {
    headers: { "X-Access-Token": API_KEY },
  }
);

const result = await response.json();
if (result.success) {
result.data.products.forEach((card) => {
console.log(`${card.value} DA - Available: ${card.available}`);
});
}


Migrate Your API Client

Here’s how to update your API client wrapper: Step 1 - Your current v2 client:
  • JavaScript
  • PHP
  • Python
class FlexyAPI {
  constructor(apiKey) {
    this.apiKey = apiKey;
    this.baseUrl = "https://flexy-api.oneclickdz.com";
  }

  async request(endpoint, options = {}) {
    const response = await fetch(`${this.baseUrl}${endpoint}`, {
      ...options,
      headers: {
        ...options.headers,
        authorization: this.apiKey,
      },
    });
    return response.json();
  }

  async getBalance() {
    const data = await this.request("/v2/account/balance");
    return data.balance;
  }

  async sendTopup(params) {
    return await this.request("/v2/topup/sendTopup", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(params),
    });
  }
}
Step 2 - What to change:
  1. Change base URL: https://flexy-api.oneclickdz.comhttps://api.oneclickdz.com
  2. Change header: authorizationX-Access-Token
  3. Add response wrapper handling in request() method
  4. Check result.success and handle errors
  5. Update all endpoint paths to v3
  6. Throw structured errors with codes and request IDs
Best Practice: Centralize error handling in your API client. This makes it easier to add logging, monitoring, and user notifications.
Step 3 - Your new v3 client:
  • JavaScript
  • PHP
  • Python
class FlexyAPI {
  constructor(apiKey) {
    this.apiKey = apiKey;
    this.baseUrl = "https://api.oneclickdz.com";
  }

async request(endpoint, options = {}) {
const response = await fetch(`${this.baseUrl}${endpoint}`, {
...options,
headers: {
...options.headers,
"X-Access-Token": this.apiKey, // Changed header name
},
});

    const result = await response.json();

    // Handle v3 response wrapper
    if (!result.success) {
      const error = new Error(result.error.message);
      error.code = result.error.code;
      error.details = result.error.details;
      error.requestId = result.requestId;
      throw error;
    }

    return result.data; // Return unwrapped data

}

async getBalance() {
const data = await this.request("/v3/account/balance"); // Updated path
return data.balance;
}

async sendTopup(params) {
return await this.request("/v3/mobile/send", { // Updated path
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(params),
});
}
}


Complete Endpoint Reference

Servicev2 Endpointv3 EndpointNotes
Authentication
Headerauthorization: KEYX-Access-Token: KEYHeader name changed
ValidateGET /v2/validateGET /v3/validateResponse wrapped
Mobile
List PlansGET /v2/plans/listAllGET /v3/mobile/plansPath changed, typo fixed
Send Top-UpPOST /v2/topup/sendTopupPOST /v3/mobile/sendPath simplified
Check by RefGET /v2/topup/checkStatus/REF/:refGET /v3/mobile/check-ref/:refPath simplified, refund info added
Check by IDGET /v2/topup/checkStatus/ID/:idGET /v3/mobile/check-id/:idPath simplified
List Top-UpsGET /v2/topup/listGET /v3/mobile/listPagination moved to data.pagination
Internet
ProductsGET /v2/internet/checkCards/:typeGET /v3/internet/products?type=Path param → query param
Check NumberGET /v2/internet/checkNumber/:t/:nGET /v3/internet/check-number?type=&number=Path params → query params
SendPOST /v2/internet/sendTopupPOST /v3/internet/sendPath simplified
Check by RefGET /v2/internet/checkStatus/REF/:refGET /v3/internet/check-ref/:refPath simplified
Check by IDGET /v2/internet/checkStatus/ID/:idGET /v3/internet/check-id/:idPath simplified
ListGET /v2/internet/listGET /v3/internet/listPagination moved
Gift Cards
CatalogGET /v2/gift-cards/catalogueGET /v3/gift-cards/catalogSpelling fixed
Check ProductGET /v2/gift-cards/checkProduct/:idGET /v3/gift-cards/checkProduct/:idResponse wrapped
Place OrderPOST /v2/gift-cards/placeOrderPOST /v3/gift-cards/placeOrderResponse wrapped
Check OrderGET /v2/gift-cards/checkOrder/:idGET /v3/gift-cards/checkOrder/:idResponse wrapped
List OrdersGET /v2/gift-cards/listGET /v3/gift-cards/listPagination moved
Account
BalanceGET /v2/account/balanceGET /v3/account/balanceResponse wrapped
TransactionsGET /v2/account/transactionsGET /v3/account/transactionsPagination moved

Error Code Reference

Common v2 errors and their v3 equivalents:
v2 Errorv3 Error CodeWhat Changed
"NO-BALANCE"INSUFFICIENT_BALANCENow a code with structured message
"DUPLICATED-REF"DUPLICATED_REFSame code, now with details object
"ERR_VALIDATION"ERR_VALIDATIONIncludes details.field and `details.pattern
"ERR_PHONE"ERR_PHONEIncludes validation pattern in details
"ERR_STOCK"ERR_STOCKProduct availability information
"Forbidden"ERR_AUTHMore descriptive, unified auth errors
"Access token missing"ERR_AUTHSame code for all auth errors
"NOT_FOUND"NOT_FOUNDResource not found (order, product, etc.)
How to handle v3 errors:
  • JavaScript
  • PHP
  • Python
// v2 way:
if (result.error === "NO-BALANCE") {
  // handle
}

// v3 way:
if (!result.success && result.error.code === "INSUFFICIENT_BALANCE") {
  console.log("Request ID:", result.requestId); // Save for support
  // handle with more context
  if (result.error.details?.currentBalance) {
    console.log("Current balance:", result.error.details.currentBalance);
  }
}

Critical Deadline: After October 30, 2026, all v2 API requests will fail. Plan your migration accordingly to avoid service disruption.

Common Migration Issues & Solutions

Problem: Changed endpoint but forgot to update header name.Solution: Replace authorization with X-Access-Token in ALL requests.
// ❌ Wrong
headers: { authorization: API_KEY }

// ✅ Correct
headers: { "X-Access-Token": API_KEY }
Problem: Trying to access data directly instead of through result.data. Solution: Always access response data through the data property.
❌ Wrong const balance = result.balance; ✅ Correct const
balance = result.data.balance; ```
</Accordion>

{" "}

<Accordion title="Issue: Pagination Not Working" icon="circle-exclamation">
**Problem**: Looking for pagination fields at root level. **Solution**: Access
pagination through `data.pagination`. ```javascript // ❌ Wrong const total =
result.totalResults; const page = result.currentPage; // ✅ Correct const
total = result.data.pagination.totalResults; const page =
result.data.pagination.page; ```
</Accordion>

<Accordion title="Issue: Error Handling Not Working" icon="circle-exclamation">
  **Problem**: Checking for old error format.
  
  **Solution**: Check `success` boolean and access structured error object.
  
  ```javascript
  // ❌ Wrong
  if (result.error) {
    console.log(result.message);
  }
  
  // ✅ Correct
  if (!result.success) {
    console.log(result.error.code, result.error.message);
    console.log("Request ID:", result.requestId);
  }
Problem: Using old v2 endpoint paths.Solution: Update all paths according to the reference table above.
// ❌ Wrong
POST /v2/topup/sendTopup
GET /v2/internet/checkCards/ADSL

// ✅ Correct
POST /v3/mobile/send
GET /v3/internet/products?type=ADSL

Testing Checklist

Before deploying to production, verify:
  • All authentication headers changed to X-Access-Token
  • All endpoint paths updated to v3
  • Success/error checking implemented everywhere
  • Data accessed through result.data
  • Pagination accessed through result.data.pagination
  • Error codes handled with result.error.code
  • Request IDs logged for debugging
  • Tested in sandbox mode first
  • All existing functionality still works
  • Error scenarios tested (insufficient balance, invalid data, etc.)

Need Help?

API v3 Documentation

Complete v3 API reference and examples

Error Handling Guide

Best practices for error handling

Dashboard Settings

Access: Login to your dashboardGenerate Sandbox Key: Create a sandbox key for safe testingIP Whitelist: Add IP restrictions for enhanced security

Support

Email: [email protected]Important: Always include your request ID when reporting issues
Migration Support: Our team is here to help! Email us with “API v3 Migration Support” in the subject line, and include: - Your current implementation details - Specific errors (with request IDs) - Code samples showing the issue