bayarcash 1.0.0 copy "bayarcash: ^1.0.0" to clipboard
bayarcash: ^1.0.0 copied to clipboard

Dart SDK for the Bayarcash payment gateway. A feature-parity, idiomatic port of the official PHP SDK, usable from Flutter apps and server-side Dart.

Bayarcash Payment Gateway Dart SDK #

pub package pub points License: MIT

The Bayarcash SDK provides an expressive interface for interacting with Bayarcash's Payment Gateway API from Dart. It is a feature-parity, idiomatic port of the official PHP SDK.

It is a pure Dart package with no Flutter dependency, so it works in both Flutter apps and server-side Dart. It supports API v2 (default) and v3, with additional query features available in v3.

Table of Contents #

Requirements #

  • Dart SDK >=2.17.0 <4.0.0 (works in Flutter and server Dart)

Installation #

Install with Dart's package manager:

dart pub add bayarcash

Or add it to your pubspec.yaml:

dependencies:
  bayarcash: ^3.0.0

Then import it:

import 'package:bayarcash/bayarcash.dart';

You will need two credentials from your Bayarcash console:

  • API token — used to authenticate SDK requests.
  • API secret key — used to generate request checksums and verify callbacks.

Getting Started #

import 'package:bayarcash/bayarcash.dart';

final bayarcash = Bayarcash(
  token: 'YOUR_API_TOKEN',
  secretKey: 'YOUR_API_SECRET_KEY',
  sandbox: true, // remove in production
);

The secretKey is optional at construction time — you can pass it per-call to the checksum and callback-verification helpers instead. When configured on the client, it is used as the default.

Configuration #

All configuration can be passed to the constructor, or set fluently afterwards (each setter returns the client for chaining):

final bayarcash = Bayarcash(token: 'YOUR_API_TOKEN')
  ..useSandbox()          // switch to the sandbox environment
  ..setApiVersion('v3')   // 'v2' (default) or 'v3'
  ..setTimeout(60);       // request timeout in seconds (default 30)

bayarcash.getApiVersion(); // read back the current version
Option Default Description
token — (required) API token used to authenticate requests.
secretKey null API secret key, used to sign and verify.
sandbox false Target the sandbox environment.
apiVersion 'v2' 'v2' or 'v3'.
timeout 30s Per-request timeout.
httpClient auto Inject your own http.Client (useful for tests).

Set sandbox/apiVersion before making requests. Omit sandbox in production to hit the live gateway.

Base URIs #

Version Environment Base URI
v2 production https://console.bayar.cash/api/v2/
v2 sandbox https://console.bayarcash-sandbox.com/api/v2/
v3 production https://api.console.bayar.cash/v3/
v3 sandbox https://api.console.bayarcash-sandbox.com/v3/

Quick Start: Accept a Payment #

A complete FPX payment flow, from creating the payment to verifying the result:

import 'package:bayarcash/bayarcash.dart';

Future<String> startPayment() async {
  final bayarcash = Bayarcash(
    token: 'YOUR_API_TOKEN',
    secretKey: 'YOUR_API_SECRET_KEY',
    sandbox: true,
  );

  // 1. Build the payment request
  final data = <String, dynamic>{
    'portal_key': 'your_portal_key',
    'payment_channel': Bayarcash.fpx,
    'order_number': 'INV-1001',
    'amount': '10.00',
    'payer_name': 'Ahmad bin Abdullah',
    'payer_email': 'ahmad@example.com',
    'payer_telephone_number': '0123456789',
    'return_url': 'https://your-site.com/payment/return',
    'callback_url': 'https://your-site.com/payment/callback',
  };

  // 2. Sign it (recommended)
  data['checksum'] = bayarcash.createPaymentIntentChecksumValue(data);

  // 3. Create the payment intent and redirect the payer to Bayarcash
  final paymentIntent = await bayarcash.createPaymentIntent(data);

  return paymentIntent.url!; // redirect the payer here
}

After payment, Bayarcash calls your callback_url (server-to-server) and redirects the payer to your return_url. Verify both — see Handling Callbacks.

Payment Channels #

Pass one of these constants (or a list of them) as payment_channel:

