Direct API

Direct API integration is MoneyHash's solution for PCI Compliant businesses who desire to integrate fully through API calls.

The Direct API integration lets you completely control your customer's payment experience while using MoneyHash's solution. Using this option, you can configure and customize every step of the user's journey. In addition, you will be required to be a PCI-compliant business to collect your customers' payment information and transmit the information to MoneyHash.

Prerequisites

Below, you will find all you need to do before integrating to MoneyHash the External API:

  1. Get Started with MoneyHash to access your own Organization.
  2. Create an Account within your Organization.
  3. Connect providers to your new Account.
  4. Set up your Payment Defaults.
  5. Get your API keys in the dashboard to be able to make API calls.

Integrating

Direct API integration type is completely done through API calls. To start every payment, the first step is to create an intent using the Create Intent endpoint, whose URL is provided below. To use MoneyHash endpoints, you need to provide correct authentication information. Otherwise, you cannot create intents or perform other requests to MoneyHash API.

POST
/api/v1.1/direct/payments/intent/

The response from the Create Intent endpoint provides the necessary information to present your customer with the first step of his payment experience. This response lets you access all available payment methods for the currency and account you specified in the intent.

As you present the available payment options and the customer chooses a payment method, you need to inform it to MoneyHash. You can call the Update selected method endpoint with the intent ID received by the intent creation.

POST
/api/v1.1/direct/payments/intents/{intent_id}/update-method/

This request will return a JSON containing all the payment information fields, after selecting the CARD method you will need to collect from your customer to proceed with their payment. The required information can be found within the state_details property of the response, containing a card property, with the fields array.

The state 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 possible state value.

stateAction
METHOD_SELECTIONstate_details will contain list of all possible payment methods that could be used to complete your payment, you need to render them to your users
INTENT_NATIVE_FORMstate_details will contain all fields required to be collected from your customer, fields will be under different parents such as card key
INTENT_FORMMoneyHash will send you a URL in the state details to be rendered to your users, used with 3DS
INTENT_PROCESSEDRender your successful confirmation UI with the intent details.
TRANSACTION_FAILEDRender your failure UI with the intent details.
TRANSACTION_WAITING_USER_ACTIONRender your pending actions confirmation UI with the intent details and externalActionMessage if exists on Transaction.
EXPIREDRender your intent expired UI.
CLOSEDRender your intent closed UI.

To proceed with the card selection, you can access these fields in the response.state_details.card.fields property. The main fields here will be:

  • card_number: The card's number.
  • card_holder_name: The card's holder name, as presented on the card.
  • expiry_month: The expiration month of the card.
  • expiry_year The expiration year of the card.
  • cvv: the card's CVV.

PCI Compliance

As you must be PCI compliant to use the Direct API you are able to present these fields and collect the customer's payment data yourself

Once you collect your customer's card info, you need to submit it to MoneyHash Vault to create a card token and complete the payment

With the customer's card data, and billing fields so you can proceed with their payment by calling the following endpoint:

POST
https://vault.moneyhash.io/api/v1/direct/payments/intents/{intent_id}/{payment_method}/

MoneyHash vault will tokenize the card info and inform MoneyHash server with the payment and will forward billing, shipping...etc if it was passed

Executing this will process the payment.

Notifications

After integrating with MoneyHash through the Direct API, it's recommended you learn how to configure and use Webhooks and Redirects to be able to receive notifications and automatically redirect your customer to where you want with ease.


Example

In this example, we want to create a payment intent to charge a user 10 USD, and collect the money using card payment method.

so let's go over it step by step to complete the entire flow.


Before we start, prepare your API key and replace it in the requests

1. Creating a payment intent

note we're sending "payment_method": "CARD" while creating the intent, so our payment method is pre selected

curl --request POST \
     --url https://web.moneyhash.io/api/v1.1/direct/payments/intent/ \
     --header 'X-Api-Key: <YOUR_API_KEY>' \
     --header 'accept: application/json' \
     --header 'content-type: application/json' \
     --data '
{
  "amount": "50",
  "amount_currency": "usd",
  "operation": "purchase",
  "webhook_url": "https://webhook.site/ce270c96-ba82-46ea-bb45-3aa9fc78e31b",
  "payment_method": "CARD"
}
'

and the response would be

