From ea22f4e9d7a1e088819f3e0a41c4bf34c514025b Mon Sep 17 00:00:00 2001
From: Luigi Morel <morelmiles@gmail.com>
Date: Fri, 15 Apr 2022 03:50:01 +0300
Subject: [PATCH 01/13] add the remittances class

---
 src/remittances.ts | 185 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 185 insertions(+)
 create mode 100644 src/remittances.ts

diff --git a/src/remittances.ts b/src/remittances.ts
new file mode 100644
index 0000000..4f611e0
--- /dev/null
+++ b/src/remittances.ts
@@ -0,0 +1,185 @@
+import { AxiosInstance } from "axios";
+import {v4 as uuid} from "uuid";
+
+import { getTransactionError } from "./errors";
+import { validateRemittance } from "./validate";
+
+import { Balance,
+  FailureReason,
+  PartyIdType,
+  TransactionStatus
+ } from "./common";
+
+export interface RemittanceRequest {
+  /**
+   * Unique Transfer Reference (UUID v4), will be automatically generated if not explicitly supplied
+   */
+
+  referenceId?: string;
+  /**
+   * Amount that will be debited from the payer account.
+   */
+  amount: string;
+
+  /**
+   * ISO4217 Currency
+   */
+  currency: string;
+
+  /**
+   * External id is used as a reference to the transaction.
+   * External id is used for reconciliation.
+   * The external id will be included in transaction history report.
+   * External id is not required to be unique.
+   */
+  externalId?: string;
+
+  /**
+   * Party identifies an account holder in the wallet platform.
+   * Party consists of two parameters, type and partyId.
+   * Each type have its own validation of the partyId
+   *   MSISDN - Mobile Number validated according to ITU-T E.164. Validated with IsMSISDN
+   *   EMAIL - Validated to be a valid e-mail format. Validated with IsEmail
+   *   PARTY_CODE - UUID of the party. Validated with IsUuid
+   */
+  payee: {
+    partyIdType: PartyIdType;
+    partyId: string;
+  };
+
+  /**
+   * Message that will be written in the payer transaction history message field.
+   */
+  payerMessage?: string;
+  /**
+   * Message that will be written in the payee transaction history note field.
+   */
+  payeeNote?: string;
+  /**
+   * URL to the server where the callback should be sent.
+   */
+  callbackUrl?: string;
+}
+
+export interface Remit {
+  /**
+   * Amount that will be debited from the payer account.
+   */
+ amount: string;
+
+  /**
+   * Financial transactionIdd from mobile money manager.
+   * Used to connect to the specific financial transaction made in the account
+   */
+ financialTransactionId: string;
+  /**
+   * ISO4217 Currency
+   */
+ currency: string;
+
+  /**
+   * External id is used as a reference to the transaction.
+   * External id is used for reconciliation.
+   * The external id will be included in transaction history report.
+   * External id is not required to be unique.
+   */
+ externalId: string;
+
+  /**
+   * Party identifies a account holder in the wallet platform.
+   * Party consists of two parameters, type and partyId.
+   * Each type have its own validation of the partyId
+   *   MSISDN - Mobile Number validated according to ITU-T E.164. Validated with IsMSISDN
+   *   EMAIL - Validated to be a valid e-mail format. Validated with IsEmail
+   *   PARTY_CODE - UUID of the party. Validated with IsUuid
+   */
+ payee: {
+   partyIdType: "MSISDN";
+    partyId: string;
+ };
+
+ status: TransactionStatus;
+ reason?: FailureReason;
+
+}
+
+export default class Remittances {
+  private client: AxiosInstance;
+
+  constructor(client: AxiosInstance) {
+    this.client = client;
+ }
+
+ /**
+  * Remit operation to send funds to local recipients from the diaspora
+  * from the owner's account to the payee's account
+  *
+  * @param remittanceRequest
+  */
+  public remit({
+    callbackUrl,
+    referenceId= uuid(),
+    ...remittanceRequest
+  }: RemittanceRequest): Promise<string> {
+
+    return validateRemittance({referenceId, ...remittanceRequest}).then(() => {
+      return this.client
+        .post<void>("/remittance/v1_0/transfer", remittanceRequest, {
+          headers: {
+            "X-Reference-Id": referenceId,
+              ...(callbackUrl ? { "X-Callback-Url": callbackUrl } : {})
+           }
+        })
+      .then(() => referenceId);
+     });
+  }
+
+  /**
+   * This method is used to retrieve the transaction. You can invoke this method
+   * to at intervals until your transaction fails or succeeds.
+   *
+   * If the transaction has failed, it will throw an appropriate error. The error will be a subclass
+   * of `MtnMoMoError`. Check [`src/error.ts`](https://github.com/sparkplug/momoapi-node/blob/master/src/errors.ts)
+   * for the various errors that can be thrown
+   *
+   * @param referenceId the value returned from `remit`
+   */
+  public getTransaction( referenceId: string): Promise<Remit> {
+    return this.client.get<Remit>(`/remittance/v1_0/transfer/${referenceId}`)
+    .then(response => response.data)
+    .then(transaction => {
+      if (transaction.status === TransactionStatus.FAILED) {
+        return Promise.reject(getTransactionError(transaction));
+    }
+
+      return Promise.resolve(transaction);
+    });
+  }
+
+  /**
+   * Get the balance of the account.
+   */
+  public getBalance(): Promise<Balance> {
+    return this.client
+      .get<Balance>("/remittance/v1_0/account/balance")
+     .then(response => response.data);
+  }
+
+  /**
+   * This method is used to check if an account holder is registered and active in the system.
+   *
+   * @param id Specifies the type of the party ID. Allowed values [msisdn, email, party_code].
+   *   accountHolderId should explicitly be in small letters.
+   *
+   * @param type The party number. Validated according to the party ID type (case Sensitive).
+   *   msisdn - Mobile Number validated according to ITU-T E.164. Validated with IsMSISDN
+   *   email - Validated to be a valid e-mail format. Validated with IsEmail
+   *   party_code - UUID of the party. Validated with IsUuid
+   */
+  public isPayerActive(id: string, type: PartyIdType = PartyIdType.MSISDN): Promise<boolean> {
+    return this.client
+      .get<{result: boolean}>(`/remittance/v1_0/accountholder/${String(type).toLowerCase()}/${id}/active`)
+      .then(response => response.data)
+      .then(data => data.result ? data.result : false);
+  }
+}

