Javascript SDK V0
MoneyHash Javascript SDK that supports rendering different payment methods while showing forms in an iframe.
Integrating
After installing MoneyHash's Javascript SDK into your application, you can start the integration. Below, you will find the essential steps to use this integration:
-
First, create an
intent
with the Payment intent endpoint. This step does not use MoneyHash's Javascript SDK and is standard for all MoneyHash's integrations, except for HPP. This endpoint requires authentication to be executed properly. You need to provide the Account API Key as a header and send the required data in the request body. Check the Create an Intent page for further explanation.
- Create a moneyHash instance using
MoneyHash
constructor. At this step, you need to define whether you will create a payment or a payout.
import MoneyHash from "@moneyhash/js-sdk/headless";
const moneyHash = new MoneyHash({ type: "payment" | "payout" });
- Get intent details: Calling the
getIntentDetails
method with theintent_id
from theintent
created at Step 1 as the parameter, you can access your intent details. Thestate
returned can guide you through the actions and methods required to proceed and complete the payment or payout. The table below describes each action related to each possiblestate
value.
moneyHash
.getIntentDetails("<intent_id>")
.then(({ intent, transaction, selectedMethod, redirect, state }) => {
console.log({ intent, transaction, selectedMethod, redirect, state });
});
state | Action |
---|---|
METHOD_SELECTION | Use moneyHash.getIntentMethods to get the different payment methods available for the intent. You can render them natively with your own styles and use moneyHash.proceedWith to proceed with one of them after the user selection. |
INTENT_FORM | Use moneyHash.renderForm to render the SDK embed to let MoneyHash handle the payments for you. Use the available onComplete and onFail callbacks on the MoneyHash instance to track the end of the process. |
INTENT_PROCESSED | Render your successful confirmation UI with the intent details. |
TRANSACTION_FAILED | Render your failure UI with the intent details. |
TRANSACTION_WAITING_USER_ACTION | Render your pending actions confirmation UI with the intent details and externalActionMessage if exists on Transaction . |
EXPIRED | Render your intent expired UI. |
CLOSED | Render your intent closed UI. |
Render SDK embed forms and payment integrations
If the state
returned is INTENT_FORM
you need to call the renderForm
method to let MoneyHash handle the payment/payout. You need to provide the CSS selector to define where to
render the forms and the intent identifier.
await moneyHash.renderForm({
selector: "<container_css_selector>",
intentId: "<intent_id>",
});
- Get intent methods: To access the available pay-in/pay-out methods, saved cards, and customer balances, call the
getIntentMethods
sending theintent_id
as the parameter. For example, you could use this information to predefine a payment method. Or choose whichpaymentMethods
to display to give the customer the option to choose their preferred method.
moneyHash
.getIntentMethods("<intent_id>")
.then(({ paymentMethods, expressMethods, savedCards, customerBalances }) => {
console.log({
paymentMethods,
expressMethods,
savedCards,
customerBalances,
});
});
- Proceed with payment: Using the
proceedWith
method, you can proceed with the payment process. You are required to inform theintentId
,type
andid
of the payment method to execute this method.
moneyHash
.proceedWith({
intentId: "<intent_id>",
type: "method" | "savedCard" | "customerBalance",
id: "<method_id>" | "<card_id>" | "<customer_balance_id>",
metaData: {
cvv: "<cvv>", // required for customer saved cards that requires cvv
},
})
.then(({ intent, transaction, selectedMethod, redirect, methods, state }) => {
console.log({
intent,
transaction,
selectedMethod,
redirect,
methods,
state,
});
});
Other available Javascript SDK methods
In addition to the essential steps and methods previously described, the Javascript SDK provides other methods to customize the user experience. These additional methods are presented and described next.
- Reset selected method: Use the
resetSelectedMethod
method for resetting the payment method selected by the user. You can provide this option to:- Give the customer a button as an option to go back after they already selected a payment method.
- Offer a retry button so your customer can select a different payment method after a failed transaction.
moneyHash
.resetSelectedMethod("<intent_id>")
.then(({ intent, transaction, selectedMethod, methods, state }) => {
console.log({
intent,
transaction,
selectedMethod,
methods,
state,
});
});
- Delete card: Call the
deleteCard
method to delete a customer's saved card from the system. You can use this option when listing the existing customer saved cards.
moneyHash
.deleteCard({
cardId: "<card_id>",
intentSecret: "<intent_secret>",
})
.then(({ message }) => {
console.log({ message });
});
Customization
With MoneyHash's Javascript SDK integrated with your application, you can customize styles of inputs and buttons. To customize them, you can send the parameter styles
with configurations to each button when creating the MoneyHash instance, as shown below:
const moneyHash = new MoneyHash({
styles: {
submitButton: {
base: {},
hover: {},
focus: {},
},
input: {
base: {},
focus: {},
error: {},
},
loader: {
backgroundColor: '',
color: '',
}
},
});
Submit Button
When using the customization option for the submit buttons, you need to follow the TS interfaces provided below, which also present the available customization options.
interface TextStyle {
color?: string;
fontFamily?: string;
fontWeight?: string;
fontSize?: string;
fontSmoothing?: string;
lineHeight?: string;
textTransform?: string;
letterSpacing?: string;
}
interface BlockStyle {
background?: string;
borderRadius?: number | string;
boxShadow?: string;
borderStyle?: string;
borderColor?: number | string;
borderWidth?: number | string;
}
export interface ButtonStyle {
base?: TextStyle & BlockStyle;
hover?: TextStyle & BlockStyle;
focus?: TextStyle & BlockStyle;
}
Input
When using the customization option for theinputs, you need to follow the TS interfaces provided below, which also present the available customization options.
interface AllowedInputStyle {
height?: number;
padding?: number;
background?: string;
borderRadius?: number | string;
boxShadow?: string;
borderStyle?: string;
borderColor?: string;
borderWidth?: number | string;
color?: string;
fontFamily?: string;
fontWeight?: string;
fontSize?: string;
fontSmoothing?: string;
lineHeight?: string;
}
Loader
When using the customization option for the loader, you need to follow the TS interfaces provided below, which also present the available customization options.
interface LoaderStyle {
backgroundColor: string;
color: string;
}
Event Listeners
To stay up to date with the process, you can use the onComplete
and/or onFail
callback methods when creating the MoneyHash instance.
onComplete
The onComplete
will be called if the payment/payout process is completed successfully. The next code block presents an example of how to use it.
const moneyHash = new MoneyHash({
onComplete: ({ intent, transaction, selectedMethod, redirect, state }) => {
console.log("onComplete", {
intent,
transaction,
selectedMethod,
redirect,
state,
});
},
});
onFail
The onFail
will be called if the payment/payout fails due to some problem. The next code block presents an example of how to use it.
const moneyHash = new MoneyHash({
onFail: ({ intent, transaction, selectedMethod, redirect, state }) => {
console.log("onFail", {
intent,
transaction,
selectedMethod,
redirect,
state,
});
},
});
Use predefined locale
When creating MoneyHash's instance, you can predefine the locale of the checkout you are about to handle. Provide this information through the locale
field.
const moneyHash = new MoneyHash({
type: "payment" | "payout",
locale: "ar-EG",
});
Change intent language programmatically
You can choose to change the language of the experience within your application. To do so, you need to call the setLocale
method and pass as its only parameter a string of the <locale_code>
. Currently, we support three languages: English, Arabic, and Français.
await moneyHash.setLocale("<locale_code>");
Native Pay
Apple pay
Based on the provider, apple pay could require billing data before showing Apple pay dialog, so we recommend sending all billing data while creating the intent.
Billing data is provided while creating the intent
In this case, rendering Apple pay button with onClick
handler that calls moneyHash.payWithApplePay
directly should show Apple Pay dialog allowing the customer to pay.
payWithApplePay
usesApplePaySession
native method under the hood that exits in safari browsers, which requiresApplePaySession
to be called right after gesture handler.
moneyHash.payWithApplePay({
intentId,
amount: <<TOTAL_PRICE>>,
currency: "CURRENCY",
countryCode: "<<COUNTRY_CODE>>",
onCancel: () => {},
onComplete: () => {
},
onError: () => {
},
});
If there are any missing billing data while trying to call
payWithApplePay
, MoneyHash SDK will throw an errorBilling data is missing while calling payWithApplePay
Billing data is not provided while creating the intent
Pass billing data while calling payWithApplePay
MoneyHash informs you beforehand, the required billing data in expressMethods
, the payload shows as follows:
{
"id": "APPLE_PAY",
"title": "Apple Pay",
"icons": [
"https://cdn.moneyhash.io/images/checkout_icons/ApplePay.svg"
],
"isSelected": false,
"confirmationRequired": false,
"requiredBillingFields": [
{
"type": "EmailField",
"field_name": "email",
"value": "",
"choices": null,
"label": "Email",
"max_length": null,
"help_text": "Customer's email address",
"required": true,
"min_length": null,
"read_only": false,
"error_messages": {
"required": "This field is required.",
"null": "This field may not be null.",
"invalid": "Enter a valid email address.",
"blank": "This field may not be blank.",
"max_length": "Ensure this field has no more than {max_length} characters.",
"min_length": "Ensure this field has at least {min_length} characters."
}
}
]
}
Notice requiredBillingFields
which you can use to pass the required billing data to payWithApplePay
moneyHash.payWithApplePay({
intentId,
amount: totalPrice,
currency,
countryCode: "AE",
onCancel: () => {},
onComplete: () => {},
billingData: {
// pass required billing data here
email: "[email protected]"
},
onError: () => {},
});
requiredBillingFields
is a dynamic set of fields that varies from a provider to another, make sure all billing fields mentioned are passed, other wise MoneyHash SDK will throw an errorBilling data is missing while calling payWithApplePay
Show MoneyHash form to collect billing data
If you don't wish to collect customer's billing data as part of your app, you can use moneyhash.renderForm
method which will fire onComplete
event once the user fills in their billing data, and state
should be NATIVE_PAY
moneyHash = new MoneyHash({
type: "payment",
onComplete: data => {
// Now you can show Apple pay button once the filling of the form is done
// Add a button to the dom or show a confirmation modal that contains Apple pay button
console.log("onComplete", data);
},
onFail: ({ intent, transaction }) => {
console.log("onFail", { intent, transaction });
},
});
The onClick
handler should be moneyhash.payWithApplePay
Error Responses
You may face issues and receive error codes and messages when using the Javascript SDK. To help you proceed and organize your code, we provide all possible error response types for the methods you can use on the Javascript SDK.
export type ErrorResponse = {
code: number;
message: string;
};
export type IntentType = "payment" | "payout";
export type IntentStatus =
| "PROCESSED"
| "UNPROCESSED"
| "CLOSED"
| "TIME_EXPIRED"
| "PENDING"
| "EXPIRED";
export type PaymentMethodSlugs =
| "CASH_OUTLET"
| "MOBILE_WALLET"
| "CARD"
| "USSD"
| "KNET"
| "CASH_COLLECTION"
| "AMAN_MASARY"
| "PAYPAL"
| "PAY_AT_FAWRY"
| "VALU"
| "SHAHRY"
| "CASH_ON_DELIVERY"
| "BANK_INSTALLMENTS"
| "BANK_TRANSFERS"
| "REFERENCE_NUMBER"
| "SELFSERVE_WALLET"
| "APPLE_PAY"
| "GOOGLE_PAY"
| "M_PESA"
| "MOBILE_MONEY"
| "CRYPTO_WALLET"
| "NAPS"
| "FORSA"
| "SYMPL"
| "TABBY"
| "SOUHOOLA"
| "GETGO"
| "SAMSUNG_PAY"
| "QPAY"
| "TAMARA"
| "BENEFIT"
| "STC"
| "BANK_ACCOUNT"
| "CASH";
export type IntentState =
| "METHOD_SELECTION"
| "INTENT_FORM"
| "INTENT_PROCESSED"
| "TRANSACTION_WAITING_USER_ACTION"
| "TRANSACTION_FAILED"
| "EXPIRED"
| "CLOSED"
| "NATIVE_PAY";
export type PurchaseOperationStatus =
| "pending"
| "pending_authentication"
| "pending_external_action"
| "pending_online_external_action"
| "pending_authorization"
| "failed"
| "successful";
export type AuthorizeOperationStatus =
| "pending"
| "pending_authentication"
| "failed"
| "successful";
export type CaptureOperationStatus =
| "pending"
| "pending_authentication"
| "failed"
| "successful";
export type VoidOperationStatus = "pending" | "failed" | "successful";
export type RefundOperationStatus = "pending" | "failed" | "successful";
type TransactionOperationStatusMap = {
purchase: PurchaseOperationStatus;
authorize: AuthorizeOperationStatus;
capture: CaptureOperationStatus;
refund: RefundOperationStatus;
void: VoidOperationStatus;
increase_authorization: AuthorizeOperationStatus;
};
type TransactionStatus = {
[k in keyof TransactionOperationStatusMap]: `${k}.${TransactionOperationStatusMap[k]}`;
}[keyof TransactionOperationStatusMap];
type TransactionOperation = {
[k in keyof TransactionOperationStatusMap]: {
id: string;
type: k;
status: `${TransactionOperationStatusMap[k]}`;
amount: {
value: number;
currency: string;
};
statuses: {
id: string;
value: `${TransactionOperationStatusMap[k]}`;
code: string;
message: string;
created: string;
}[];
refund_type?: "full" | "partial" | null;
};
}[keyof TransactionOperationStatusMap];
export interface AbstractIntent {
id: string;
status: IntentStatus;
amount: {
value: string;
currency: string;
formatted: number;
maxPayout?: number | null;
};
secret: string;
isLive: boolean;
}
export interface PaymentIntent extends AbstractIntent {
expirationDate: string | null;
}
export interface PayoutIntent extends AbstractIntent {}
export interface Transaction {
id: string;
status: TransactionStatus;
operations: TransactionOperation[];
createdDate: string;
billingData: {
apartment: string | null;
building: string | null;
city: string | null;
country: string | null;
email: string | null;
first_name: string | null;
floor: string | null;
last_name: string | null;
name: string | null;
phone_number: string | null;
postal_code: string | null;
state: string | null;
street: string | null;
};
customFields: Record<string, unknown> | null;
providerTransactionFields: Record<string, unknown>;
externalActionMessage: string[];
}
export interface PaymentTransaction extends Transaction {
amount: {
value: number;
currency: string;
};
paymentMethodName: string;
paymentMethod: PaymentMethodSlugs;
customFormAnswers: {
formFields: Record<string, string | number | boolean>;
} | null;
}
export interface PayoutTransaction extends Transaction {
amount: {
value: string;
currency: string;
};
payoutMethodName: string;
payoutMethod: PaymentMethodSlugs;
}
export interface Redirect {
redirectUrl: string;
}
export interface Method {
id: PaymentMethodSlugs;
title: string;
icons: string[];
isSelected: boolean;
confirmationRequired: boolean;
requiredBillingFields: FormField[] | null;
}
export interface Card {
id: string;
brand: string;
logo: string;
last4: string;
expiryMonth: string;
expiryYear: string;
country: string | null;
requiresCvv: boolean;
}
export type CustomerBalances = [
{
id: "SELFSERVE_WALLET";
balance: number;
icon: string;
isSelected: boolean;
},
];
export type IntentMethods<TType extends IntentType> = TType extends "payment"
? {
paymentMethods: Method[];
expressMethods: Method[];
savedCards: Card[];
customerBalances: CustomerBalances;
}
: {
payoutMethods: Method[];
};
export type FormField = {
choices?: Record<string, string> | null;
error_messages: {
blank: string;
null?: string;
required: string;
invalid: string;
min_length: string;
max_length: string;
};
field_name: string;
help_text?: string | null;
label?: string;
max_length?: number | null;
min_length?: number | null;
read_only: boolean;
required: boolean;
type:
| "PhoneNumberField"
| "ChoiceField"
| "CharField"
| "IntegerField"
| "EmailField"
| "DateField";
value: string;
};
Embed Experience
With the Javascript SDK, you still have the option to choose a more simple solution by applying the embedded version of the Javascript SDK. This option requires fewer configurations and steps, which will work similarly to our Embedded integration.
To use the Embed Experience, you can follow the next steps. Some of them are similar or equal to the ones presented earlier on this page.
-
First, create an
intent
with the Payment intent endpoint. This step does not use MoneyHash's Javascript SDK and is standard for all MoneyHash's integrations, except for HPP. This endpoint requires authentication to be executed properly. You need to provide the Account API Key as a header and send the required data in the request body. Check the Create an Intent page for further explanation.
- Create a moneyHash instance using
MoneyHash
constructor. At this step, you need to define whether you will create a payment or a payout.
import MoneyHash from "@moneyhash/js-sdk";
const moneyHash = new MoneyHash({ type: "payment" | "payout" });
- Render the iframe: The entire payment process will be rendered inside the iframe. To use it, you need to call the
start
method. You also need to define the CSS selector where the iframe should be rendered, along with theintentId
. After calling thestart
method, the payment checkout will be available for your customer.
await moneyHash.start({
selector: "<container_css_selector>",
intentId: "<intent_id>",
});
Event listeners
Notifications
After integrating with MoneyHash through the Embedded Experience, it's recommended you learn how to configure and use Webhooks and Redirects to be able to receive notifications and automatically redirect your customer.
Updated 4 months ago