digetpay_plugin 0.3.0 copy "digetpay_plugin: ^0.3.0" to clipboard
digetpay_plugin: ^0.3.0 copied to clipboard

Pure-Dart DigetPay payment plugin: hosted (PCI-safe) checkout via WebView plus transaction management over the DigetPay REST API.

DigetPay for Flutter #

[DigetPay — pure-Dart hosted checkout for Flutter]

pub version pub points pub likes platforms license: MIT

Accept card payments in your Flutter app in minutes. DigetPay uses a hosted, PCI-safe WebView checkout — raw card data never passes through your app, so you keep your PCI scope small. Pure Dart, built on http and webview_flutter; no native code to write or register.

await DigetPaySdk.cardPay()
    .setOrder(DigetPaySaleOrder(id: orderId, description: 'Coffee', currency: 'SAR', amount: 15))
    .setPayer(payer)
    .onTransactionSuccess((res) => print('Paid ✓ ${res.transactionId}'))
    .onTransactionFailure((res) => print('Failed: ${res.declineReason}'))
    .onDismiss(() => print('User cancelled'))
    .start(context);

Contents #

Install #

dependencies:
  digetpay_plugin: ^0.3.0
flutter pub add digetpay_plugin

Quick start #

Initialize once at startup, then call the static API anywhere:

import 'package:digetpay_plugin/digetpay_plugin.dart';

DigetPaySdk.initialize(
  apiKey: '<your-mobile-api-key>',
  baseUrl: kDigetPayDefaultBaseUrl, // https://fin-api.digetpay.com/v1
);

Every call before initialize() throws DigetPaySdkIsNotInitializedException.

That's it — you're ready to open the checkout.

What you can do #

✅ Available now Purpose
cardPay() Hosted, PCI-safe card checkout (WebView)
getCheckoutStatus(sessionId) Confirm a checkout's outcome
getCheckoutSessions([filter]) List your checkout sessions (paginated)
capture · refund · voidd Move money on an existing transaction
🚧 Not yet available Behaviour
sale (raw-card S2S) Throws UnsupportedError — disabled to keep card data off-device
applePay · externalPayment · recurring Throws UnsupportedError — no backend endpoint yet
getTransactionById(id) Throws UnsupportedError — the lookup-by-id endpoint is no longer available; use getCheckoutStatus(sessionId) instead
getTransactionByOrderId · getTransactionByRrn Throws UnsupportedError — no endpoint yet
await DigetPaySdk.cardPay()
    .setOrder(DigetPaySaleOrder(
      id: orderId, description: 'Coffee', currency: 'SAR', amount: 15))
    .setPayer(DigetPayPayer(
      firstName: 'Demo', lastName: 'User', address: 'Riyadh',
      country: 'SA', city: 'Riyadh', zip: '00000',
      email: 'demo@example.com', phone: '+966500000000'))
    // .setResultUrls(...) is optional — omit to use the SDK defaults.
    .onTransactionSuccess((res) { /* res.status, res.transactionId ... */ })
    .onTransactionFailure((res) { /* res.declineReason, res.errorCode */ })
    .onDismiss(() { /* user backed out */ })
    .start(context);

start() calls POST /payment/checkout/intiate, opens the returned redirectUrl in a WebView and — once the hosted page reaches a result page — fetches GET /sdk/status?sessionId= and dispatches success or failure from the transaction's paymentStatus. Exactly one callback fires.

Flutter app
  │  DigetPaySdk.cardPay()…start(context)
  ▼
POST /payment/checkout/intiate  ──▶  { id, redirectUrl }
  │  push CheckoutPage → load redirectUrl
  ▼
WebView (hosted card form + 3-D Secure)
  │
  ├─ reaches a result page ──▶ GET /sdk/status?sessionId=<id>  (authoritative)
  │        ├─ paymentStatus == APPROVED ─▶ onTransactionSuccess(res)
  │        └─ otherwise                 ─▶ onTransactionFailure(res)
  │
  └─ user backs out (no result page) ──▶ onDismiss()
  • intiate is spelled that way on the backend — kept verbatim so the docs match the actual wire call (it is not a typo in your code).
  • The status response is authoritative — the SDK does not trust the result URL alone, because the gateway can route to /success briefly before settling on /failure.

Listing checkout sessions #

getCheckoutSessions() returns a paginated PageDto<CheckoutSession> from GET /payment/checkout/sessions:

final page = await DigetPaySdk.getCheckoutSessions(
  const CheckoutSessionFilter(page: 1, limit: 20),
);

for (final session in page?.content ?? const <CheckoutSession>[]) {
  print('${session.merchantOrderId} · ${session.amount} ${session.currency} · ${session.status}');
}

⚠️ Which id do I use?

