public async Task SendPaymentRequest()
        {
            // Create two agent hosts and establish pairwise connection between them
            var agents = await InProcAgent.CreatePairedAsync(true);

            // Get each agent payment address records
            var paymentAddress1 = await agents.Agent1.Payments.GetDefaultPaymentAddressAsync(agents.Agent1.Context);

            var paymentAddress2 = await agents.Agent2.Payments.GetDefaultPaymentAddressAsync(agents.Agent2.Context);

            // Internal reference number for this payment
            const string paymentReference = "INVOICE# 0001";

            // Setup a basic use case for payments by using basic messages
            // Any AgentMessage can be used to attach payment requests and receipts
            var basicMessage = new BasicMessage {
                Content = "This is payment request"
            };

            // Attach the payment request to the agent message
            var paymentRecord1 = await agents.Agent1.Payments.AttachPaymentRequestAsync(
                context : agents.Agent1.Context,
                agentMessage : basicMessage,
                details : new PaymentDetails
            {
                Id    = paymentReference,
                Items = new List <PaymentItem>
                {
                    new PaymentItem {
                        Label = "Item 1", Amount = 8
                    },
                    new PaymentItem {
                        Label = "Tax", Amount = 2
                    }
                },
                Total = new PaymentItem
                {
                    Amount = new PaymentAmount
                    {
                        Currency = "sov",
                        Value    = 10
                    },
                    Label = "Total"
                }
            },
                payeeAddress : paymentAddress1);

            // PaymentRecord expectations
            Assert.NotNull(paymentRecord1);
            Assert.Equal(10UL, paymentRecord1.Amount);
            Assert.Equal(paymentAddress1.Address, paymentRecord1.Address);
            Assert.Equal(PaymentState.Requested, paymentRecord1.State);

            // Ensure the payment request is attached to the message
            var decorator = basicMessage.FindDecorator <PaymentRequestDecorator>("payment_request");

            Assert.NotNull(decorator);

            // Send the message to agent 2
            await agents.Agent1.Messages.SendAsync(agents.Agent1.Context.Wallet, basicMessage, agents.Connection1);

            // Find the payment record in the context of agent 2
            var search = await agents.Agent2.Records.SearchAsync <PaymentRecord>(
                wallet : agents.Agent2.Context.Wallet,
                query : SearchQuery.And(
                    SearchQuery.Equal(nameof(PaymentRecord.ReferenceId), paymentReference),
                    SearchQuery.Equal(nameof(PaymentRecord.ConnectionId), agents.Connection2.Id)));

            var paymentRecord2 = search.FirstOrDefault();

            Assert.Single(search);
            Assert.NotNull(paymentRecord2);
            Assert.Equal(PaymentState.RequestReceived, paymentRecord2.State);

            // Fund payment address of agent 2 so we can make payment to agent 1
            await FundAccountAsync(50UL, paymentAddress2.Address);

            // Refresh balance to ensure it is funded correctly
            await agents.Agent2.Payments.RefreshBalanceAsync(agents.Agent2.Context, paymentAddress2);

            Assert.Equal(50UL, paymentAddress2.Balance);

            // Make payment for received request
            await agents.Agent2.Payments.MakePaymentAsync(agents.Agent2.Context, paymentRecord2, paymentAddress2);

            Assert.Equal(PaymentState.Paid, paymentRecord2.State);
            Assert.Equal(40UL, paymentAddress2.Balance);
            Assert.NotNull(paymentRecord2.ReceiptId);

            // Send a basic message back to agent 1 and attach a payment receipt
            var message2 = new BasicMessage {
                Content = "Here's a receipt"
            };

            // Attach a payment receipt to the basic message
            // Receipts can be attached to any agent message
            agents.Agent2.Payments.AttachPaymentReceipt(agents.Agent2.Context, message2, paymentRecord2);

            // Send the message to agent 1
            await agents.Agent2.Messages.SendAsync(agents.Agent2.Context.Wallet, message2, agents.Connection2);

            // Fetch payment record 1 again, to refresh state
            paymentRecord1 = await agents.Agent1.Records.GetAsync <PaymentRecord>(agents.Agent1.Context.Wallet, paymentRecord1.Id);

            // Check payment record 1 for receipt

            Assert.Equal(PaymentState.ReceiptReceived, paymentRecord1.State);
            Assert.NotNull(paymentRecord1.ReceiptId);

            // Check agent 1 balance
            await agents.Agent1.Payments.RefreshBalanceAsync(agents.Agent1.Context, paymentAddress1);

            Assert.Equal(10UL, paymentAddress1.Balance);

            // Verify the payment receipt on the ledger
            var verified = await agents.Agent1.Payments.VerifyPaymentAsync(agents.Agent1.Context, paymentRecord1);

            Assert.True(verified);

            // Clean things up and shut down hosts gracefully
            await agents.Agent1.DisposeAsync();

            await agents.Agent2.DisposeAsync();
        }