LittleFish Payments Cloud POS Receiver

Cloud POS receiver package — enables POS terminals to receive and process push-payment requests from companion devices via Terminal Manager SignalR events.

Overview

This package provides the receiving side of the Cloud POS payment flow. While littlefish_payments_cloud_pos handles the sending side (companion device staging transactions), this package handles the POS terminal side: listening for incoming payment requests, decoding them, processing card payments through the local hardware, and reporting results back.

The package is designed to be consumed by both the full merchant app and a lightweight POS application, with hardware-specific card reader integration provided by the host app via the abstract PaymentDeviceAdapter.

Architecture

Terminal Manager (SignalR Hub)
  -> TerminalManagerSignalRClient (this package)
    -> TransactionPayloadDecoder (base64 -> ReceivedTransaction)
    -> CloudPosReceiver (orchestrator)
      -> PaymentDeviceAdapter (host app provides implementation)
        -> Physical Card Reader (AR, Verifone, PAX, etc.)
      -> ResultReporter (HTTP POST back to Terminal Manager)

Components

Receiver

  • CloudPosReceiver — Core orchestrator. Connects to Terminal Manager, receives PushSaleV1 events, decodes payloads, processes card payments via the adapter, and reports results. Exposes a stateStream for UI binding.

Models

  • ReceivedTransaction — Equatable model representing a decoded transaction payload with amount, currency, order reference, and business ID.
  • PaymentDeviceAdapter — Abstract adapter for hardware-specific card reader integration. Host app provides the concrete implementation.
  • PaymentDeviceResult — Result of processing a card payment (approved/declined/error) with acquirer details.
  • ReceiverConfig — Configuration for Terminal Manager URL, terminal ID, business ID, auth token, and timeouts.
  • ReceiverState — Immutable state object tracking receiver status, current transaction, and last result.

Services

  • TerminalManagerSignalRClient — Abstraction over the SignalR connection to Terminal Manager. Supports both standalone connection and shared connection (when the host app already has a SignalR connection).
  • TransactionPayloadDecoder — Decodes base64-encoded transaction payloads from PushSaleV1 CloudEvents into ReceivedTransaction objects.
  • ResultReporter — HTTP client for sending UpdateSale results back to Terminal Manager.

Presentation

  • PaymentRequestPage — Full-screen page shown when a payment request is received. Displays amount and "Process Payment" / "Decline" buttons.
  • PaymentProcessingPage — Full-screen page shown during card processing. Displays status, progress, and final result (approved/declined/error).
  • PaymentAmountDisplay — Reusable widget for displaying payment amounts with currency formatting.
  • CardReaderStatus — Reusable widget for displaying card reader status with icons and animations.

Usage

Basic Setup

import 'package:littlefish_payments_cloud_pos_receiver/littlefish_payments_cloud_pos_receiver.dart';

// 1. Create configuration
final config = ReceiverConfig(
  terminalManagerBaseUrl: 'https://terminal-manager.littlefish.app',
  terminalId: 'TM-001',
  businessId: 'BUS-001',
  authToken: authService.currentToken,
);

// 2. Provide a card reader adapter (hardware-specific)
final adapter = MyCardReaderAdapter(); // extends PaymentDeviceAdapter

// 3. Create and initialise receiver
final receiver = CloudPosReceiver(
  config: config,
  deviceAdapter: adapter,
  logger: loggerService,
);

// 4. Listen for state changes (bind to UI)
receiver.stateStream.listen((state) {
  switch (state.status) {
    case ReceiverStatus.idle:
      // Show idle screen
      break;
    case ReceiverStatus.paymentReceived:
      // Navigate to PaymentRequestPage
      break;
    case ReceiverStatus.waitingForCard:
    case ReceiverStatus.processingCard:
      // Navigate to PaymentProcessingPage
      break;
    case ReceiverStatus.completed:
      // Show result
      break;
    default:
      break;
  }
});

// 5. Start listening for payment requests
await receiver.initialise();

Shared SignalR Connection

If the host app already has a SignalR connection to Terminal Manager:

// Forward events from existing connection
receiver.signalRClient.registerExternalEventHandler(
  pushSaleEvents: existingConnection.pushSaleStream,
  cancelSaleEvents: existingConnection.cancelSaleStream,
);

Custom Card Reader Adapter

class ArPaymentDeviceAdapter extends PaymentDeviceAdapter {
  @override
  Future<PaymentDeviceResult> processCardPayment(
    ReceivedTransaction transaction,
  ) async {
    final arResult = await ArSdk.processPayment(
      amount: transaction.amountMinorUnits,
      currency: transaction.currencyCode,
    );
    return PaymentDeviceResult(
      approved: arResult.isApproved,
      statusCode: arResult.responseCode,
      statusMessage: arResult.responseMessage,
    );
  }

  @override
  Future<bool> isReady() => ArSdk.isReaderConnected();

  @override
  Future<void> cancelPayment() => ArSdk.cancelCurrentTransaction();

  @override
  Future<bool> printReceipt(
    ReceivedTransaction transaction,
    PaymentDeviceResult result,
  ) async {
    await ArSdk.printReceipt(result.toJson());
    return true;
  }
}

Dependencies

  • littlefish_core ^6.1.2 — LoggerService
  • littlefish_core_utils ^4.7.5 — LittleFishHttpClient
  • equatable ^2.0.7 — Value equality for models
  • json_annotation ^4.9.0 — JSON serialization
  • Sender Package: littlefish_payments_cloud_pos — companion device side
  • Backend API: littlefish.CloudPos service in littlefish_core_api (PR #192)
  • Spec: CPOS-SPEC_001 §6.4 in littlefish_ai_planning