Checkout
Flutter checkout SDK
Open VenPays hosted card checkout inside a Flutter WebView. Card numbers never touch your app — the shopper pays on the VenPays / Mastercard page.
This version is card only (venpays_flutter 0.1.2). Benefit, BenefitPay, and Apple Pay are not in the Flutter SDK yet. For native Apple Pay on iOS, see Apple Pay iOS.
Credentials
| Credential | Where it lives | What it does |
|---|---|---|
Secret (sk_…) or existing unprefixed key | Your merchant backend | Creates the checkout session, starts card pay, confirms status |
Publishable (pk_…) | Not required for this Flutter flow | Used by the JavaScript checkout SDK only |
Never put a secret or legacy key in the Flutter app. The SDK never accepts or stores VenPays API keys.
1. Create a session and start card pay on your server
POST /v1/sdk/checkout
Host: init-vpay.venlabs.link
X-API-KEY: sk_test_…
Content-Type: application/json
{ "amount": 12.500, "currency": "BHD" }
Then start card payment:
POST /v1/sdk/checkout/{track_id}/pay
Host: init-vpay.venlabs.link
Content-Type: application/json
{ "method": "card" }
Live host: merchant.venpays.com. Use a secret or legacy key, not the publishable key.
Return only safe fields to the app:
{
"track_id": "…",
"payment_url": "https://…/mastercard/payment?payment_id=…",
"amount": 12.5,
"currency": "BHD"
}
2. Install the Flutter package
dependencies:
venpays_flutter: ^0.1.2
flutter pub get
Package: venpays_flutter
Source: venpays-flutter
3. Start checkout in the app
import 'package:venpays_flutter/venpays_flutter.dart';
final result = await VenPaysCheckout.start(
context: context,
paymentUrl: payment.paymentUrl, // from your backend
trackId: payment.trackId, // from your backend
successUrl: 'https://merchant.example/payment/success',
failureUrl: 'https://merchant.example/payment/failure',
);
switch (result.status) {
case PaymentStatus.success:
// Informational only — confirm on your backend before fulfillment.
break;
case PaymentStatus.failed:
break;
case PaymentStatus.cancelled:
// Shopper closed checkout; transaction is marked cancelled on VenPays.
break;
case PaymentStatus.error:
break;
}
| Field | Requirement |
|---|---|
paymentUrl | HTTPS hosted card URL from POST …/pay |
trackId | Session track_id from your backend |
successUrl / failureUrl | Same HTTPS Profile (or override) return URLs VenPays will redirect to |
Custom URL schemes (myapp://…) are not supported by the Payment Engine return-URL validator. See Return URLs.
While the sheet is open, the SDK polls GET /v1/sdk/checkout/{track_id}/status on the Payment Engine host from paymentUrl. When status becomes success, failed, or cancelled, the sheet dismisses automatically — even if the Profile return URL does not exactly match what you passed in.
If the shopper closes the sheet while the payment is still pending, the SDK calls POST /v1/sdk/checkout/{track_id}/cancel so the transaction is marked cancelled on VenPays (not left pending). Closing after a finished payment still reports success/failure, not cancelled.
If the customer never pays, VenPays cancels the payment after 30 minutes even when the sheet stays open. Payment-status then returns cancelled.
PaymentResult is still client-observed only. Confirm on your server before fulfillment.
4. Confirm on your server
After the WebView closes, treat PaymentResult as a hint only. Fulfill the order from a webhook or POST /merchant/payment-status with your secret key. See Payment status and Webhooks.
Abandoned checkouts should show status: "cancelled" on POST /merchant/payment-status.
Sandbox and live
The Flutter app does not choose sandbox vs live. Your backend selects the environment by which Payment Engine host and API key it uses; the app only opens the payment_url you return.
| Environment | Payment Engine |
|---|---|
| Sandbox | https://init-vpay.venlabs.link |
| Live | https://merchant.venpays.com |
What the Flutter SDK does not do
- Collect or store card PAN / CVV
- Hold secret, legacy, or publishable keys
- Call initiate, refund, or merchant
payment-statusAPIs - Select Benefit, BenefitPay, or Apple Pay
It may poll the public checkout status endpoint and call cancel on abandon for UX. That is not a substitute for merchant-server confirmation.
Troubleshooting
| Symptom | Check |
|---|---|
| Validation error “must use https” | Use HTTPS for paymentUrl, successUrl, and failureUrl |
| Sheet does not auto-close | Ensure the device can reach GET /v1/sdk/checkout/{track_id}/status on the same PE host as payment_url; prefer matching Profile return URLs too |
| App shows cancelled but dashboard still pending | Use Payment Engine build with cancel support + venpays_flutter ≥ 0.1.2; confirm with POST /merchant/payment-status |
| App shows cancelled but dashboard shows success | Update to venpays_flutter ≥ 0.1.1 (status re-check on close); confirm with webhooks / payment-status |
| Success in app but order not paid | Confirm with POST /merchant/payment-status / webhooks |
| Blank WebView | Device network, Payment Engine / gateway reachability, invalid payment_url |