{
  "status": {
    "code": 200,
    "message": "success",
    "errors": []
  },
  "data": {
    "intent": {
      "id": "LYPXeJ9",
      "status": "UNPROCESSED",
      "amount": {
        "value": "50.00",
        "currency": "USD",
        "formatted": 50,
        "display_value": "50.00 USD"
      },
      "expiration_date": null,
      "is_live": true,
      "methods": {
        "payment_methods": [
          {
            "payment_method_name": "Card",
            "has_customized_label": false,
            "payment_method": "CARD",
            "checkout_icons": [
              "https://cdn.moneyhash.io/images/checkout_icons/Visa.svg",
              "https://cdn.moneyhash.io/images/checkout_icons/Master_Card.svg"
            ],
            "confirmation_required": false,
            "use_for_express_checkout": false,
            "required_billing_fields": []
          }
        ],
        "express_methods": [
          {
            "payment_method_name": "Google Pay",
            "has_customized_label": false,
            "payment_method": "GOOGLE_PAY",
            "checkout_icons": [
              "https://cdn.moneyhash.io/images/checkout_icons/Google%20Pay%20Icon.svg"
            ],
            "confirmation_required": false,
            "use_for_express_checkout": true,
            "required_billing_fields": [
              {
                "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."
                }
              }
            ]
          }
        ],
        "saved_cards": [],
        "customer_balances": [
          {
            "id": "SELFSERVE_WALLET",
            "balance": 0,
            "icon": "https://embed.moneyhash.io/assets/selfWalletIcon.767086fb.svg",
            "is_selected": false
          }
        ]
      }
    },
    "selected_method": "CARD",
    "transaction": {
      "id": "941c546d-1339-4017-a3d9-76c5104d47d6",
      "status": "PENDING",
      "operations": null,
      "created_date": "2024-03-12T11:24:51.863059Z",
      "amount": {
        "value": "50.00",
        "currency": "USD",
        "formatted": 50,
        "display_value": "50.00 USD"
      },
      "payment_method": "CARD",
      "payment_method_name": "Card",
      "billing_data": {
        "name": "",
        "first_name": "",
        "last_name": "",
        "email": "",
        "phone_number": "",
        "address": "",
        "address1": "",
        "apartment": "",
        "floor": "",
        "building": "",
        "street": "",
        "city": "",
        "state": "",
        "country": "",
        "postal_code": ""
      },
      "custom_fields": null,
      "provider_transaction_fields": {},
      "custom_form_answers": null
    },
    "state": "INTENT_FORM_NATIVE",
    "state_details": {
      "card": {
        "fields": [
          {
            "type": "CharField",
            "field_name": "card_number",
            "value": "",
            "choices": null,
            "label": "Card number",
            "max_length": 16,
            "help_text": null,
            "required": true,
            "min_length": 15,
            "read_only": false,
            "error_messages": {
              "required": "This field is required.",
              "null": "This field may not be null.",
              "invalid": "Not a valid string.",
              "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."
            }
          },
          {
            "type": "CharField",
            "field_name": "card_holder_name",
            "value": "",
            "choices": null,
            "label": "Card holder name",
            "max_length": null,
            "help_text": null,
            "required": true,
            "min_length": 6,
            "read_only": false,
            "error_messages": {
              "required": "This field is required.",
              "null": "This field may not be null.",
              "invalid": "Not a valid string.",
              "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."
            }
          },
          {
            "type": "CharField",
            "field_name": "expiry_month",
            "value": "",
            "choices": null,
            "label": "Expiry month",
            "max_length": 2,
            "help_text": null,
            "required": true,
            "min_length": 2,
            "read_only": false,
            "error_messages": {
              "required": "This field is required.",
              "null": "This field may not be null.",
              "invalid": "Not a valid string.",
              "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."
            }
          },
          {
            "type": "CharField",
            "field_name": "expiry_year",
            "value": "",
            "choices": null,
            "label": "Expiry year",
            "max_length": 2,
            "help_text": null,
            "required": true,
            "min_length": 2,
            "read_only": false,
            "error_messages": {
              "required": "This field is required.",
              "null": "This field may not be null.",
              "invalid": "Not a valid string.",
              "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."
            }
          },
          {
            "type": "CharField",
            "field_name": "cvv",
            "value": "",
            "choices": null,
            "label": "CVV",
            "max_length": 4,
            "help_text": null,
            "required": true,
            "min_length": 3,
            "read_only": false,
            "error_messages": {
              "required": "This field is required.",
              "null": "This field may not be null.",
              "invalid": "Not a valid string.",
              "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."
            }
          }
        ]
      },
      "meta": {
        "url": "https://vault.moneyhash.io/api/v1/direct/payments/intents/LYPXeJ9/CARD/?token=eyJhbGciOiJFUzI1NksiLCJ0eXAiOiJKV1QifQ.eyJleHAiOjE3MTAyNDI5OTIsImludGVudF9pZCI6IkxZUFhlSjkiLCJpc19saXZlIjp0cnVlfQ.ytdid84QW8CIQtxoWJxCYwbUoMPaOeFK5RkSpI_I2giSNywpT_OIxZN50bAV3ExqY_t-xSphMJ2c-Kbsiz7apw"
      }
    },
    "customer": null,
    "tokenized_card_token": null
  },
  "count": 1,
  "next": null,
  "previous": null
}

