refatbd/bd-courier-fraud-checker

Check for fraudulent customers using Bangladeshi courier data.

Maintainers

Package info

github.com/refatbd/bd-courier-fraud-checker

pkg:composer/refatbd/bd-courier-fraud-checker

Transparency log

Statistics

Installs: 6

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

1.2.0 2026-06-13 20:26 UTC

This package is auto-updated.

Last update: 2026-07-13 20:40:05 UTC


README

BD Courier Fraud Checker Typing SVG

Packagist Version Downloads PHP Laravel License

Maintained with โค๏ธ by refatbd


A Laravel package that checks a Bangladeshi phone number against the data of four major couriers โ€” Steadfast, Pathao, RedX, and Carrybee โ€” and tells you, in one call, how risky that customer is before you confirm a Cash-on-Delivery order.

๐Ÿ“ž  01XXXXXXXXX  โ”€โ”€โ”€โ”€โ”€โ–ถ  ๐Ÿ”Ž  BdCourierFraudChecker  โ”€โ”€โ”€โ”€โ”€โ–ถ  ๐Ÿ“Š  Success rate ยท Fraud signals ยท Complaints

๐Ÿ“‘ Table of Contents

โœจ Features

Feature Description
๐Ÿ” One call, four couriers A single check() queries Steadfast, Pathao, RedX & Carrybee.
๐Ÿ“Š Delivery success rate Delivered / cancelled / total + auto-calculated percentages.
๐Ÿšจ Detailed complaints Steadfast returns the full complaint list โ€” name, details, date & image.
๐Ÿท๏ธ Fraud labels Pathao rating, RedX segment, Carrybee complaint count.
โšก Smart caching Auth tokens/cookies cached for ~50 min โ€” fewer logins, faster checks.
๐Ÿ›ก๏ธ Resilient In-call re-auth on expired sessions, request timeouts, browser-like headers, graceful failures, BD phone validation.
๐Ÿงฉ Extensible Drop in a new courier class and wire it up in minutes.

๐Ÿ“ฆ Installation

composer require refatbd/bd-courier-fraud-checker

Publish the config file:

php artisan vendor:publish --tag=bdcourierfraudchecker-config

โš™๏ธ Configuration

Add your courier merchant credentials to your .env file:

# ๐ŸŸฆ Steadfast
STEADFAST_USER=your_email@example.com
STEADFAST_PASSWORD=your_password

# ๐ŸŸฅ Pathao
PATHAO_USER=your_email@example.com
PATHAO_PASSWORD=your_password

# ๐ŸŸง RedX
REDX_PHONE=01XXXXXXXXX
REDX_PASSWORD=your_password

# ๐ŸŸจ Carrybee
CARRYBEE_PHONE=01XXXXXXXXX
CARRYBEE_PASSWORD=your_password

๐Ÿ’ก You only need to configure the couriers you actually use. A courier with missing credentials simply returns status => false instead of breaking the whole check.

๐Ÿš€ Usage

use Refatbd\BdCourierFraudChecker\Facade\BdCourierFraudChecker;

$result = BdCourierFraudChecker::check('01XXXXXXXXX');

That's it โ€” $result is an array keyed by courier. Loop over it, render it, or feed it into your own risk score.

๐Ÿงพ Response Format

[
    'steadfast' => [
        'status' => true,
        'message' => 'Successful.',
        'data' => [
            'success'             => 45,
            'cancel'              => 5,
            'total'               => 50,
            'deliveredPercentage' => 90.0,
            'returnPercentage'    => 10.0,
            'fraudReportCount'    => 1,
            'frauds'              => [
                [
                    'name'             => 'Saiyan Ahammd Santo',
                    'phone'            => '01893048178',
                    'details'          => 'เฆชเฆพเฆฐเงเฆธเง‡เฆฒ เฆฐเฆฟเฆธเฆฟเฆญ เฆ•เฆฐเง‡เฆจเฆพเฅค',
                    'image'            => null,
                    'consignment_id'   => 124581452,
                    'created_at'       => '2025-02-11T14:43:02.000000Z',
                    'created_at_human' => '1 year ago',
                ],
            ],
        ],
    ],
    'pathao' => [
        'status'  => true,
        'message' => 'Successful.',
        'data'    => [
            // Pathao has moved to a rating-based model โ€” most accounts no longer
            // receive numeric counts (showCount: false). See the note below.
            'success'             => null,
            'cancel'              => null,
            'total'               => null,
            'deliveredPercentage' => null,
            'returnPercentage'    => null,
            'customerRating'      => 'excellent_customer', // Pathao's own label
            'riskLevel'           => 'low',                // derived: low | medium | high
            'showCount'           => false,                // did Pathao expose counts?
            'countsAvailable'     => false,                // numeric data usable?
        ],
    ],
    'redx' => [
        'status'  => true,
        'message' => 'Successful.',
        'data'    => [
            'success'             => 30,
            'cancel'              => 5,
            'total'               => 35,
            'deliveredPercentage' => 85.71,
            'returnPercentage'    => 14.29,
            'customerSegment'     => 'Normal Customer', // RedX's own rating label
        ],
    ],
    'carrybee' => [
        'status'  => true,
        'message' => 'Successful.',
        'data'    => [
            'success'             => 18,
            'cancel'              => 2,
            'total'               => 20,
            'deliveredPercentage' => 90.0,
            'returnPercentage'    => 10.0,
            'fraudCount'          => 0, // Carrybee's own complaint counter
        ],
    ],
]

