API Reference
The FraudDetect API checks a customer's COD delivery history across all five major Bangladeshi couriers — Steadfast, Pathao, RedX, Paperfly, and Carrybee — and returns an aggregated success/cancel score in a single HTTP request. Use it to flag risky orders before dispatch.
Base URL
connect.chowdhury.bd
Protocol
HTTPS only
Format
JSON
What a single API call gives you
Quick Start
From zero to your first fraud check in under five minutes.
Create a free account
Register at frauddetect.chowdhury.bd/register. No credit card required.
Generate an API key
Go to your Dashboard, click New API Key, give it a name, and copy the key. Store it securely — it is shown only once.
Make your first request
Replace YOUR_API_KEY and send the request below. You'll get live courier data back immediately.
curl -X POST https://connect.chowdhury.bd/api/v1/check \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"phone":"01711223344"}'Expected response
A 200 OK with a JSON body containing per-courier stats and an aggregate object. See Response Schema for the full field reference.
Authentication
Every request must include your API key in the X-Api-Key request header. There is no OAuth or session-based authentication — the key itself is the credential.
curl -X POST https://connect.chowdhury.bd/api/v1/check \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"phone":"01711223344"}'Security tips
- Never embed keys in client-side JavaScript
- Store keys in environment variables, not config files
- Rotate keys immediately if compromised
- Use separate keys per environment (dev/staging/prod)
Key management
- Create unlimited keys from the dashboard
- Keys can be revoked instantly — no downtime
- Label each key for easy identification
- All keys share the same rate limit quota
Endpoint Reference
The API currently exposes a single endpoint. All requests go to the base URLhttps://connect.chowdhury.bd/api.
/v1/checkCheck phone fraud risk. Accepts a Bangladeshi mobile number and returns delivery history from all five supported couriers along with an aggregated risk score. Courier data is cached — typical response time is under 500ms.
Request Schema
The request body must be JSON with Content-Type: application/json.
| Field | Type | Required | Description |
|---|---|---|---|
phone | string | Yes | Bangladeshi mobile number in local 11-digit format. Must start with 01. Do not include country code (+88 or 88). |
# Minimal
curl -X POST https://connect.chowdhury.bd/api/v1/check \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"phone":"01711223344"}'Response Schema
A successful 200 OK response contains a top-level object with one key per courier and an aggregate summary. Couriers with no data for the phone number return zero counts — they are never omitted from the response.
{
"steadfast": {
"success": 3,
"cancel": 1,
"total": 4
},
"pathao": {
"success": 5,
"cancel": 2,
"total": 7
},
"redx": {
"success": 20,
"cancel": 5,
"total": 25
},
"paperfly": {
"success": 0,
"cancel": 0,
"total": 1
},
"carrybee": {
"success": 10,
"cancel": 0,
"total": 10,
"fraud_count": 0
},
"aggregate": {
"total_success": 38,
"total_cancel": 8,
"total_deliveries": 47,
"success_ratio": 80.85,
"cancel_ratio": 17.02,
"verdict": {
"level": "good",
"title": "Looks Good",
"subtitle": "80.85% success across 47 orders. Good track record for COD."
}
}
}Courier object
Each of the five courier keys (steadfast, pathao, redx, paperfly, carrybee) contains the same structure:
| Field | Type | Required | Description |
|---|---|---|---|
success | integer | No | Number of successfully delivered orders via this courier for the phone number. |
cancel | integer | No | Number of cancelled or returned orders via this courier. |
total | integer | No | Total orders recorded. Equals success + cancel + any pending orders. |
Aggregate object
The aggregate key summarises data across all five couriers:
| Field | Type | Required | Description |
|---|---|---|---|
total_success | integer | No | Sum of successful deliveries across all couriers. |
total_cancel | integer | No | Sum of cancelled or returned orders across all couriers. |
total_deliveries | integer | No | Sum of all resolved deliveries (success + cancel) across all couriers. |
success_ratio | float | No | Percentage of orders successfully delivered: (total_success / total_deliveries) × 100. Rounded to 2 decimal places. Returns 0 if no history. |
cancel_ratio | float | No | Percentage of orders cancelled or returned. success_ratio + cancel_ratio may not equal 100 if pending orders exist. |
verdict | object | No | COD safety verdict computed from all courier signals. See Verdict object below. |
Verdict object
Returned inside aggregate.verdict. Combines delivery history, Pathao rating, and Carrybee fraud reports into a single COD recommendation.
| Field | Type | Required | Description |
|---|---|---|---|
level | string | No | Machine-readable risk level. One of: trusted, reliable, good, caution, risky, unknown. |
title | string | No | Short human-readable verdict label, e.g. "Trusted Customer — COD Safe" or "High Risk — Avoid COD". |
subtitle | string | No | One-sentence explanation of the verdict with the key signals that drove it. |
| Level | Meaning | Typical condition |
|---|---|---|
| trusted | Trusted Customer — COD Safe | ≥3 orders, ≥90% success or Pathao excellent/safe, no fraud reports |
| reliable | Reliable Customer | ≥3 orders, 70–89% success, no fraud reports |
| good | Looks Good | 1–2 orders with ≥70% success, or limited but clean history |
| caution | Proceed with Caution | ≥2 orders with 40–69% success rate |
| risky | High Risk — Avoid COD | Fraud reports, Pathao risky flag, or <40% success on ≥2 orders |
| unknown | No History Found | Zero orders and no Pathao data available |
Notes on the data
- A phone with no history returns zeros in all fields. This is normal — it does not mean the customer is fraudulent.
- total_deliveries counts only resolved orders (success + cancel). In-transit orders are excluded.
- Data freshness depends on each courier's API caching — typically within 1–6 hours of the last order update.
- success_ratio + cancel_ratio can be less than 100 if some orders are still in pending/transit state.
Code Examples
Production-ready examples in all major languages. Each snippet reads the API key from an environment variable (FRAUDDETECT_API_KEY), handles errors, and prints the fraud score.
Basic check
curl -X POST https://connect.chowdhury.bd/api/v1/check \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"phone":"01711223344"}'Retry on rate limit (429)
If you exceed 30 requests/minute the API returns 429 Too Many Requests. These examples implement exponential back-off.
#!/bin/bash
# Retry with exponential back-off on 429
MAX_RETRIES=3
DELAY=1
for i in $(seq 1 $MAX_RETRIES); do
STATUS=$(curl -s -o /tmp/fd_resp.json -w "%{http_code}" \
-X POST https://connect.chowdhury.bd/api/v1/check \
-H "X-Api-Key: $FRAUDDETECT_API_KEY" \
-H "Content-Type: application/json" \
-d '{"phone":"01711223344"}')
if [ "$STATUS" -eq 200 ]; then
cat /tmp/fd_resp.json
exit 0
elif [ "$STATUS" -eq 429 ]; then
echo "Rate limited, waiting ${DELAY}s..."
sleep $DELAY
DELAY=$((DELAY * 2))
else
echo "Error: HTTP $STATUS"
cat /tmp/fd_resp.json
exit 1
fi
done
echo "Exceeded retry limit"
exit 1Score Interpretation
success_ratio is the single most useful field for deciding whether to fulfil a COD order. It represents what percentage of this customer's past orders across all five couriers were successfully delivered.
Suggested thresholds
Low risk — fulfil
Strong delivery track record. Safe to ship COD without extra checks.
Medium risk — review
Consider requiring partial prepayment or calling to confirm. History exists but cancel rate is notable.
High risk — caution
Majority of past orders cancelled. Strongly consider prepayment or declining the COD order.
New customer
No delivery history found across any courier. Apply your standard new-customer policy.
Using cancel_ratio as a secondary signal
If total_deliveries is low (e.g. 1–3 orders), a high cancel_ratio may not be statistically significant — a single bad order skews a thin history. Use both fields together:
const { aggregate } = result;
function getRiskLevel(aggregate) {
const { total_deliveries, success_ratio, cancel_ratio } = aggregate;
if (total_deliveries === 0) return 'new_customer'; // no history
// Low sample size — be less aggressive
if (total_deliveries < 3) {
return cancel_ratio > 66 ? 'high_risk' : 'low_sample';
}
if (success_ratio >= 80) return 'safe';
if (success_ratio >= 50) return 'medium_risk';
return 'high_risk';
}
console.log(getRiskLevel(aggregate)); // 'safe' | 'medium_risk' | 'high_risk' | ...Phone Number Format
The phone field must be an 11-digit Bangladeshi mobile number in local format — no country code prefix.
01711223344Grameenphone01876543210Banglalink01511223344Teletalk01611223344Robi01911223344Airtel+8801711223344Remove +88 prefix8801711223344Remove 88 prefix1711223344Missing leading 0017112233Too short (9 digits)017112233444Too long (12 digits)Normalize user input before sending:
function normalizePhone(input) {
let phone = input.trim().replace(/\s+/g, '');
if (phone.startsWith('+88')) phone = phone.slice(3);
if (phone.startsWith('88') && phone.length === 13) phone = phone.slice(2);
if (!/^01[0-9]{9}$/.test(phone)) throw new Error('Invalid phone number');
return phone;
}
normalizePhone('+8801711223344'); // '01711223344'
normalizePhone('01711223344'); // '01711223344'Rate Limits
Each API key is rate-limited to protect the service and ensure fair usage.
Limit
30 req / min
Per API key, rolling window
Response
429
Too Many Requests
Strategy
Exponential
Back-off on retry
Need more throughput?
Create multiple API keys — one per environment or service — to multiply your effective limit. Or contact us for an Enterprise plan with higher limits.
Handle 429 with exponential back-off:
async function checkPhoneWithRetry(phone, maxRetries = 3) {
let delay = 1000; // 1 second
for (let attempt = 1; attempt <= maxRetries; attempt++) {
const res = await fetch('https://connect.chowdhury.bd/api/v1/check', {
method: 'POST',
headers: {
'X-Api-Key': process.env.FRAUDDETECT_API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({ phone }),
});
if (res.ok) return res.json();
if (res.status === 429 && attempt < maxRetries) {
console.warn(`Rate limited — retrying in ${delay}ms (attempt ${attempt})`);
await new Promise(r => setTimeout(r, delay));
delay *= 2; // exponential back-off
continue;
}
const err = await res.json().catch(() => ({}));
throw new Error(`API error ${res.status}: ${err.message ?? 'unknown'}`);
}
throw new Error('Exceeded maximum retries');
}Error Reference
All errors return a JSON body with a message field. HTTP status codes follow standard semantics.
{
"message": "Unauthenticated."
}
# or for validation errors:
{
"message": "The phone field is required.",
"errors": {
"phone": ["The phone field is required."]
}
}200OK
Request succeeded.
Parse the response body — data is ready.
401Unauthorized
The X-Api-Key header is missing, empty, or the key does not exist.
Verify the key is included in every request. Check for typos. Regenerate from the dashboard if needed.
422Unprocessable Entity
Request body is missing, malformed JSON, or the phone field fails validation (wrong format, missing, too short/long).
Ensure Content-Type is application/json, the body is valid JSON, and phone is an 11-digit local number starting with 01.
429Too Many Requests
This API key has exceeded 30 requests in the current 60-second window.
Wait before retrying. Implement exponential back-off. Create additional keys if throughput demand is constant.
500Internal Server Error
Unexpected server-side failure. Rare — usually transient.
Retry after a short delay. If the issue persists beyond a few minutes, contact support at abrar@chowdhury.bd.
503Service Unavailable
The server is temporarily down for maintenance or a courier API is unreachable.
Retry with exponential back-off. The service typically recovers within minutes.
Debugging checklist
Still stuck?
If you've worked through the checklist and the error persists, reach out with your request ID (from the response headers if available) and the full error body.
abrar@chowdhury.bd