paperfly_courier 0.1.0 copy "paperfly_courier: ^0.1.0" to clipboard
paperfly_courier: ^0.1.0 copied to clipboard

Official Dart/Flutter client for the Paperfly (Bangladesh) merchant courier API — create parcels, exchange orders, track shipments, cancel orders, and parse webhook events.

paperfly_courier #

Official Dart/Flutter client for the Paperfly (Bangladesh) merchant courier API. Create parcels and exchange orders, track shipments, cancel orders, and parse webhook events — all with typed requests, typed responses, and typed errors.

Works in any Dart or Flutter app (mobile, web, desktop, server/CLI); it has no Flutter SDK dependency, so it's just as usable from a Dart backend.

Features #

  • createOrder — create a parcel, or an exchange order via PaperflyOrderRequest.exchange.
  • trackOrder — look up delivery status, with a ready-made chronological timeline.
  • cancelOrder — cancel a parcel.
  • PaperflyWebhookEvent — parse inbound webhook payloads for all 14 documented event types.
  • PaperflyWebhookVerifier — check a webhook's shared secret.
  • Typed exceptions (PaperflyAuthException, PaperflyApiException, PaperflyNetworkException, PaperflyDecodeException) instead of raw HTTP responses to parse yourself.

Getting started #

Add the package:

flutter pub add paperfly_courier

or, for a plain Dart project:

dart pub add paperfly_courier

You'll need three values from your Paperfly merchant dashboard (https://go.paperfly.com.bd/merchant/dashboardDeveloper & PluginsAPI Docs):

  • Your merchant panel User Name
  • Your merchant panel Password
  • The paperflykey header value shown on that page

Security note: never hard-code these in a public client app, and never embed them in an app you distribute. Treat them like any other API secret — load them from secure configuration and, where possible, make Paperfly calls from your own backend rather than directly from a mobile or web client.

Usage #

Create a parcel #

import 'package:paperfly_courier/paperfly_courier.dart';

final client = PaperflyClient(
  merchantUsername: 'YOUR_MERCHANT_USERNAME',
  merchantPassword: 'YOUR_MERCHANT_PASSWORD',
  paperflyKey: 'YOUR_PAPERFLY_KEY',
);

try {
  final order = await client.createOrder(
    PaperflyOrderRequest(
      merchantOrderReference: 'ORDER-1001', // must be unique per order
      storeName: 'My Shop',
      productBrief: 'Blue T-Shirt (L)',
      packagePrice: 590,
      maxWeight: 0.5,
      customerName: 'Jane Doe',
      customerAddress: 'House 12, Road 5, Banani, Dhaka',
      customerPhone: '01700000000',
    ),
  );

  print(order.trackingNumber); // e.g. "Z-051125-63821-A3-A1"
  print(order.trackingBarcode);
} on PaperflyAuthException catch (e) {
  // Bad username/password/paperflykey.
} on PaperflyApiException catch (e) {
  // Paperfly rejected the request — see e.message / e.responseBody.
} on PaperflyNetworkException catch (e) {
  // Couldn't reach Paperfly at all (offline, timeout, etc).
}

Create an exchange order #

Paperfly uses the same endpoint for exchange orders — just set exchange:

final order = await client.createOrder(
  PaperflyOrderRequest(
    merchantOrderReference: 'ORDER-1002',
    storeName: 'My Shop',
    productBrief: 'Blue T-Shirt (L)',
    packagePrice: 590,
    maxWeight: 0.5,
    customerName: 'Jane Doe',
    customerAddress: 'House 12, Road 5, Banani, Dhaka',
    customerPhone: '01700000000',
    exchange: PaperflyExchangeDetails(
      description: 'Red T-Shirt (M) — exchanged for blue L',
      price: 590,
      weight: 0.5,
    ),
  ),
);

Track a parcel #

final tracking = await client.trackOrder('ORDER-1001');

for (final milestone in tracking.latest?.timeline ?? const []) {
  print('${milestone.stage}: ${milestone.time}');
}

print(tracking.latest?.isDelivered); // true / false

Cancel a parcel #

final cancelled = await client.cancelOrder('ORDER-1001');
print(cancelled.message);

Handling webhooks #

Configure a webhook URL and secret under Developer & Plugins → Webhooks in the dashboard, then parse incoming requests on your server with PaperflyWebhookEvent:

import 'dart:convert';
import 'package:paperfly_courier/paperfly_courier.dart';

// Inside your webhook handler, given the raw request body:
void handleWebhook(String requestBody) {
  final event = PaperflyWebhookEvent.fromJson(jsonDecode(requestBody));

  switch (event.type) {
    case PaperflyWebhookEventType.parcelDelivered:
      // Mark the order delivered in your own system.
      break;
    case PaperflyWebhookEventType.parcelCancelled:
      // ...
      break;
    default:
      // See PaperflyWebhookEventType for the full list of 14 events.
      break;
  }

  print(event.data.orderNumber);
  print(event.data.merchantOrderReference);
  print(event.data.recipient.name);
}

Paperfly's dashboard states that the secret you configure "will be sent in the header for verification", without documenting the exact header name or signing scheme. Compare whatever header your server receives against your configured secret with PaperflyWebhookVerifier.isValid:

final isGenuine = PaperflyWebhookVerifier.isValid(
  request.headers['x-paperfly-secret'], // adjust to the header you observe
  configuredSecret,
);

Webhooks arrive on your server, not inside the Flutter app itself — wire this up in whatever backend (Cloud Function, Node/PHP/Dart server, etc.) receives the webhook, not in client-side app code.

Full example #

See example/lib/main.dart for a small Flutter app that creates, tracks, and cancels a parcel, and example/paperfly_courier_example.dart for a plain-Dart version.

API coverage #

This package covers every endpoint documented on the merchant dashboard's Developer & Plugins → API Docs page as of writing:

Operation Endpoint
Create order POST /merchant/api/service/new_order_v2.php
Create exchange POST /merchant/api/service/new_order_v2.php (with exchange fields)
Track order POST /API-Order-Tracking
Cancel order POST /api/v1/cancel-order

All requests are authenticated with HTTP Basic Auth (your merchant panel username/password) plus a paperflykey header.

Error handling #

Every failure surfaces as a PaperflyException subtype instead of a raw http.Response:

  • PaperflyAuthException — HTTP 401/403, or bad credentials.
  • PaperflyApiException — any other API-reported failure (non-2xx status, or a 200 whose body reports failure). Carries statusCode, responseCode, and the raw responseBody.
  • PaperflyNetworkException — the request couldn't be sent at all (offline, DNS failure, timeout, etc). Carries the original cause.
  • PaperflyDecodeException — Paperfly's response wasn't valid JSON.

Contributing #

Issues and pull requests are welcome. Please run dart format ., dart analyze, and dart test before submitting.

License #

MIT — see LICENSE.

0
likes
160
points
63
downloads

Documentation

Documentation
API reference

Publisher

verified publishercarboncodes.net

Weekly Downloads

Official Dart/Flutter client for the Paperfly (Bangladesh) merchant courier API — create parcels, exchange orders, track shipments, cancel orders, and parse webhook events.

Repository (GitHub)
View/report issues

Topics

#courier #shipping #paperfly #ecommerce #bangladesh

License

MIT (license)

Dependencies

http

More

Packages that depend on paperfly_courier