Bayarcash.fpx              // 1  FPX Online Banking
Bayarcash.manualTransfer   // 2  Manual Bank Transfer
Bayarcash.fpxDirectDebit   // 3  FPX Direct Debit
Bayarcash.fpxLineOfCredit  // 4  FPX Line of Credit
Bayarcash.duitnowDobw      // 5  DuitNow Online Banking
Bayarcash.duitnowQr        // 6  DuitNow QR
Bayarcash.spaylater        // 7  ShopeePayLater
Bayarcash.boostPayflex     // 8  Boost PayFlex
Bayarcash.qrisob           // 9  QRIS Online Banking
Bayarcash.qriswallet       // 10 QRIS Wallet
Bayarcash.nets             // 11 NETS
Bayarcash.creditCard       // 12 Credit Card
Bayarcash.alipay           // 13 Alipay
Bayarcash.wechatpay        // 14 WeChat Pay
Bayarcash.promptpay        // 15 PromptPay
Bayarcash.touchNGo         // 16 Touch 'n Go eWallet
Bayarcash.boostWallet      // 17 Boost Wallet
Bayarcash.grabpay          // 18 GrabPay
Bayarcash.grabpl           // 19 Grab PayLater
Bayarcash.shopeePay        // 21 ShopeePay (note: there is no id 20)

Creating a Payment Intent #

final paymentIntent = await bayarcash.createPaymentIntent(data);

Request fields:

Field Required Description
portal_key Your portal key.
order_number Your reference. Max 30 chars.
amount String with up to 2 decimals, e.g. '10.00'.
payer_name Max 150 chars.
payer_email Valid email, max 250 chars.
payment_channel A Bayarcash.* channel id, or a list of ids.
payer_telephone_number Required for e-wallet / DuitNow channels.
return_url Where the payer's browser is redirected after payment.
callback_url Server-to-server notification URL.
metadata Any extra data you want echoed back.
checksum Recommended. See below.

Checksum #

Generate the checksum after building the request and append it as checksum:

data['checksum'] = bayarcash.createPaymentIntentChecksumValue(data);
// or pass the secret explicitly:
data['checksum'] =
    bayarcash.createPaymentIntentChecksumValue(data, secretKey: apiSecretKey);

The checksum is computed from payment_channel, order_number, amount, payer_name, and payer_email.

Handling Callbacks #

Bayarcash sends two kinds of notification. Always verify them with your API secret key before trusting the data. Checksum comparison uses a constant-time algorithm to resist timing attacks.

Notification How it arrives Read it from
callback_url (transaction) Server-to-server POST (form-encoded) request body
return_url (payer redirect) Browser redirect — POST on v2, GET query on v3 request body / query
final callbackData = <String, dynamic>{/* parsed request body or query */};

// Transaction callback (sent to your callback_url)
if (bayarcash.verifyTransactionCallbackData(callbackData)) {
  // Data is authentic — safe to process.
}

// Payer redirect (sent to your return_url)
if (bayarcash.verifyReturnUrlCallbackData(callbackData)) {
  // ...
}

// Pre-transaction callback (sent before the transaction record)
if (bayarcash.verifyPreTransactionCallbackData(callbackData)) {
  // ...
}

Each verifier returns true only when the checksum matches. See FPX Direct Debit for mandate-specific callback verifiers.

Payment & Transaction Status #

Transaction status is an integer code. Use the Fpx helper instead of hardcoding numbers:

Fpx.statusNew;        // 0
Fpx.statusPending;    // 1
Fpx.statusFailed;     // 2
Fpx.statusSuccess;    // 3
Fpx.statusCancelled;  // 4

if (int.parse(callbackData['status'].toString()) == Fpx.statusSuccess) {
  // Payment successful
}

Fpx.getStatusText(3); // "Successful"

Transactions #

// Get a single transaction (v2 and v3)
final transaction = await bayarcash.getTransaction('transaction_id');

The following query helpers require API v3 and throw on v2:

bayarcash.setApiVersion('v3');