From 7aa75fa82f73cf2c72e2acfef97757bcbe3ff769 Mon Sep 17 00:00:00 2001
From: Luigi Morel <morelmiles@gmail.com>
Date: Fri, 15 Apr 2022 03:50:49 +0300
Subject: [PATCH 02/13] add the remittances class tests

---
 test/remittances.test.ts | 159 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 159 insertions(+)
 create mode 100644 test/remittances.test.ts

diff --git a/test/remittances.test.ts b/test/remittances.test.ts
new file mode 100644
index 0000000..972f594
--- /dev/null
+++ b/test/remittances.test.ts
@@ -0,0 +1,159 @@
+import { AxiosInstance } from "axios";
+import MockAdapter from "axios-mock-adapter";
+import { expect } from "chai";
+
+import Remittances from "../src/remittances";
+
+import { createMock } from "./mock";
+
+import { PartyIdType } from "../src/common";
+import {RemittanceRequest} from "./../src/remittances";
+
+describe("Remittances", function() {
+  let remittances: Remittances;
+  let mockAdapter: MockAdapter;
+  let mockClient: AxiosInstance;
+
+  beforeEach(() => {
+    [mockClient, mockAdapter] = createMock();
+    remittances = new Remittances(mockClient);
+  });
+
+  describe("remit", function() {
+    context("when the amount is missing", function() {
+      it("throws an error", function() {
+        const request = {} as RemittanceRequest;
+        return expect(remittances.remit(request)).to.be.rejectedWith(
+          "amount is required"
+        );
+      });
+    });
+
+    context("when the amount is not numeric", function() {
+      it("throws an error", function() {
+        const request = { amount: "alphabetic" } as RemittanceRequest;
+        return expect(remittances.remit(request)).to.be.rejectedWith(
+          "amount must be a number"
+        );
+      });
+    });
+
+    context("when the currency is missing", function() {
+      it("throws an error", function() {
+        const request = {
+          amount: "1000"
+        } as RemittanceRequest;
+        return expect(remittances.remit(request)).to.be.rejectedWith(
+          "currency is required"
+        );
+      });
+    });
+
+    context("when the payee is missing", function() {
+      it("throws an error", function() {
+        const request = {
+          amount: "1000",
+          currency: "UGX"
+        } as RemittanceRequest;
+        return expect(remittances.remit(request)).to.be.rejectedWith(
+          "payee is required"
+        );
+      });
+    });
+
+    context("when the party id is missing", function() {
+      it("throws an error", function() {
+        const request = {
+          amount: "1000",
+          currency: "UGX",
+          payee: {
+          }
+        } as RemittanceRequest;
+        return expect(remittances.remit(request)).to.be.rejectedWith(
+          "payee.partyId is required"
+        );
+      });
+    });
+
+    context("when the party id type is missing", function() {
+      it("throws an error", function() {
+        const request = {
+          amount: "1000",
+          currency: "UGX",
+          payee: {
+            partyId: "xxx",
+          }
+        } as RemittanceRequest;
+        return expect(remittances.remit(request)).to.be.rejectedWith(
+          "payee.partyIdType is required"
+        );
+      });
+    });
+
+    it("makes the correct request", function() {
+      const request: RemittanceRequest = {
+        amount: "50",
+        currency: "EUR",
+        externalId: "123456",
+        payee: {
+          partyIdType: PartyIdType.MSISDN,
+          partyId: "256774290781"
+        },
+        payerMessage: "testing",
+        payeeNote: "hello"
+      };
+      return expect(
+        remittances.remit({ ...request, callbackUrl: "callback url" })
+      ).to.be.fulfilled.then(() => {
+        expect(mockAdapter.history.post).to.have.lengthOf(1);
+        expect(mockAdapter.history.post[0].url).to.eq(
+          "/remittance/v1_0/transfer"
+        );
+        expect(mockAdapter.history.post[0].data).to.eq(JSON.stringify(request));
+        expect(mockAdapter.history.post[0].headers["X-Reference-Id"]).to.be.a(
+          "string"
+        );
+        expect(mockAdapter.history.post[0].headers["X-Callback-Url"]).to.eq(
+          "callback url"
+        );
+      });
+    });
+  });
+
+  describe("getTransaction", function() {
+    it("makes the correct request", function() {
+      return expect(
+        remittances.getTransaction("reference")
+      ).to.be.fulfilled.then(() => {
+        expect(mockAdapter.history.get).to.have.lengthOf(1);
+        expect(mockAdapter.history.get[0].url).to.eq(
+          "/remittance/v1_0/transfer/reference"
+        );
+      });
+    });
+  });
+
+  describe("getBalance", function() {
+    it("makes the correct request", function() {
+      return expect(remittances.getBalance()).to.be.fulfilled.then(() => {
+        expect(mockAdapter.history.get).to.have.lengthOf(1);
+        expect(mockAdapter.history.get[0].url).to.eq(
+          "/remittance/v1_0/account/balance"
+        );
+      });
+    });
+  });
+
+  describe("isPayerActive", function() {
+    it("makes the correct request", function() {
+      return expect(
+        remittances.isPayerActive("0772000000", PartyIdType.MSISDN)
+      ).to.be.fulfilled.then(() => {
+        expect(mockAdapter.history.get).to.have.lengthOf(1);
+        expect(mockAdapter.history.get[0].url).to.eq(
+          "/remittance/v1_0/accountholder/msisdn/0772000000/active"
+        );
+      });
+    });
+  });
+});

