Direct API integration | Successful payment with intent native form
In this example, we want to create a payment intent to charge a user 10 USD, and collect the money using card payment method.
Our flow would look like this:
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
curl --location --request POST 'https://web.moneyhash.io/api/v1.1/payments/intent/' \
--header 'X-Api-Key: YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data-raw '{
"amount": 10,
"amount_currency": "USD",
"operation": "purchase",
"use_direct_api": true
}'
import requests
url = "https://moneyhash.io/api/v1.1/payments/intent/"
payload = {
"amount": 50,
"amount_currency": "USD",
"operation": "purchase",
"use_direct_api": True
}
headers = {
'X-Api-Key': '<YOUR_API_KEY>',
'Content-Type': 'application/json'
}
response = requests.request("POST", url, headers=headers, json=payload)
print(response.text.encode('utf8'))
and the response would be
{
"status": {
"code": 200,
"message": "success",
"errors": []
},
"data": {
"embed_url": "https://web.moneyhash.io/payments/embed/ePgw3gN/",
"id": "ePgw3gN",
"status": "UNPROCESSED"
},
"count": null,
"next": null,
"previous": null
}
let's grab the intent id from data.id
and let's fetch the intent details
2. Getting intent details
curl --location --request GET 'https://web.moneyhash.io/api/v1.1/payments/external/intents/ePgw3gN/' \
--header 'X-Api-Key: <YOUR_API_KEY>' \
--header 'Content-Type: application/json'
import requests
url = 'https://web.moneyhash.io/api/v1.1/payments/external/intent/ePgw3gN'
headers = {
'X-Api-Key': '<YOUR_API_KEY>',
'Content-Type': 'application/json'
}
response = requests.get(url, headers=headers)
print(response.json())
const fetch = require('node-fetch');
const url = 'https://web.moneyhash.io/api/v1.1/payments/external/intent/ePgw3gN';
const headers = {
'X-Api-Key': '<YOUR_API_KEY>',
'Content-Type': 'application/json'
};
fetch(url, {
method: 'GET',
headers: headers
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error(error));
and the response would be:
{
"status": {
"code": 200,
"message": "success",
"errors": []
},
"data": {
"state": "METHOD_SELECTION",
"state_details": {
"payment_methods": [
{
"payment_method_name": "Cash Outlet",
"has_customized_label": false,
"payment_method": "CASH_OUTLET",
"checkout_icons": [
"https://web.moneyhash.io/static/images/checkout_icons/payat-checkout.svg"
],
"confirmation_required": true,
"use_for_express_checkout": false
},
{
"payment_method_name": "Mobile Wallet",
"has_customized_label": false,
"payment_method": "MOBILE_WALLET",
"checkout_icons": [
"https://web.moneyhash.io/static/images/checkout_icons/Mobile_Wallet.svg"
],
"confirmation_required": false,
"use_for_express_checkout": false
},
{
"payment_method_name": "Card",
"has_customized_label": false,
"payment_method": "CARD",
"checkout_icons": [
"https://web.moneyhash.io/static/images/checkout_icons/Visa.svg",
"https://web.moneyhash.io/static/images/checkout_icons/Master_Card.svg"
],
"confirmation_required": false,
"use_for_express_checkout": false
},
{
"payment_method_name": "Paypal",
"has_customized_label": false,
"payment_method": "PAYPAL",
"checkout_icons": [
"https://web.moneyhash.io/static/images/checkout_icons/Paypal.svg"
],
"confirmation_required": true,
"use_for_express_checkout": false
},
{
"payment_method_name": "Cash On Delivery",
"has_customized_label": false,
"payment_method": "CASH_ON_DELIVERY",
"checkout_icons": [
"https://web.moneyhash.io/static/images/checkout_icons/Cash.svg"
],
"confirmation_required": true,
"use_for_express_checkout": false
},
{
"payment_method_name": "M-Pesa",
"has_customized_label": false,
"payment_method": "M_PESA",
"checkout_icons": [
"https://web.moneyhash.io/static/images/checkout_icons/M-Pesa-icon.svg"
],
"confirmation_required": false,
"use_for_express_checkout": false
},
{
"payment_method_name": "Mobile Money",
"has_customized_label": false,
"payment_method": "MOBILE_MONEY",
"checkout_icons": [
"https://web.moneyhash.io/static/images/checkout_icons/Mobile_Wallet.svg"
],
"confirmation_required": false,
"use_for_express_checkout": false
},
{
"payment_method_name": "Crypto Wallet",
"has_customized_label": false,
"payment_method": "CRYPTO_WALLET",
"checkout_icons": [
"https://web.moneyhash.io/static/images/checkout_icons/crypto_method.svg"
],
"confirmation_required": false,
"use_for_express_checkout": false
}
],
"express_methods": [
{
"payment_method_name": "Google Pay",
"has_customized_label": false,
"payment_method": "GOOGLE_PAY",
"checkout_icons": [
"https://web.moneyhash.io/static/images/checkout_icons/Google%20Pay%20Icon.svg"
],
"confirmation_required": false,
"use_for_express_checkout": true
}
],
"saved_cards": [
{
"id": "zGgq4Lx",
"brand": "MasterCard",
"logo": "/static/images/card_icons/default.svg",
"last4": "0022",
"expiry_month": "03",
"expiry_year": "25",
"country": null,
"requires_cvv": true
}
],
"customer_balances": [
{
"id": "SELFSERVE_WALLET",
"balance": 0,
"icon": "https://embed.moneyhash.io/assets/selfWalletIcon.767086fb.svg",
"is_selected": false
}
]
},
"selected_method": null,
"intent": {
"id": "ePgw3gN",
"status": "UNPROCESSED",
"amount": {
"value": "10.00USD",
"currency": "USD",
"formatted": 10
},
"expiration_date": null,
"is_live": false
},
"transaction": null
},
"count": 1,
"next": null,
"previous": null
}
Note that the
state
here isMETHOD_SELECTION
which means we need to render the available methods to users to select the method they want to proceed with.
3. Showing available methods to users to select from
once you get available methods, you can start rendering them natively in your app for users to select from. For our example, let's assume that the user selected CARD
payment method, so we need to update the selected method.
4. Updating MoneyHash selected method
curl --location --request POST 'https://web.moneyhash.io/api/v1.1/external/payments/intents/ePgw3gN/update-method/' \
--header 'X-Api-Key: <YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data-raw '{"payment_method": "CARD"}'
import requests
url = 'https://web.moneyhash.io/api/v1.1/external/payments/intents/ePgw3gN/update-method/'
headers = {
'X-Api-Key': '<YOUR_API_KEY>',
'Content-Type': 'application/json'
}
payload = {
'payment_method': 'CARD'
}
response = requests.post(url, headers=headers, json=payload)
print(response.json())
const fetch = require('node-fetch');
const url = 'https://web.moneyhash.io/api/v1.1/external/payments/intents/ePgw3gN/update-method/';
const headers = {
'X-Api-Key': '<YOUR_API_KEY>',
'Content-Type': 'application/json'
};
const payload = {
payment_method: 'CARD'
};
fetch(url, {
method: 'POST',
headers: headers,
body: JSON.stringify(payload)
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error(error));
and the response would be
{
"status": {
"code": 200,
"message": "success",
"errors": []
},
"data": {
"state": "METHOD_SELECTION",
"state_details": {
"card": {
"fields": [
{
"type": "CharField",
"field_name": "card_holder_name",
"value": "",
"choices": null,
"label": "Card holder name",
"max_length": 100,
"help_text": null,
"required": true,
"min_length": null,
"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_number",
"value": "",
"choices": null,
"label": "Card number",
"max_length": 18,
"help_text": null,
"required": true,
"min_length": null,
"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": null,
"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": null,
"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": null,
"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/external/tokens/",
"secret": "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.eyJleHAiOjE2ODkwMTkxMDF9.IWzIUZljENyq0e12BUnej8VkR-Uz1ljzspJB2XOEyZddK1KMjPL16qVrN6UaWOZmNuQLScJ41cEyuV0cgsUhmw",
"is_live": false
}
},
"billing": {
"fields": [
{
"type": "CharField",
"field_name": "first_name",
"value": "",
"choices": null,
"label": "First name",
"max_length": 100,
"help_text": null,
"required": true,
"min_length": null,
"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": "last_name",
"value": "eid",
"choices": null,
"label": "Last name",
"max_length": 150,
"help_text": null,
"required": true,
"min_length": null,
"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": "EmailField",
"field_name": "email",
"value": "[email protected]",
"choices": null,
"label": "Email",
"max_length": null,
"help_text": null,
"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."
}
},
{
"type": "PhoneNumberField",
"field_name": "phone_number",
"value": "+201064610000",
"choices": null,
"label": "Phone number",
"max_length": null,
"help_text": null,
"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 phone number.",
"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."
}
}
]
},
"shipping": {
"fields": []
},
"product_items": {
"fields": []
}
},
"selected_method": null,
"intent": {
"id": "ePgw3gN",
"status": "UNPROCESSED",
"amount": {
"value": "10.00USD",
"currency": "USD",
"formatted": 10
},
"expiration_date": null,
"is_live": false
},
"transaction": null,
"count": 1,
"next": null,
"previous": null
}
}
Note that the
state
now after selecting a method isINTENT_NATIVE_FORM
5. Rendering native intent form
MoneyHash providers you with a form definition to render the required fields, including card fields. Worth mentioning that card fields needs to be sent to MoneyHash vault endpoint. So we need to perform 2 API calls:
- Submitting card info to MoneyHash vault.
- Submitting vault successful response along with other data to MoneyHash web.
so once we get user credit card information that includes, card_holder_name
, card_number
...etc, we send that to MoneyHash vault
curl --location --request POST 'https://vault.moneyhash.io/api/v1/external/tokens/' \
--header 'Content-Type: application/json' \
--header 'Mh-Authorization: <SECRET_RETURNED_FROM_MONEYHASH_WEB>' \
--data-raw '{
"card_holder_name": "Kevin Smith",
"card_number": "1111000000000000",
"expiry_month": "02",
"expiry_year": "24",
"cvv": "000",
"is_live": false,
"save_card": false
}'
import requests
url = 'https://vault.moneyhash.io/api/v1/external/tokens/'
headers = {
'Content-Type': 'application/json',
'mh-authorization': '<SECRET>'
}
payload = {
'card_holder_name': 'Kevin Smith',
'card_number': '1111000000000000',
'expiry_month': '02',
'expiry_year': '24',
'cvv': '000',
'is_live': False,
'save_card': False
}
response = requests.post(url, headers=headers, json=payload)
print(response.json())
and the successful response from MoneyHash vault would be:
{
"first_six_digits": "111100",
"last_four_digits": "0000",
"card_scheme": "Unknown",
"card_holder_name": "Kevin Smith",
"expiry_year": "24",
"expiry_month": "02",
"is_live": false,
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.eyJleHAiOjE2ODg5OTQyNjV9.HE7Mej91WFPb9AM4HYIllQ7sD3W3uOsO8gONjbpujtGntrkfHer9VfQgvEs0gdw1dWJwFiV5yTLJGjkadBNTVw",
"card_token": "token-e6f163f4-490c-4d78-8a94-1e10a6755f55",
"cvv": "000",
"save_card": false
}
Now we need to submit this response with the other user collected data to MoneyHash web
curl --location --request POST 'https://web.moneyhash.io/api/v1.1/external/payments/intents/ePgw3gN/CARD/' \
--header 'X-Api-Key: <YOUR_API_KEY>' \
--header 'Content-Type: application/json' \
--data-raw '{
"native_form": {
"billing_fields": {},
"card_details": {
"first_six_digits": "111100",
"last_four_digits": "0000",
"card_scheme": "Unknown",
"card_holder_name": "Kevin Smith",
"expiry_year": "24",
"expiry_month": "02",
"is_live": false,
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.eyJleHAiOjE2ODg5OTQyNjV9.HE7Mej91WFPb9AM4HYIllQ7sD3W3uOsO8gONjbpujtGntrkfHer9VfQgvEs0gdw1dWJwFiV5yTLJGjkadBNTVw",
"card_token": "token-e6f163f4-490c-4d78-8a94-1e10a6755f55",
"cvv": "000",
"save_card": false
}
}
}'
import requests
url = 'https://web.moneyhash.io/api/v1.1/external/payments/intents/ePgw3gN/<method>'
headers = {
'X-Api-Key': '<YOUR_API_KEY>',
'Content-Type': 'application/json'
}
payload = {
"card_fields": {},
"billing_fields": {},
"shipping_fields": {},
"card_embed": {
"first_six_digits": "111100",
"last_four_digits": "0000",
"card_scheme": "Unknown",
"card_holder_name": "Kevin Smith",
"expiry_year": "24",
"expiry_month": "02",
"is_live": False,
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.eyJleHAiOjE2ODg5OTQyNjV9.HE7Mej91WFPb9AM4HYIllQ7sD3W3uOsO8gONjbpujtGntrkfHer9VfQgvEs0gdw1dWJwFiV5yTLJGjkadBNTVw",
"card_token": "token-e6f163f4-490c-4d78-8a94-1e10a6755f55",
"cvv": "000",
"save_card": False
},
"product_items_fields": []
}
response = requests.post(url, headers=headers, json=payload)
print(response.json())
const fetch = require('node-fetch');
const url = 'https://web.moneyhash.io/api/v1.1/external/payments/intents/ePgw3gN/CARD';
const headers = {
'X-Api-Key': '<YOUR_API_KEY>',
'Content-Type': 'application/json'
};
const payload = {
"card_fields": {},
"billing_fields": {},
"shipping_fields": {},
"card_embed": {
"first_six_digits": "111100",
"last_four_digits": "0000",
"card_scheme": "Unknown",
"card_holder_name": "Kevin Smith",
"expiry_year": "24",
"expiry_month": "02",
"is_live": false,
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.eyJleHAiOjE2ODg5OTQyNjV9.HE7Mej91WFPb9AM4HYIllQ7sD3W3uOsO8gONjbpujtGntrkfHer9VfQgvEs0gdw1dWJwFiV5yTLJGjkadBNTVw",
"card_token": "token-e6f163f4-490c-4d78-8a94-1e10a6755f55",
"cvv": "000",
"save_card": false
},
"product_items_fields": []
};
fetch(url, {
method: 'POST',
headers: headers,
body: JSON.stringify(payload)
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error(error));
and the response would be like the following:
{
"status": {
"code": 200,
"message": "success",
"errors": []
},
"data": {
"state": "INTENT_PROCESSED",
"state_details": {},
"selected_method": "CARD",
"intent": {
"id": "ePgw3gN",
"status": "PROCESSED",
"amount": {
"value": "10.00USD",
"currency": "USD",
"formatted": 10
},
"expiration_date": null,
"is_live": false
},
"transaction": {
"id": "73ce83ff-8c42-4950-8a59-eedc54075505",
"custom_fields": null,
"created": "2023-07-10T12:59:16.974143Z",
"status": "SUCCESSFUL",
"amount": 10,
"amount_currency": "USD",
"billing_data": null,
"external_action_message": [],
"payment_method": "CARD",
"payment_method_name": "Card",
"custom_form_answers": null,
"custom_message": "",
"service_provider": "eZAewZx",
"account": "YVglAZx",
"provider_transaction_fields": {},
"provider_signature_match": false,
"localized_status": "SUCCESSFUL",
"trx_status": "purchase.successful",
"operations": [
{
"id": "ZA5p2eZ",
"type": "purchase",
"status": "successful",
"amount": {
"value": 10,
"currency": "USD"
},
"statuses": [
{
"id": "Z0G4EKg",
"value": "successful",
"code": "6000",
"message": "Successful",
"created": "2023-07-10 12:59:25.985113+00:00"
},
{
"id": "9Jd2brg",
"value": "pending",
"code": "8000",
"message": "Pending",
"created": "2023-07-10 12:59:17.022562+00:00"
}
],
"refund_type": null
}
],
"type": "payin"
}
},
"count": 1,
"next": null,
"previous": null
}
6. Showing a success message
Now we can notify our user that their transaction was successful.
Updated about 1 year ago