A CheckoutSession carries two ids. For capture / refund / voidd, always use session.gatewayTransactionIdnot session.id (which identifies the checkout session, not the transaction).

// ✅ correct
await DigetPaySdk.refund(transactionId: session.gatewayTransactionId!, amount: session.amount!);
// ❌ wrong — session.id is NOT a transaction id

PageDto exposes content, number (the backend's 1-based page), size, totalElements, totalPages, first, and last.

Money movement #

Operate on an existing transaction by its gateway transaction id (no card data involved):

await DigetPaySdk.capture(transactionId: id, amount: 10); // POST /payment/s2s/capture
await DigetPaySdk.voidd(id);                              // POST /payment/s2s/void
await DigetPaySdk.refund(transactionId: id, amount: 10);  // POST /payment/refund

These return a typed DigetPayResponse. HTTP errors and declines come back as an unsuccessful response — they do not throw:

DigetPayResponse Meaning
isSuccess 2xx and not declined/failed
status / result Gateway status text
transactionId · orderId · rrn Identifiers
message · errorCode · declineReason Failure detail
data The raw decoded payload (for anything not typed above)

Handling transaction data #

getCheckoutStatus returns a typed Transaction? (a DECLINED transaction is still returned — inspect paymentStatus). Some fields are sensitive; the SDK delivers them to you but never logs them:

  • pan — already masked by the backend (4323 2** **** 0853); safe to show.
  • cardHolderName — PII; display it, but don't log/persist broadly.
  • recurringTokensensitive: it can initiate future charges. Keep it server-side, never log it, and don't surface it in the UI.

Debug logging #

Pass an optional logger to initialize for a redacted, step-by-step trace — HTTP method + path + status, checkout milestones, and the terminal outcome. It never receives the API key, card data, request/response bodies, or query values.

import 'dart:developer' as developer;

DigetPaySdk.initialize(
  apiKey: '<key>',
  logger: (message) => developer.log(message, name: 'DigetPay'),
);
💳 checkout: creating session for order 6f… (15.0 SAR)
➡️ → POST /payment/checkout/intiate
⬅️ ← 201 OK POST /payment/checkout/intiate {code=201, session=ab02…, redirect=https://fin-admin.digetpay.com/pay/checkout}
🌐 webview → https://fin-admin.digetpay.com/pay/checkout/success
➡️ → GET /sdk/status?sessionId
⬅️ ← 200 OK GET /sdk/status {code=200, status=APPROVED, txn=070ae…, msg=Success}
✅ checkout: APPROVED → onTransactionSuccess

Leave logger unset (the default) for zero logging in production.

Platform setup #

Pure-Dart plugin — no native code to write. You only need standard network/WebView configuration.

Android #

  • minSdkVersion 24 (Android 7.0) in android/app/build.gradle.

  • INTERNET permission in android/app/src/main/AndroidManifest.xml (the release manifest does not include it automatically):

    <uses-permission android:name="android.permission.INTERNET"/>
    

iOS #

  • Deployment target iOS 13.0+ in ios/Podfile and the Runner target.
  • DigetPay endpoints and the hosted page are served over HTTPS, so the default App Transport Security policy works with no changes. Avoid a blanket NSAllowsArbitraryLoads in production.

Hosted checkout targets Android and iOS (via webview_flutter); Flutter web and desktop are not supported in this version.

Security — mobile API key #

DigetPayConfig.apiKey is embedded in your app binary, and anything shipped in a mobile app can be extracted. Always initialize with a publishable / restricted mobile key scoped to client operations — never a full server secret. Rotate the key if it is ever exposed, and keep privileged operations behind your own server. This is why the plugin implements only the hosted (PCI-safe) card flow: raw card data never touches the device.

Not yet available #

sale, applePay, externalPayment, recurring, getTransactionById, getTransactionByOrderId, and getTransactionByRrn throw UnsupportedError until the corresponding backend endpoints exist (see the TODO(endpoint) markers in the source). sale is intentionally disabled to keep raw card data off-device — use cardPay() instead. getTransactionById previously worked via GET /payment/checkout/status?id=, which the backend has since retired; use getCheckoutStatus(sessionId) or inspect getCheckoutSessions() results instead.


MIT © DigetPay · Issues & source: https://github.com/DigetPay/digetpay_plugin

1
likes
0
points
287
downloads

Publisher

unverified uploader

Weekly Downloads

Pure-Dart DigetPay payment plugin: hosted (PCI-safe) checkout via WebView plus transaction management over the DigetPay REST API.

Homepage
Repository (GitHub)
View/report issues

Topics

#payments #payment-gateway #checkout #webview

License

unknown (license)

Dependencies

flutter, http, uuid, webview_flutter

More

Packages that depend on digetpay_plugin