From 022c104dbfa1e6a6028f9a254fac3cdbe8ac809c Mon Sep 17 00:00:00 2001
From: Luigi Morel <morelmiles@gmail.com>
Date: Fri, 15 Apr 2022 03:53:07 +0300
Subject: [PATCH 03/13] add auth for the remittance operation

---
 src/auth.ts | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/src/auth.ts b/src/auth.ts
index 9d07ea2..e5f5252 100644
--- a/src/auth.ts
+++ b/src/auth.ts
@@ -70,6 +70,20 @@ export const authorizeDisbursements: Authorizer = function(
     .then(response => response.data);
 };
 
+export const authorizeRemittances: Authorizer = function(
+  config: Config,
+  client: AxiosInstance = createClient(config)
+): Promise<AccessToken> {
+  const basicAuthToken: string = createBasicAuthToken(config);
+  return client
+    .post<AccessToken>("/remittance/token/", null, {
+      headers: {
+        Authorization: `Basic ${basicAuthToken}`
+      }
+    })
+    .then(response => response.data);
+};
+
 export function createBasicAuthToken(config: UserConfig): string {
   return Buffer.from(`${config.userId}:${config.userSecret}`).toString(
     "base64"

From f2d2a8b9eda63b2d4d86b09be60f3aa787e55735 Mon Sep 17 00:00:00 2001
From: Luigi Morel <morelmiles@gmail.com>
Date: Fri, 15 Apr 2022 03:54:04 +0300
Subject: [PATCH 04/13] add tests for auth - remittance operation

---
 test/auth.test.ts | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/test/auth.test.ts b/test/auth.test.ts
index 58c1d7e..804854c 100644
--- a/test/auth.test.ts
+++ b/test/auth.test.ts
@@ -5,6 +5,7 @@ import { expect } from "./chai";
 import {
   authorizeCollections,
   authorizeDisbursements,
+  authorizeRemittances,
   createBasicAuthToken,
   createTokenRefresher
 } from "../src/auth";
@@ -85,6 +86,21 @@ describe("Auth", function() {
     });
   });
 