📘

Note that the state now after selecting a method is INTENT_NATIVE_FORM which means you have to render all fields natively on your client to be filled by your customer

2. Rendering native intent form

MoneyHash providers you with a form definition to render the required fields, including card fields.

so once we get user credit card information that includes, card_holder_name, card_number...etc, we send that to MoneyHash vault which will take care of communicating with MoneyHash server

curl --request POST \
     --url 'https://vault.moneyhash.io/api/v1/direct/payments/intents/LYPXeJ9/CARD/?token=eyJhbGciOiJFUzI1NksiLCJ0eXAiOiJKV1QifQ.eyJleHAiOjE3MTAyNDI5OTIsImludGVudF9pZCI6IkxZUFhlSjkiLCJpc19saXZlIjp0cnVlfQ.ytdid84QW8CIQtxoWJxCYwbUoMPaOeFK5RkSpI_I2giSNywpT_OIxZN50bAV3ExqY_t-xSphMJ2c-Kbsiz7apw' \
     --header 'X-Api-Key: gQdw2v2X.6yWA088CJ4rqK3o8zE6s1TJoquOPmqv4' \
     --header 'accept: application/json' \
     --header 'content-type: application/json' \
     --data '
{
  "native_form": {
    "card_details": {
      "card_number": "4242424242424242",
      "card_holder_name": "john done",
      "expiry_month": "12",
      "expiry_year": "26",
      "cvv": "100"
    },
    "shipping_fields": {
      "email": "[email protected]"
    }
  }
}
'

📘

Note we're appending token to the vault url which is used for authentication, and you have to send x-api-key header to be able to complete the payment. Token is valid for only 5 mins

🚧

billing_fields has to be present in the payload, if no billing fields are required, billing fields should be sent as an empty object {}

and the successful response from MoneyHash vault would be:

{
  "status": {
    "code": 200,
    "message": "success",
    "errors": []
  },
  "data": {
    "intent": {
      "id": "ZpojpBg",
      "status": "PROCESSED",
      "amount": {
        "value": "50.00",
        "currency": "USD",
        "formatted": 50,
        "display_value": "50.00 USD"
      },
      "expiration_date": null,
      "is_live": true,
      "methods": {
        "payment_methods": [
          {
            "payment_method_name": "Cash Outlet",
            "has_customized_label": false,
            "payment_method": "CASH_OUTLET",
            "checkout_icons": [
              "https://cdn.moneyhash.io/images/checkout_icons/Cash.svg"
            ],
            "confirmation_required": false,
            "use_for_express_checkout": false,
            "required_billing_fields": []
          },
          {
            "payment_method_name": "Mobile Wallet",
            "has_customized_label": false,
            "payment_method": "MOBILE_WALLET",
            "checkout_icons": [
              "https://cdn.moneyhash.io/images/checkout_icons/Mobile_Wallet.svg"
            ],
            "confirmation_required": false,
            "use_for_express_checkout": false,
            "required_billing_fields": []
          },
          {
            "payment_method_name": "Card",
            "has_customized_label": false,
            "payment_method": "CARD",
            "checkout_icons": [
              "https://cdn.moneyhash.io/images/checkout_icons/Visa.svg",
              "https://cdn.moneyhash.io/images/checkout_icons/Master_Card.svg"
            ],
            "confirmation_required": false,
            "use_for_express_checkout": false,
            "required_billing_fields": []
          },
          {
            "payment_method_name": "Cash On Delivery",
            "has_customized_label": false,
            "payment_method": "CASH_ON_DELIVERY",
            "checkout_icons": [
              "https://cdn.moneyhash.io/images/checkout_icons/Cash.svg"
            ],
            "confirmation_required": true,
            "use_for_express_checkout": false,
            "required_billing_fields": []
          },
          {
            "payment_method_name": "SelfServe - Wallet",
            "has_customized_label": false,
            "payment_method": "SELFSERVE_WALLET",
            "checkout_icons": [
              "https://cdn.moneyhash.io/images/checkout_icons/Mobile_Wallet.svg"
            ],
            "confirmation_required": true,
            "use_for_express_checkout": false,
            "required_billing_fields": []
          },
          {
            "payment_method_name": "M-Pesa",
            "has_customized_label": false,
            "payment_method": "M_PESA",
            "checkout_icons": [
              "https://cdn.moneyhash.io/images/checkout_icons/M-Pesa-icon.svg"
            ],
            "confirmation_required": true,
            "use_for_express_checkout": false,
            "required_billing_fields": []
          },
          {
            "payment_method_name": "Mobile Money",
            "has_customized_label": false,
            "payment_method": "MOBILE_MONEY",
            "checkout_icons": [
              "https://cdn.moneyhash.io/images/checkout_icons/Mobile_Wallet.svg"
            ],
            "confirmation_required": true,
            "use_for_express_checkout": false,
            "required_billing_fields": []
          }
        ],
        "express_methods": [
          {
            "payment_method_name": "Google Pay",
            "has_customized_label": false,
            "payment_method": "GOOGLE_PAY",
            "checkout_icons": [
              "https://cdn.moneyhash.io/images/checkout_icons/Google%20Pay%20Icon.svg"
            ],
            "confirmation_required": true,
            "use_for_express_checkout": true,
            "required_billing_fields": [
              {
                "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."
                }
              }
            ]
          }
        ],
        "saved_cards": [],
        "customer_balances": [
          {
            "id": "SELFSERVE_WALLET",
            "balance": 0,
            "icon": "https://embed.moneyhash.io/assets/selfWalletIcon.767086fb.svg",
            "is_selected": false
          }
        ]
      }
    },
    "selected_method": "CARD",
    "transaction": {
      "id": "17acbc78-8edf-4647-8c1a-53b0c291dffe",
      "status": "SUCCESSFUL",
      "operations": [
        {
          "id": "ZDr7N3L",
          "type": "purchase",
          "status": "successful",
          "amount": {
            "value": "50.00",
            "currency": "USD",
            "formatted": 50,
            "display_value": "50.00 USD"
          },
          "statuses": [
            {
              "id": "ZGJM5Pg",
              "value": "successful",
              "code": "6000",
              "message": "Successful",
              "created": "2024-03-12 11:33:41.670034+00:00"
            },
            {
              "id": "LW3wXML",
              "value": "pending",
              "code": "8000",
              "message": "Pending",
              "created": "2024-03-12 11:33:38.021135+00:00"
            }
          ]
        }
      ],
      "created_date": "2024-03-12T11:33:37.909578Z",
      "amount": {
        "value": "50.00",
        "currency": "USD",
        "formatted": 50,
        "display_value": "50.00 USD"
      },
      "payment_method": "CARD",
      "payment_method_name": "Card",
      "billing_data": {
        "name": null,
        "first_name": null,
        "last_name": null,
        "email": "[email protected]",
        "phone_number": null,
        "address": null,
        "address1": null,
        "apartment": null,
        "floor": null,
        "building": null,
        "street": null,
        "city": null,
        "state": null,
        "country": null,
        "postal_code": null
      },
      "custom_fields": null,
      "provider_transaction_fields": {
        "stripe_intent_id": "pi_3OtTaSH2aRW7je2s17Mft1df",
        "stripe_customer_id": "cus_PivRRw8KS77qwq",
        "stripe_method_id": "pm_1OtTaQH2aRW7je2s1bo6MfFi"
      },
      "custom_form_answers": null
    },
    "state": "INTENT_PROCESSED",
    "state_details": {},
    "customer": null,
    "tokenized_card_token": null
  },
  "count": 1,
  "next": null,
  "previous": null
}

3. Showing a success message

Now we can notify our user that their transaction was successful.