Flutter

A shop app in Dart.

pubspec.yaml
dependencies:
  http: ^1.2.0
  uuid: ^4.4.0
lib/cashiar.dart
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:uuid/uuid.dart';

class CashiarException implements Exception {
  CashiarException(this.status, this.message);
  final int status;
  final String message;
  @override
  String toString() => message;
}

class Cashiar {
  Cashiar(this.key);
  final String key;
  static const _base = 'https://api.cashiar.app/v1/storefront';

  Future<Map<String, dynamic>> _call(String method, String path,
      {Map<String, dynamic>? body, String? idempotencyKey}) async {
    final uri = Uri.parse('$_base$path');
    final headers = {
      'Authorization': 'Bearer $key',
      if (body != null) 'Content-Type': 'application/json',
      if (idempotencyKey != null) 'Idempotency-Key': idempotencyKey,
    };
    final res = method == 'GET'
        ? await http.get(uri, headers: headers)
        : await http.post(uri, headers: headers, body: jsonEncode(body));
    final data = jsonDecode(res.body) as Map<String, dynamic>;
    if (res.statusCode >= 400) {
      throw CashiarException(res.statusCode, data['message'].toString());
    }
    return data;
  }

  Future<Map<String, dynamic>> shop() => _call('GET', '/shop');
  Future<Map<String, dynamic>> products({String? collection, String? cursor}) =>
      _call('GET', '/products?${Uri(queryParameters: {
        if (collection != null) 'collection': collection,
        if (cursor != null) 'cursor': cursor,
      }).query}');
  Future<Map<String, dynamic>> placeOrder(Map<String, dynamic> order,
          {String? idempotencyKey}) =>
      _call('POST', '/orders',
          body: order, idempotencyKey: idempotencyKey ?? const Uuid().v4());
  Future<Map<String, dynamic>> order(String id) => _call('GET', '/orders/$id');
}
Placing an order
final api = Cashiar('pk_live_your_key');
final placed = await api.placeOrder({
  'customerName': 'Kojo Mensah',
  'customerPhone': '024 555 0199',
  'fulfilment': 'pickup',
  'lines': [
    {'variantId': '1db29704-09ee-4aa3-95cc-c424173e6d5a', 'quantity': 2},
  ],
});
// Show placed['number']; open placed['payUrl'] in the browser when it is set.

Amounts are minor units: format sellingPrice / 100 with the shop's currency (NumberFormat.simpleCurrency(name: 'GHS') from package:intl).