Mobile

Flutter / Dart SDK

Dart implementation for integrating YardPay Pro into Flutter apps on iOS, Android, and web. Uses dart:io / http with no third-party dependencies.

Dependencies

Add the built-in http package to your pubspec.yaml (included with Flutter):

dependencies:
  http: ^1.1.0
API Client

Create lib/yardpaypro/client.dart

// lib/yardpaypro/client.dart

import 'dart:convert';
import 'package:http/http.dart' as http;

class YppException implements Exception {
  final int status;
  final String code;
  final String message;
  YppException(this.status, this.code, this.message);

  @override
  String toString() => 'YppException($status $code: $message)';
}

class YardPayProClient {
  final String apiKey;
  final String baseUrl;
  final http.Client _http;

  YardPayProClient({
    required this.apiKey,
    required this.baseUrl,
    http.Client? httpClient,
  }) : _http = httpClient ?? http.Client();

  Map<String, String> get _headers => {
    'Content-Type': 'application/json',
    'x-api-key': apiKey,
  };

  Future<dynamic> request(String method, String path, {
    Map<String, dynamic>? body,
    Map<String, String>? params,
  }) async {
    var uri = Uri.parse('$baseUrl$path');
    if (params != null && params.isNotEmpty) {
      uri = uri.replace(queryParameters: params);
    }

    late http.Response response;
    final bodyStr = body != null ? jsonEncode(body) : null;

    switch (method) {
      case 'GET':
        response = await _http.get(uri, headers: _headers);
        break;
      case 'POST':
        response = await _http.post(uri, headers: _headers, body: bodyStr);
        break;
      case 'PUT':
        response = await _http.put(uri, headers: _headers, body: bodyStr);
        break;
      case 'DELETE':
        response = await _http.delete(uri, headers: _headers);
        break;
      default:
        throw ArgumentError('Unknown method: $method');
    }

    if (response.statusCode == 204) return null;

    if (response.statusCode >= 400) {
      final err = jsonDecode(response.body) as Map<String, dynamic>;
      throw YppException(
        response.statusCode,
        err['code']?.toString() ?? 'api_error',
        err['message']?.toString() ?? response.reasonPhrase ?? 'Unknown error',
      );
    }

    final data = jsonDecode(response.body);
    if (data is Map && data.containsKey('value')) return data['value'];
    return data;
  }

  Future<dynamic> get(String path, [Map<String, String>? params]) =>
      request('GET', path, params: params);
  Future<dynamic> post(String path, Map<String, dynamic> body) =>
      request('POST', path, body: body);
  Future<dynamic> put(String path, Map<String, dynamic> body) =>
      request('PUT', path, body: body);
  Future<dynamic> delete(String path) =>
      request('DELETE', path);

  void dispose() => _http.close();
}
Payments Service

Create lib/yardpaypro/payments.dart

// lib/yardpaypro/payments.dart

import 'client.dart';

class PaymentsService {
  final YardPayProClient client;
  PaymentsService(this.client);

  /// Pay an invoice with a card or saved funding source
  Future<Map<String, dynamic>> payInvoice({
    int? invoiceId,
    String? invoiceIdentifier,
    required int paymentOptionId,
    int? fundingSourceId,
    Map<String, String>? card,
    Map<String, String>? billingAddress,
  }) async {
    return await client.post('/api/payment/payinvoice', {
      if (invoiceId != null) 'invoiceId': invoiceId,
      if (invoiceIdentifier != null) 'invoiceIdentifier': invoiceIdentifier,
      'paymentOptionId': paymentOptionId,
      if (fundingSourceId != null) 'fundingSourceId': fundingSourceId,
      if (card != null) 'card': card,
      if (billingAddress != null) 'billingAddress': billingAddress,
    });
  }

  /// Get available payment methods for an invoice
  Future<List<dynamic>> getPaymentMethods(int invoiceId) async {
    return await client.get('/v1/invoice/$invoiceId/PaymentMethods');
  }

  /// List saved funding sources
  Future<List<dynamic>> getFundingSources() async {
    return await client.get('/v1/FundingSource');
  }

  /// Register a new card
  Future<Map<String, dynamic>> registerCard({
    required Map<String, String> card,
    required String name,
  }) async {
    return await client.post('/v1/payment/RegisterCard', {
      'card': card,
      'name': name,
    });
  }

  /// Verify a registered card
  Future<void> verifyCard(int fundingSourceId, String code) async {
    await client.post('/v1/fundingSource/$fundingSourceId/verify', {
      'VerificationCode': code,
    });
  }
}
Invoices Service