final result = await bayarcash.getAllTransactions({
  'order_number': 'INV-1001',
  'status': '3',
  'payment_channel': Bayarcash.fpx,
  'exchange_reference_number': 'REF123',
  'payer_email': 'ahmad@example.com',
});
// result.data => List<TransactionResource>, result.meta => pagination meta

final byOrder = await bayarcash.getTransactionByOrderNumber('INV-1001');
final byEmail = await bayarcash.getTransactionsByPayerEmail('ahmad@example.com');
final byStatus = await bayarcash.getTransactionsByStatus('3');
final byChannel = await bayarcash.getTransactionsByPaymentChannel(Bayarcash.fpx);
final byRef = await bayarcash.getTransactionByReferenceNumber('REF123'); // or null

// Get a payment intent by id (v3 only)
final intent = await bayarcash.getPaymentIntent('payment_intent_id');

// Cancel a payment intent (v3 only)
await bayarcash.cancelPaymentIntent('payment_intent_id');

FPX Direct Debit #

FPX Direct Debit lets you set up a recurring mandate and later maintain or terminate it. Constants live on the FpxDirectDebit class:

// Payer ID type
FpxDirectDebit.nric;                 // 1 (New IC)
FpxDirectDebit.oldIc;                // 2
FpxDirectDebit.passport;             // 3
FpxDirectDebit.businessRegistration; // 4
FpxDirectDebit.others;               // 5

// Frequency mode
FpxDirectDebit.modeDaily;   // 'DL'
FpxDirectDebit.modeWeekly;  // 'WK'
FpxDirectDebit.modeMonthly; // 'MT'
FpxDirectDebit.modeYearly;  // 'YR'

1. Enrolment #

final data = <String, dynamic>{
  'portal_key': 'your_portal_key',
  'order_number': 'DD-1001',
  'amount': '10.00',
  'payer_name': 'Ahmad bin Abdullah',
  'payer_id_type': FpxDirectDebit.nric,
  'payer_id': '900101011234',
  'payer_email': 'ahmad@example.com',
  'payer_telephone_number': '0123456789',
  'application_reason': 'Monthly subscription',
  'frequency_mode': FpxDirectDebit.modeMonthly,
  'effective_date': '2026-08-01', // optional, yyyy-MM-dd
  'expiry_date': '2027-08-01',    // optional, yyyy-MM-dd
  'return_url': 'https://your-site.com/mandate/return',
};

data['checksum'] = bayarcash.createFpxDirectDebitEnrolmentChecksumValue(data);

final mandate = await bayarcash.createFpxDirectDebitEnrollment(data);
// redirect the payer to mandate.url

2. Maintenance #

final data = <String, dynamic>{
  'amount': '15.00',
  'payer_email': 'ahmad@example.com',
  'payer_telephone_number': '0123456789',
  'application_reason': 'Update amount',
  'frequency_mode': FpxDirectDebit.modeMonthly,
};

data['checksum'] =
    bayarcash.createFpxDirectDebitMaintenanceChecksumValue(data);

final mandate =
    await bayarcash.createFpxDirectDebitMaintenance(mandateId, data);

3. Termination #

final mandate = await bayarcash.createFpxDirectDebitTermination(mandateId, {
  'application_reason': 'Customer cancelled',
});

Retrieving mandates & verifying mandate callbacks #

final mandate = await bayarcash.getFpxDirectDebit(mandateId);
final transaction =
    await bayarcash.getFpxDirectDebitTransaction(transactionId);

// Mandate callback verifiers
bayarcash.verifyDirectDebitBankApprovalCallbackData(callbackData);
bayarcash.verifyDirectDebitAuthorizationCallbackData(callbackData);
bayarcash.verifyDirectDebitTransactionCallbackData(callbackData);

Manual Bank Transfer #

Submit a manual (offline) bank transfer with proof of payment. The proof file is uploaded as multipart form data.

