Moosyl logo

Dart SDK

Use the official Moosyl Dart SDK in Dart and Flutter backends

Overview

Use moosyl to integrate Moosyl payments from Dart or Flutter server-side code using a generated, typed API client built on Dio.

Installation

dart pub add moosyl

Or add it directly:

pubspec.yaml
dependencies:
  moosyl: ^1.1.1

Initialization

import 'package:moosyl/moosyl.dart';

final client = Moosyl(
  basePathOverride: 'https://api.moosyl.com',
);

client.setApiKey('ApiKey', 'sk_test_...');

Core Feature 1: Create Payment Request

Use a secret key (sk_...) on backend only. See API Keys.

import 'package:moosyl/moosyl.dart';
import 'package:one_of/any_of.dart';

PaymentRequestCreateAmount amountAsNumber(num value) {
  return PaymentRequestCreateAmount(
    (b) => b.anyOf = AnyOf2<String, num>(values: {1: value}),
  );
}

final paymentRequestApi = client.getPaymentRequestApi();

final created = await paymentRequestApi.postPaymentRequest(
  paymentRequestCreate: PaymentRequestCreate(
    (b) => b
      ..transactionId = 'order_123'
      ..amount.replace(amountAsNumber(1000)),
  ),
);

final paymentRequestId = created.data?.data.id;

For hosted checkout after creating the request, see Checkout Session.

Retry pattern with stable transactionId:

import 'package:dio/dio.dart';

Future<String?> ensurePaymentRequestId(Moosyl client, String transactionId) async {
  final api = client.getPaymentRequestApi();

  try {
    final created = await api.postPaymentRequest(
      paymentRequestCreate: PaymentRequestCreate(
        (b) => b
          ..transactionId = transactionId
          ..amount.replace(amountAsNumber(1000)),
      ),
    );
    return created.data?.data.id;
  } on DioException catch (_) {
    final existing = await api.getPaymentRequestByTransactionByTransactionId(
      transactionId: transactionId,
    );
    return existing.data?.data.id;
  }
}

Core Feature 2: Send and Check Status

Send

final checkoutApi = client.getCheckoutSessionApi();

final checkout = await checkoutApi.postCheckoutSession(
  checkoutSessionCreateBody: CheckoutSessionCreateBody(
    (b) => b.paymentRequestId = paymentRequestId!,
  ),
);

final checkoutUrl = checkout.data?.checkoutUrl;

Check

final paymentRequestApi = client.getPaymentRequestApi();

await paymentRequestApi.patchPaymentRequestByTransactionIdRefreshStatus(
  transactionId: 'order_123',
);

final latest = await paymentRequestApi.getPaymentRequestByTransactionByTransactionId(
  transactionId: 'order_123',
);

Full flow

Full flow (Dart)
import 'package:moosyl/moosyl.dart';
import 'package:one_of/any_of.dart';

PaymentRequestCreateAmount amountAsNumber(num value) {
  return PaymentRequestCreateAmount(
    (b) => b.anyOf = AnyOf2<String, num>(values: {1: value}),
  );
}

Future<void> runMoosylFlow() async {
  final client = Moosyl(basePathOverride: 'https://api.moosyl.com');
  client.setApiKey('ApiKey', 'sk_test_...');

  final paymentRequestApi = client.getPaymentRequestApi();
  final checkoutApi = client.getCheckoutSessionApi();

  final created = await paymentRequestApi.postPaymentRequest(
    paymentRequestCreate: PaymentRequestCreate(
      (b) => b
        ..transactionId = 'order_789'
        ..amount.replace(amountAsNumber(1000)),
    ),
  );

  final id = created.data?.data.id;
  if (id == null) return;

  final checkout = await checkoutApi.postCheckoutSession(
    checkoutSessionCreateBody: CheckoutSessionCreateBody(
      (b) => b.paymentRequestId = id,
    ),
  );

  await paymentRequestApi.patchPaymentRequestByTransactionIdRefreshStatus(
    transactionId: 'order_789',
  );

  final current = await paymentRequestApi.getPaymentRequestByTransactionByTransactionId(
    transactionId: 'order_789',
  );

  print(checkout.data?.checkoutUrl);
  print(current.data?.data.status);
}

Error Handling

The SDK methods throw DioException for network, API, and serialization errors.

import 'package:dio/dio.dart';

try {
  await client.getPaymentRequestApi().getPaymentRequestById(id: 'pr_123');
} on DioException catch (e) {
  final statusCode = e.response?.statusCode;
  final body = e.response?.data;
  print('Moosyl request failed: $statusCode');
  print(body);
}

Reference API status/error responses in the API docs: https://api.moosyl.com/docs

Webhook/Event Verification

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

String _hexEncode(List<int> bytes) =>
    bytes.map((b) => b.toRadixString(16).padLeft(2, '0')).join();

bool _constantTimeEqual(String a, String b) {
  if (a.length != b.length) return false;
  var diff = 0;
  for (var i = 0; i < a.length; i++) {
    diff |= a.codeUnitAt(i) ^ b.codeUnitAt(i);
  }
  return diff == 0;
}

bool verifyMoosylWebhook({
  required String rawBody,
  required String signature,
  required String webhookSecret,
}) {
  final digest = Hmac(
    sha256,
    utf8.encode(webhookSecret),
  ).convert(utf8.encode(rawBody));

  return _constantTimeEqual(_hexEncode(digest.bytes), signature);
}

For setup details, see Webhooks.

Requirements

  • Dart SDK >=2.18.0 <4.0.0
  • Compatible with Dart backend services and Flutter projects
  • Optional for SDK contributors: build_runner for local codegen workflows
Dart SDK | Moosyl Docs