Create lib/yardpaypro/invoices.dart

// lib/yardpaypro/invoices.dart

import 'client.dart';

class InvoicesService {
  final YardPayProClient client;
  InvoicesService(this.client);

  /// Get invoice by public reference code (no auth needed)
  Future<Map<String, dynamic>> getByReference(String code) async {
    return await client.get("/v1/invoice/getByReference(code='$code')");
  }

  /// Get invoice by ID
  Future<Map<String, dynamic>> getById(int id, {String? expand}) async {
    return await client.get(
      '/v1/invoice/$id',
      expand != null ? {'\$expand': expand} : null,
    );
  }

  /// List invoices with OData filtering
  Future<List<dynamic>> list({
    String? filter,
    String? orderBy,
    int top = 20,
    int skip = 0,
  }) async {
    return await client.get('/v1/invoice', {
      if (filter != null) '\$filter': filter,
      if (orderBy != null) '\$orderby': orderBy,
      '\$top': top.toString(),
      '\$skip': skip.toString(),
    });
  }

  /// Create a new invoice
  Future<Map<String, dynamic>> create(Map<String, dynamic> data) async {
    return await client.post('/v1/invoice', data);
  }

  /// Get QR code URL for an invoice
  String getQrCodeUrl(String identifier) {
    return '${client.baseUrl}/v1/invoice/qrcode/$identifier';
  }

  /// Check if an invoice can be paid
  bool canBePaid(Map<String, dynamic> invoice) {
    const payable = ['Pending', 'Sent', 'PartiallyPaid', 'Overdue'];
    return payable.contains(invoice['status']);
  }
}
Usage in a Flutter Widget
import 'package:flutter/material.dart';
import 'yardpaypro/client.dart';
import 'yardpaypro/payments.dart';
import 'yardpaypro/invoices.dart';

class PaymentScreen extends StatefulWidget {
  final String invoiceCode;
  const PaymentScreen({super.key, required this.invoiceCode});

  @override
  State<PaymentScreen> createState() => _PaymentScreenState();
}

class _PaymentScreenState extends State<PaymentScreen> {
  final _client = YardPayProClient(apiKey: 'sk_test_YOUR_KEY', baseUrl: 'https://your-server.com');
  late final _payments = PaymentsService(_client);
  late final _invoices = InvoicesService(_client);

  Map<String, dynamic>? _invoice;
  bool _loading = true;
  String? _error;

  @override
  void initState() {
    super.initState();
    _loadInvoice();
  }

  Future<void> _loadInvoice() async {
    try {
      final invoice = await _invoices.getByReference(widget.invoiceCode);
      setState(() { _invoice = invoice; _loading = false; });
    } on YppException catch (e) {
      setState(() { _error = e.message; _loading = false; });
    }
  }

  Future<void> _pay() async {
    if (_invoice == null) return;
    setState(() => _loading = true);
    try {
      final result = await _payments.payInvoice(
        invoiceIdentifier: _invoice!['identifier'],
        paymentOptionId: 1,
        card: {
          'name': 'Test User',
          'cardNumber': '4111111111111111',
          'expiryDate': '12/28',
          'cvv': '123',
        },
      );

      if (result['isSuccess'] == true) {
        if (mounted) {
          ScaffoldMessenger.of(context).showSnackBar(
            SnackBar(content: Text('Paid: ${result["referenceNumber"]}')),
          );
        }
      }
    } on YppException catch (e) {
      setState(() { _error = e.message; _loading = false; });
    }
  }

  @override
  void dispose() {
    _client.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    if (_loading) return const Center(child: CircularProgressIndicator());
    if (_error != null) return Center(child: Text('Error: $_error'));

    return Scaffold(
      appBar: AppBar(title: const Text('Pay Invoice')),
      body: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(_invoice!['description'] ?? 'Invoice', style: Theme.of(context).textTheme.titleLarge),
            const SizedBox(height: 8),
            Text('${_invoice!["currencyCode"]} ${_invoice!["totalCost"]}',
                style: Theme.of(context).textTheme.headlineMedium),
            const Spacer(),
            SizedBox(
              width: double.infinity,
              child: ElevatedButton(
                onPressed: _pay,
                child: const Text('Pay Now'),
              ),
            ),
          ],
        ),
      ),
    );
  }
}
Requirements
  • Dart 3.0+ / Flutter 3.10+
  • Only dependency: http (included with Flutter)
  • Works on iOS, Android, Web, macOS, Windows, Linux