โš ๏ธ Always check status before reading data. When a courier fails (auth error, no data, etc.) it returns ['status' => false, 'message' => '...'] with no data key.

๐ŸŸฅ Pathao counts may be null. Pathao migrated to a rating-based model, so most merchant accounts receive no numeric delivery counts โ€” showCount and countsAvailable are false, and the count fields are null (not 0, to avoid implying a customer with zero orders). The package still returns the full numeric breakdown for any account that is entitled to counts (countsAvailable: true). Guard on countsAvailable before doing math on Pathao counts. Steadfast, RedX, and Carrybee continue to return real numeric counts.

๐Ÿšš Supported Couriers

Courier Status Delivery Stats Fraud Signal
Steadfast โœ… โœ… โœ… Full complaint list โ€” frauds[] (name ยท details ยท date ยท image)
Pathao โœ… โš ๏ธ Rating-basedยน ๐Ÿท๏ธ Rating + risk โ€” customerRating, riskLevel
RedX โœ… โœ… ๐Ÿท๏ธ Segment label โ€” customerSegment
Carrybee โœ… โœ… ๐Ÿ”ข Complaint count โ€” fraudCount

ยน Pathao moved to a rating-based model โ€” most accounts get no numeric counts (countsAvailable: false). Numeric counts are still returned for entitled accounts.

More couriers can be added easily โ€” see Adding a New Courier.

๐Ÿง  How the Fraud Signal Works

Each courier exposes risk differently. The package normalizes the delivery stats for all of them, and surfaces each courier's native fraud signal on top:

Courier Field Example values Meaning
Steadfast frauds[] + fraudReportCount complaint objects Real merchant-submitted complaints with text, date & image
Pathao customerRating + riskLevel excellent_customer โ†’ low, fraud_customer โ†’ high Pathao's internal rating, mapped to a coarse risk level
RedX customerSegment Normal Customer, High Return Customer RedX's internal customer tier
Carrybee fraudCount 0, 3, โ€ฆ How many complaints Carrybee holds for the number

๐Ÿ”Ž Only Steadfast returns the full who / what / when complaint text. The others give a single label or count โ€” useful as a quick red flag, but without the details.

Pathao customerRating โ†’ riskLevel mapping:

customerRating riskLevel
excellent_customer, good_customer low
regular_customer, new_customer medium
fraud_customer high
unknown / missing null

โž• Adding a New Courier

Click to expand the step-by-step guide

1. Create a new class in src/Courier/YourCourier.php:

<?php

namespace Refatbd\BdCourierFraudChecker\Courier;

use Refatbd\BdCourierFraudChecker\Traits\Helpers;

class YourCourier
{
    use Helpers;

    public function __construct()
    {
        $this->checkRequiredConfig(['your_courier_user', 'your_courier_password']);
    }

    public function check($phoneNumber)
    {
        $phoneNumber = $this->validateBDPhoneNumber($phoneNumber);
        // Add your API logic here
        return [
            'status'  => true,
            'message' => 'Successful.',
            'data'    => [],
        ];
    }
}

2. Add credentials to config/bdcourierfraudchecker.php:

"your_courier_user"     => env("YOUR_COURIER_USER", ""),
"your_courier_password" => env("YOUR_COURIER_PASSWORD", ""),

3. Inject it into CourierCheckerService and add it to the check() return array.

4. Bind it in BdCourierFraudCheckerServiceProvider.

โ“ FAQ

Do I need an account with every courier?
No. Configure only the couriers you use. Unconfigured couriers return status => false and are skipped โ€” the rest still work.
Why are Pathao's delivery counts null?
Pathao migrated the customer-success endpoint to a rating-based model. Most merchant accounts now receive show_count: false with no numeric delivery counts at all โ€” only a customer_rating. The package returns null for the count fields (and countsAvailable: false) rather than fake 0s, so you can tell "Pathao gave us no counts" apart from "a customer with zero orders". The customerRating / riskLevel is your reliable Pathao signal. If your account is entitled to numeric counts, the package returns them automatically with countsAvailable: true โ€” no code change needed. This is a Pathao server-side policy and can't be toggled from the API.
Is the data cached?
Only the auth tokens / session cookies are cached (~50 minutes) to avoid logging in on every request. The fraud lookup itself runs fresh on every call, so results are always current.
What phone formats are accepted?
Any valid Bangladeshi mobile number โ€” with or without the +88/88 prefix. The package normalizes and validates it (01[3-9]XXXXXXXX) for you.

๐Ÿ“ Changelog

See CHANGELOG.md for the full version history.

Latest โ€” v1.2.0: connection hardening across all four couriers (browser-like headers, request timeouts, in-call re-authentication on stale sessions) and Pathao's rating-based response shape (riskLevel, showCount, countsAvailable; counts are null when Pathao doesn't expose them). โš ๏ธ Guard on countsAvailable before doing math on Pathao counts.

๐Ÿ“„ License

Released under the MIT License โ€” free to use, modify, and distribute.

footer

โญ If this package saved you from a fraud order, consider starring the repo!