+  describe("authorizeRemittances", function() {
+    it("makes the correct request", function() {
+      const [mockClient, mockAdapter] = createMock();
+      return expect(
+        authorizeRemittances(config, mockClient)
+      ).to.be.fulfilled.then(() => {
+        expect(mockAdapter.history.post).to.have.lengthOf(1);
+        expect(mockAdapter.history.post[0].url).to.eq("/remittance/token/");
+        expect(mockAdapter.history.post[0].headers.Authorization).to.eq(
+          "Basic " + Buffer.from("id:secret").toString("base64")
+        );
+      });
+    });
+  });  
+
   describe("createBasicAuthToken", function() {
     it("encodes id and secret in base64", function() {
       expect(

From 7c9ac8df02f38b0d9619ca9f75049ae3a0e07636 Mon Sep 17 00:00:00 2001
From: Luigi Morel <morelmiles@gmail.com>
Date: Fri, 15 Apr 2022 03:55:45 +0300
Subject: [PATCH 05/13] add validation for the remittance operation

---
 src/validate.ts | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/src/validate.ts b/src/validate.ts
index b875983..3857444 100644
--- a/src/validate.ts
+++ b/src/validate.ts
@@ -9,6 +9,7 @@ import {
   UserConfig
 } from "./common";
 import { TransferRequest } from "./disbursements";
+import {RemittanceRequest} from "./remittances";
 
 export function validateRequestToPay(
   paymentRequest: PaymentRequest
@@ -50,6 +51,26 @@ export function validateTransfer(
   });
 }
 
+export function validateRemittance( remittanceRequest: RemittanceRequest
+): Promise<void> {
+  const { amount, currency, payee, referenceId }: RemittanceRequest = remittanceRequest || {};
+  return Promise.resolve().then(() => {
+    strictEqual(isTruthy(referenceId), true, "referenceId is required");
+    strictEqual(isUuid4(referenceId as string), true, "referenceId must be a valid uuid v4");
+    strictEqual(isTruthy(amount), true, "amount is required");
+    strictEqual(isNumeric(amount), true, "amount must be a number");
+    strictEqual(isTruthy(currency), true, "currency is required");
+    strictEqual(isTruthy(payee), true, "payee is required");
+    strictEqual(isTruthy(payee.partyId), true, "payee.partyId is required");
+    strictEqual(
+      isTruthy(payee.partyIdType),
+      true,
+      "payee.partyIdType is required"
+    );
+    strictEqual(isString(currency), true, "amount must be a string");
+  });
+}
+
 export function validateGlobalConfig(config: GlobalConfig): void {
   const { callbackHost, baseUrl, environment } = config;
   strictEqual(isTruthy(callbackHost), true, "callbackHost is required");

From 498ef91d83e254dd864736006fcc2d55a57e5100 Mon Sep 17 00:00:00 2001
From: Luigi Morel <morelmiles@gmail.com>
Date: Fri, 15 Apr 2022 03:57:29 +0300
Subject: [PATCH 06/13] add the remit inteface to error class

---
 src/errors.ts | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/src/errors.ts b/src/errors.ts
index b97024f..e2b3300 100644
--- a/src/errors.ts
+++ b/src/errors.ts
@@ -2,6 +2,7 @@ import { AxiosError } from "axios";
 import { Payment } from "./collections";
 import { FailureReason } from "./common";
 import { Transfer } from "./disbursements";
+import {Remit} from "./remittances";
 
 interface ErrorBody {
   code: FailureReason;
@@ -9,7 +10,7 @@ interface ErrorBody {
 }
 
 export class MtnMoMoError extends Error {
-  public transaction?: Payment | Transfer;
+  public transaction?: Payment | Transfer | Remit;
 
   constructor(message?: string) {
     super(message);
@@ -171,7 +172,7 @@ export function getError(code?: FailureReason, message?: string) {
   return new UnspecifiedError(message);
 }
 
-export function getTransactionError(transaction: Payment | Transfer) {
+export function getTransactionError(transaction: Payment | Transfer | Remit) {
   const error: MtnMoMoError = getError(transaction.reason as FailureReason);
   error.transaction = transaction;
 

From 83febfbefb635d6c34f32a5dcba46214e7fd04d8 Mon Sep 17 00:00:00 2001
From: Luigi Morel <morelmiles@gmail.com>
Date: Fri, 15 Apr 2022 04:00:49 +0300
Subject: [PATCH 07/13] add remittance operation to global config

---
 src/index.ts | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/src/index.ts b/src/index.ts
index 6c4b298..04639a4 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,5 +1,7 @@
 export { Payment, PaymentRequest } from "./collections";
 export { Transfer, TransferRequest } from "./disbursements";
+export { Remit, RemittanceRequest } from "./remittances";
+
 export * from "./errors";
 export {
   PartyIdType as PayerType,
@@ -16,11 +18,13 @@ import { AxiosInstance } from "axios";
 
 import Collections from "./collections";
 import Disbursements from "./disbursements";
+import Remittances from "./remittances";
 import Users from "./users";
 
 import {
   authorizeCollections,
   authorizeDisbursements,
+  authorizeRemittances,
   createTokenRefresher
 } from "./auth";
 import { createAuthClient, createClient } from "./client";
@@ -41,6 +45,7 @@ import {
 export interface MomoClient {
   Collections(productConfig: ProductConfig): Collections;
   Disbursements(productConfig: ProductConfig): Disbursements;
+  Remittances(productConfig: ProductConfig): Remittances;
   Users(subscription: SubscriptionConfig): Users;
 }
 
@@ -89,6 +94,21 @@ export function create(globalConfig: GlobalConfig): MomoClient {
       return new Disbursements(client);
     },
 
+    Remittances(productConfig: ProductConfig): Remittances {
+      const config: Config = {
+        ...defaultGlobalConfig,
+        ...globalConfig,
+        ...productConfig,
+      };
+
+      const client: AxiosInstance = createAuthClient(
+        createTokenRefresher(authorizeRemittances, config),
+        createClient(config)
+      );
+
+      return new Remittances(client);
+    },
+
     Users(subscriptionConfig: SubscriptionConfig): Users {
       validateSubscriptionConfig(subscriptionConfig);
 

From e1b0a50efb20a6971165157ea8f628161978fdd9 Mon Sep 17 00:00:00 2001
From: Luigi Morel <morelmiles@gmail.com>
Date: Fri, 15 Apr 2022 04:01:44 +0300
Subject: [PATCH 08/13] add tests for remittance op. - global config

---
 test/index.test.ts | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/test/index.test.ts b/test/index.test.ts
index fa59087..2715aea 100644
--- a/test/index.test.ts
+++ b/test/index.test.ts
@@ -30,6 +30,12 @@ describe("MomoClient", function() {
           .to.have.property("Disbursements")
           .that.is.a("function");
       });
+
+      it("returns a creator for Remittances client", function() {
+        expect(momo.create({ callbackHost: "example.com" }))
+          .to.have.property("Remittances")
+          .that.is.a("function");
+      });
     });
   });
 });

From 1fc148da49e3480a99b37db5910976f6ed73d5f2 Mon Sep 17 00:00:00 2001
From: Luigi Morel <morelmiles@gmail.com>
Date: Fri, 15 Apr 2022 04:02:52 +0300
Subject: [PATCH 09/13] mock the remittance endpoint

---
 test/mock.ts | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/test/mock.ts b/test/mock.ts
index 21532cd..6d6e772 100644
--- a/test/mock.ts
+++ b/test/mock.ts
@@ -4,6 +4,7 @@ import MockAdapter from "axios-mock-adapter";
 import { Payment } from "../src/collections";
 import { AccessToken, Balance, Credentials } from "../src/common";
 import { Transfer } from "../src/disbursements";
+import {Remit} from "../src/remittances";
 
 export function createMock(): [AxiosInstance, MockAdapter] {
   const client = axios.create({
@@ -84,5 +85,35 @@ export function createMock(): [AxiosInstance, MockAdapter] {
     currency: "UGX"
   } as Balance);
 
+  mock.onPost("/remittance/token/").reply(200, {
+    access_token: "token",
+    token_type: "access_token",
+    expires_in: 3600
+  } as AccessToken);
+
+  mock
+    .onGet(
+      /\/remittance\/v1_0\/accountholder\/(msisdn|email|party_code)\/\w+/
+    )
+    .reply(200, "true");
+
+  mock.onPost("/remittance/v1_0/transfer").reply(201);
+
+  mock.onGet(/\/remittance\/v1_0\/transfer\/[\w\-]+/).reply(200, {
+    financialTransactionId: "tx id",
+    externalId: "string",
+    amount: "2000",
+    currency: "UGX",
+    payee: {
+      partyIdType: "MSISDN",
+      partyId: "256772000000"
+    },
+    status: "SUCCESSFUL"
+  } as Remit);
+
+  mock.onGet("/remittance/v1_0/account/balance").reply(200, {
+    availableBalance: "2000",
+    currency: "UGX"
+  } as Balance);
   return [client, mock];
 }

From fe5f872e049b27d08b561855a45c51d58f9d1d53 Mon Sep 17 00:00:00 2001
From: Luigi Morel <morelmiles@gmail.com>
Date: Fri, 15 Apr 2022 04:03:27 +0300
Subject: [PATCH 10/13] add example for the remittance operation

---
 examples/remittances.js | 51 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 51 insertions(+)
 create mode 100644 examples/remittances.js

diff --git a/examples/remittances.js b/examples/remittances.js
new file mode 100644
index 0000000..3cacf79
--- /dev/null
+++ b/examples/remittances.js
@@ -0,0 +1,51 @@
+const momo = require("../lib");
+
+const { Remittances } = momo.create({ callbackHost: process.env.CALLBACK_HOST });
+
+// initialise collections
+const remittances = Remittances({
+  userSecret: process.env.REMITTANCES_USER_SECRET,
+  userId: process.env.REMITTANCES_USER_ID,
+  primaryKey: process.env.REMITTANCES_PRIMARY_KEY
+});
+
+const partyId = "256776564739";
+const partyIdType = momo.PayerType.MSISDN;
+// Transfer
+remittances
+    .isPayerActive(partyId, partyIdType)
+    .then((isActive) => {
+        console.log("Is Active ? ", isActive);
+        if (!isActive) {
+            return Promise.reject("Party not active");
+        }
+        return remittances.remit({
+            amount: "100",
+            currency: "EUR",
+            externalId: "947354",
+            payee: {
+                partyIdType,
+                partyId
+            },
+            payerMessage: "testing",
+            payeeNote: "hello",
+            callbackUrl: process.env.CALLBACK_URL ? process.env.CALLBACK_URL : "https://75f59b50.ngrok.io"
+        });
+    })
+    
+  .then(transactionId => {
+    console.log({ transactionId });
+
+    // Get transaction status
+    return remittances.getTransaction(transactionId);
+  })
+  .then(transaction => {
+    console.log({ transaction });
+
+    // Get account balance
+    return remittances.getBalance();
+  })
+  .then(accountBalance => console.log({ accountBalance }))
+  .catch(error => {
+    console.log(error);
+  });

From d4f1d197eb8b14799b145b8ee2c3c668067c55bf Mon Sep 17 00:00:00 2001
From: Luigi Morel <morelmiles@gmail.com>
Date: Tue, 19 Apr 2022 09:26:00 +0300
Subject: [PATCH 11/13] reject promise with error, remove ngrok url

---
 examples/remittances.js | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/examples/remittances.js b/examples/remittances.js
index 3cacf79..d71eaab 100644
--- a/examples/remittances.js
+++ b/examples/remittances.js
@@ -17,7 +17,7 @@ remittances
     .then((isActive) => {
         console.log("Is Active ? ", isActive);
         if (!isActive) {
-            return Promise.reject("Party not active");
+            return Promise.reject( new Error("Party not active"));
         }
         return remittances.remit({
             amount: "100",
@@ -29,7 +29,7 @@ remittances
             },
             payerMessage: "testing",
             payeeNote: "hello",
-            callbackUrl: process.env.CALLBACK_URL ? process.env.CALLBACK_URL : "https://75f59b50.ngrok.io"
+            callbackUrl: process.env.CALLBACK_URL
         });
     })
     

From 444010261cf2dd2fbb0a74ef1badd55dfa96bf35 Mon Sep 17 00:00:00 2001
From: Luigi Morel <morelmiles@gmail.com>
Date: Wed, 20 Apr 2022 12:44:18 +0300
Subject: [PATCH 12/13] fix: remove type coercion

---
 src/validate.ts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/validate.ts b/src/validate.ts
index 3857444..fc183e5 100644
--- a/src/validate.ts
+++ b/src/validate.ts
@@ -56,7 +56,7 @@ export function validateRemittance( remittanceRequest: RemittanceRequest
   const { amount, currency, payee, referenceId }: RemittanceRequest = remittanceRequest || {};
   return Promise.resolve().then(() => {
     strictEqual(isTruthy(referenceId), true, "referenceId is required");
-    strictEqual(isUuid4(referenceId as string), true, "referenceId must be a valid uuid v4");
+    strictEqual(isUuid4(referenceId), true, "referenceId must be a valid uuid v4");
     strictEqual(isTruthy(amount), true, "amount is required");
     strictEqual(isNumeric(amount), true, "amount must be a number");
     strictEqual(isTruthy(currency), true, "currency is required");

From 74fc4f5aa68186679d6db8de99e711ad54aa6eb3 Mon Sep 17 00:00:00 2001
From: Luigi Morel <morelmiles@gmail.com>
Date: Wed, 20 Apr 2022 12:45:26 +0300
Subject: [PATCH 13/13] fix:changes referenceId type to strictly string

---
 src/remittances.ts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/remittances.ts b/src/remittances.ts
index 4f611e0..c4349ba 100644
--- a/src/remittances.ts
+++ b/src/remittances.ts
@@ -15,7 +15,7 @@ export interface RemittanceRequest {
    * Unique Transfer Reference (UUID v4), will be automatically generated if not explicitly supplied
    */
 
-  referenceId?: string;
+  referenceId: string;
   /**
    * Amount that will be debited from the payer account.
    */