final response = await bayarcash.createManualBankTransfer({
  'portal_key': 'your_portal_key',
  'payment_gateway': Bayarcash.manualTransfer, // must be 2
  'order_no': 'MT-1001',
  'buyer_name': 'Ahmad bin Abdullah',
  'buyer_email': 'ahmad@example.com',
  'buyer_tel_no': '0123456789', // optional
  'order_amount': '10.00',
  'merchant_bank_name': 'Maybank',
  'merchant_bank_account': '1234567890',
  'merchant_bank_account_holder': 'Your Company Sdn Bhd',
  'bank_transfer_type': 'Internet Banking',
  'bank_transfer_notes': 'Payment for order MT-1001',
  'bank_transfer_date': '2026-07-22', // optional, defaults to today
  'proof_of_payment': '/path/to/receipt.jpg', // jpeg/png/gif/pdf
});

Update the status of an existing transfer:

await bayarcash.updateManualBankTransferStatus(
  'ref_no_here',
  Fpx.statusSuccess.toString(),
  '10.00',
);

Portals & FPX Banks #

// All portals for your account
final portals = await bayarcash.getPortals();

// Payment channels available for a portal
final channels = await bayarcash.getChannels('your_portal_key');

// FPX banks (for building a bank selector)
final banks = await bayarcash.fpxBanksList();

Error Handling #

Failed API calls throw typed exceptions. Catch them to handle errors gracefully. Every exception subclasses BayarcashException.

try {
  final paymentIntent = await bayarcash.createPaymentIntent(data);
} on ValidationException catch (e) {
  // 422 — invalid request data
  final errors = e.errors;
} on NotFoundException {
  // 404 — resource not found
} on RateLimitException catch (e) {
  // 429 — too many requests
  final resetAt = e.rateLimitResetsAt; // unix timestamp or null
} on FailedActionException catch (e) {
  // 400 — request failed
  final message = e.message;
} on BayarcashApiException catch (e) {
  // any other non-2xx response
  final status = e.statusCode;
}
Exception HTTP Meaning
ValidationException 422 Invalid data. Read .errors for details.
FailedActionException 400 Request failed. .message has the reason.
NotFoundException 404 Resource not found.
RateLimitException 429 Rate limited. .rateLimitResetsAt holds the reset time.
BayarcashApiException other Any other non-2xx response.

Response Objects #

API methods return typed resource objects. Any missing field is null, and the raw JSON is available through resource.raw and resource['snake_case_key'].

PaymentIntentResource (from createPaymentIntent / getPaymentIntent)

paymentIntent.url;          // checkout URL to redirect the payer to
paymentIntent.id;
paymentIntent.status;
paymentIntent.amount;
paymentIntent.orderNumber;
paymentIntent.payerName;
paymentIntent.payerEmail;

TransactionResource (from getTransaction / transaction queries)

transaction.id;
transaction.status;                 // int status code as a string — see Fpx
transaction.statusDescription;
transaction.amount;
transaction.orderNumber;
transaction.exchangeReferenceNumber;
transaction.payerName;
transaction.payerEmail;
transaction.toMap();                // the raw JSON as a map

Testing #

Inject a mock http.Client to test without hitting the network:

import 'package:bayarcash/bayarcash.dart';
import 'package:http/testing.dart';
import 'package:http/http.dart' as http;

final client = MockClient((request) async {
  return http.Response('{"url": "https://pay.example/checkout"}', 200);
});

final bayarcash = Bayarcash(token: 'test', httpClient: client);

Security Recommendations #

  1. Always send a checksum with payment and mandate requests.
  2. Verify every callback with the provided verification methods before acting on it.
  3. Store and check transaction ids to prevent duplicate processing.
  4. Use HTTPS for your return_url and callback_url.
  5. Keep your API token and secret key out of source control.

API Documentation #

For full API details, see the Official Bayarcash API Documentation.

Support #

For support questions, contact Bayarcash support or open an issue in this repository.

Changelog #

See CHANGELOG.md for the version history.

License #

Open-sourced software licensed under the MIT license.

0
likes
150
points
27
downloads

Documentation

Documentation
API reference

Publisher

verified publisherwebimpian.com

Weekly Downloads

Dart SDK for the Bayarcash payment gateway. A feature-parity, idiomatic port of the official PHP SDK, usable from Flutter apps and server-side Dart.

Homepage
Repository (GitHub)
View/report issues

Topics

#payment #payment-gateway #bayarcash #fpx

License

MIT (license)

Dependencies

crypto, http, http_parser

More

Packages that depend on bayarcash