Skip to main content

redx_courier 0.0.1 copy "redx_courier: ^0.0.1" to clipboard
redx_courier: ^0.0.1 copied to clipboard

A Dart/Flutter client for the RedX (redx.com.bd) courier OpenAPI: create parcels, resolve delivery areas from a free-text address, and list your pickup stores (including the shop-ID vs pickup-store-ID [...]

redx_courier #

A Dart/Flutter client for the RedX courier OpenAPI (https://openapi.redx.com.bd/v1.0.0-beta): create parcels, resolve a delivery area from a free-text customer address, and list your pickup stores.

Companion package to paperfly_courier.

Install #

dependencies:
  redx_courier: ^0.0.1

Getting your access token #

Log in to your RedX merchant dashboard and grab your API access token from the Developer/API section. It's sent on every request as:

API-ACCESS-TOKEN: Bearer <your token>

Finding your pickup store ID (read this first) #

This is the single most common integration mistake with RedX, and it's why this package puts it front and center.

RedX has two different IDs that look interchangeable but aren't:

  • Your shop ID - the number in your merchant dashboard URL, and also the shop_id field baked into your access token's own JWT payload.
  • Your pickup store ID - a separate ID for each physical pickup location registered under your shop, used for the pickup_store_id field when creating a parcel.

It's natural to assume they're the same thing, or to grab the shop ID out of your JWT and use that as pickup_store_id - RedX's own docs don't call this out. If you do, createParcel() will fail with:

{"message": "Cannot read property 'PHONE' of undefined"}

That error is RedX's backend trying to read a phone number off a pickup store that doesn't exist under the ID you sent (because it was actually your shop ID). Same symptom no matter what else you change in the request - a different cash_collection_amount, phone formatting, or the type field will not fix it.

The fix: always look up your real pickup store ID at runtime instead of hardcoding a number you found in a URL or a JWT:

final client = RedxClient(accessToken: 'YOUR_REDX_ACCESS_TOKEN');

final stores = await client.getPickupStores();
for (final store in stores) {
  print('${store.name} -> id: ${store.id}, phone: ${store.phone}');
}

final pickupStoreId = stores.first.id; // use this, not your shop ID

You can also sanity-check a specific ID with getPickupStoreInfo() - it returns null (instead of throwing) when the ID you passed turns out to be a shop ID rather than a pickup store ID:

final store = await client.getPickupStoreInfo(1040634);
if (store == null) {
  print('That ID is not a pickup store - probably your shop ID instead.');
}

Usage #

import 'package:redx_courier/redx_courier.dart';

Future<void> main() async {
  final client = RedxClient(accessToken: 'YOUR_REDX_ACCESS_TOKEN');

  final stores = await client.getPickupStores();
  final pickupStoreId = stores.first.id;

  // Resolves a free-text address to the right RedX delivery area, e.g.
  // matching "House 5, Road 12, Gulshan 2" to an area named "Gulshan-2".
  final area = await client.resolveAreaForAddress(
    districtName: 'Dhaka',
    customerAddress: 'House 5, Road 12, Gulshan 2, Dhaka',
  );

  if (area == null) {
    // No confident match - fall back to client.getAreasByDistrict('Dhaka')
    // and let the customer pick their area explicitly.
    return;
  }

  final result = await client.createParcel(
    RedxParcelRequest(
      customerName: 'Test Customer',
      customerPhone: normalizeBdPhoneForRedx('+8801712345678') ?? '',
      customerAddress: 'House 5, Road 12, Gulshan 2, Dhaka',
      areaId: area.id,
      areaName: area.name,
      merchantInvoiceId: 'INV-0001',
      cashCollectionAmount: 500, // 0 for a prepaid order
      parcelWeight: 1,
      value: 500,
      itemName: 'Sample Item',
      pickupStoreId: pickupStoreId,
    ),
  );

  print('success: ${result.success}, tracking: ${result.trackingId}');

  client.close();
}

See example/example.dart for the full runnable version.

API #

  • RedxClient.getPickupStores() - list pickup stores under your shop.
  • RedxClient.getPickupStoreInfo(int pickupStoreId) - look up one store; null if the ID isn't a real pickup store.
  • RedxClient.getAreasByDistrict(String districtName) - raw area lookup, with automatic retry under known alternate district spellings (Barisal/ Barishal, Bogra/Bogura, Chattogram/Chittagong, Comilla/Cumilla, Jashore/ Jessore).
  • RedxClient.resolveAreaForAddress(...) - best-match area for a district
    • free-text address; null if nothing matches confidently.
  • RedxClient.createParcel(RedxParcelRequest request) - create a parcel.
  • RedxClient.trackParcel(String trackingId) - track a parcel.
  • normalizeBdPhoneForRedx(String? phone) - normalizes a phone number to the local 01XXXXXXXXX format RedX expects (a +880/880-prefixed number sent as-is has also been observed to trigger the same "Cannot read property 'PHONE' of undefined" crash as the wrong pickup store ID, so normalize phone numbers too).

License #

MIT, see LICENSE.

1
likes
150
points
218
downloads

Documentation

API reference

Publisher

verified publishercarboncodes.net

Weekly Downloads

A Dart/Flutter client for the RedX (redx.com.bd) courier OpenAPI: create parcels, resolve delivery areas from a free-text address, and list your pickup stores (including the shop-ID vs pickup-store-ID distinction that trips up most first integrations).

Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

http

More

Packages that depend on redx_courier