API Integration
This guide covers the technical implementation of Merso BNPL API integration for game companies.
⚠️ Before Starting
Prior to integrating the Merso BNPL API into your game, follow these preliminary steps:
When a company expresses the desire to integrate BNPL into their game, we generate an API Key and a Game ID for them. These are unique identifiers for your project and should be kept confidential to prevent unauthorized access. The JWT is generated when you first authenticate with the /auth endpoint and will expire every 12 hours, requiring you to re-authenticate to continue making requests.
To call the /auth endpoint, the client needs to send the following parameters in the request body:
gameIdapiKey
We provide both parameters to the companies once they decide to implement BNPL in their games.
0. Auth
Endpoint: POST /auth
Purpose: Verify API connectivity and status
Request:
curl -X POST https://api3.dev.merso.io/auth \
-H "Content-Type: application/json" \
-d '{
"game_id": "YOUR_GAME_ID",
"api_key": "YOUR_API_KEY"
}'Response:
{
"authResult": {
"token": "YOUR_NEW_JWT_TOKEN",
"expires_at": "2025-08-05T21:21:13.000Z"
}
}Example Request Body:
const axios = require('axios');
async function authenticateGame() {
try {
const response = await axios.post('/auth', {
gameid: 'exampleGameId',
apikey: 'exampleApiKey'
});
console.log('Authentication successful:', response.data.authResult);
} catch (error) {
if (error.response) {
console.error('Error:', error.response.data.error);
} else {
console.error('Failed to authenticate game. Error Message:', error.message);
}
}
}🎯 Integration Overview
The Merso BNPL API provides three core endpoints for game integration:
/health- API health check/user-approval- Approve ERC20 token spending/buy-token-with-merso- Purchase NFT with BNPL
🔐 Authentication
JWT Token Setup
During onboarding, you'll receive a custom Game ID token for API access:
// Your custom GameID (provided during onboarding)
const GAME_ID = 'YOUR_GAME_ID';
// API base URL for your game
const API_BASE_URL = 'https://api.merso.io/game/YOUR_GAME_ID';Request Headers
All API requests require these headers:
const headers = {
'Content-Type': 'application/json',
'Authorization': `Bearer ${JWT_TOKEN}`
};📋 API Endpoints
1. Health Check
Endpoint: GET /health
Purpose: Verify API connectivity and status
Request:
curl -X GET "https://api3.dev.merso.io/health"Response:
{
"success": true,
"message": "Hello World, Merso BNPL Backend",
}JavaScript Example:
async function checkAPIHealth() {
try {
const response = await fetch(`https://api3.dev.merso.io/health`, {
method: 'GET',
headers: headers
});
const data = await response.json();
console.log('API Status:', data.status);
return data;
} catch (error) {
console.error('Health check failed:', error);
}
}2. User Approval
Endpoint: POST /user-approval
Purpose: Approve Merso BNPL to spend user's ERC20 tokens
Request :
curl -X POST "https://api3.dev.merso.io/user-approval" \
-H "Authorization: Bearer <your_token>" \
-H "Content-Type: application/json" \
-d '{
"userAddress": "VALID_USER_ADDRESS",
"userEmail": "user@email.com",
"gameTokenAddress": "YOUR_GAME_ERC20_ADDRESS",
"tokenPrice": "PRICE_IN_WEI",
"collectionAddress": "YOUR_GAME_ERC721_ADDRESS"
}'Parameters:
userAddress(string): User's wallet addressuserEmail(string): User's in-game emailtokenAddress(string): ERC20 token contract addressamount(string): Amount to approve (in wei)
Response:
{
"success": true,
"txData": {
"to": "0x1234567890123456789012345678901234567890",
"from": "0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6",
"data": "0xa9059cbb000000000000000000000000...",
"gasPrice": "20000000000",
"nonce": 5,
"value": "0"
},
}JavaScript Example:
async function approveTokens(userAddress, tokenAddress, amount) {
try {
const approvalResponse = await fetch(
`https://api3.dev.merso.io/user-approval`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
userAddress: walletAddress,
userEmail: "test@test.com",
tokenPrice: tokenPrice,
gameTokenAddress: MOCK_ERC20_ADDRESS,
}),
}
);
if (!approvalResponse.ok) {
throw new Error("Approval API request failed");
}
const approvalData: ApiResponse = await approvalResponse.json();
// Execute approval transaction
const approvalTx = await signer.sendTransaction({
to: approvalData.txData.to,
from: approvalData.txData.from,
data: approvalData.txData.data,
gasPrice: approvalData.txData.gasPrice,
nonce: approvalData.txData.nonce,
value: approvalData.txData.value,
});
// Wait for approval transaction to be mined
await approvalTx.wait();
} catch (error) {
console.error('Approval failed:', error);
throw error;
}
}3. Buy Token with Merso
Endpoint: POST /buy-token-with-merso
Purpose: Purchase NFT using BNPL functionality
Request:
curl -X POST "https://api3.dev.merso.io/buy-token-with-merso" \
-H "Authorization: Bearer <your_token>" \
-H "Content-Type: application/json" \
-d '{
"userAddress": "VALID_USER_ADDRESS",
"tokenId": "1",
"tokenPrice": "PRICE_IN_WEI",
"nftCollectionAddress": "YOUR_GAME_ERC721_ADDRESS"
}'Parameters:
userAddress(string): User's wallet addresstokenId(string): NFT token ID to purchasetokenPrice(string): Total price in weinftCollectionAddress(string): NFT collection contract address
Response:
{
"success": true,
"txData": {
"to": "0x1234567890123456789012345678901234567890",
"from": "0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6",
"data": "0x...",
"gasPrice": "20000000000",
"nonce": 6,
"value": "0"
},
}JavaScript Example:
async function buyNFTWithMerso(userAddress, tokenId, price, collectionAddress) {
try {
const response = await fetch(`https://api3.dev.merso.io/buy-token-with-merso`, {
method: 'POST',
headers: headers,
body: JSON.stringify({
userAddress,
tokenId,
price,
collectionAddress
})
});
const buyResponse = await fetch(
`${API_BASE_URL}/buy-token-with-merso`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
nftCollectionAddress: MOCK_ERC721_ADDRESS,
tokenId: tokenId,
tokenPrice: tokenPrice,
userAddress: walletAddress,
}),
}
);
if (!buyResponse.ok) {
throw new Error("Buy API request failed");
}
const buyData: ApiResponse = await buyResponse.json();
// Execute buy transaction
const buyTx = await signer.sendTransaction({
to: buyData.txData.to,
from: buyData.txData.from,
data: buyData.txData.data,
gasPrice: buyData.txData.gasPrice,
nonce: buyData.txData.nonce,
value: buyData.txData.value,
});
// Wait for buy transaction to be mined
await buyTx.wait();
} catch (error) {
console.error('NFT purchase failed:', error);
throw error;
}
}🔄 Integration Flow
Complete Purchase Flow
const handleBuy = async (tokenId: number) => {
if (!window.ethereum || !walletAddress) return;
setIsLoading(true);
setError("");
try {
const provider = new ethers.BrowserProvider(window.ethereum as any);
const signer = await provider.getSigner();
const tokenPrice = ethers.parseEther("100").toString();
// Step 1: Call your API for approval transaction
const approvalResponse = await fetch(
`https://api3.dev.merso.io/user-approval`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
userAddress: walletAddress,
userEmail: "test@test.com",
tokenPrice: tokenPrice,
gameTokenAddress: MOCK_ERC20_ADDRESS,
}),
}
);
if (!approvalResponse.ok) {
throw new Error("Approval API request failed");
}
const approvalData: ApiResponse = await approvalResponse.json();
if (!approvalData.success) {
throw new Error("Approval API returned error");
}
// Execute approval transaction
const approvalTx = await signer.sendTransaction({
to: approvalData.txData.to,
from: approvalData.txData.from,
data: approvalData.txData.data,
gasPrice: approvalData.txData.gasPrice,
nonce: approvalData.txData.nonce,
value: approvalData.txData.value,
});
// Wait for approval transaction to be mined
await approvalTx.wait();
console.log("Approval transaction confirmed:", approvalTx.hash);
// Step 2: Call your API for buy transaction
const buyResponse = await fetch(
`https://api3.dev.merso.io/buy-token-with-merso`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
nftCollectionAddress: MOCK_ERC721_ADDRESS,
tokenId: tokenId,
tokenPrice: tokenPrice,
userAddress: walletAddress,
}),
}
);
if (!buyResponse.ok) {
throw new Error("Buy API request failed");
}
const buyData: ApiResponse = await buyResponse.json();
if (!buyData.success) {
throw new Error("Buy API returned error");
}
// Execute buy transaction
const buyTx = await signer.sendTransaction({
to: buyData.txData.to,
from: buyData.txData.from,
data: buyData.txData.data,
gasPrice: buyData.txData.gasPrice,
nonce: buyData.txData.nonce,
value: buyData.txData.value,
});
// Wait for buy transaction to be mined
await buyTx.wait();
console.log("Buy transaction confirmed:", buyTx.hash);
// Optionally reload NFTs
await loadNFTs();
} catch (err: any) {
setError(
"Transaction failed: " +
(err?.reason || err?.message || "Unknown error")
);
console.error(err);
}
setIsLoading(false);
};```🪄 Optional endpoints
Endpoint: GET /user-loans
Purpose: Retrieves loan information for a specific user
Request:
curl -X GET "https://api3.dev.merso.io/user-loans?userEmail=USER_EMAIL" \
-H "Authorization: Bearer <your_token>"Parameters:
userId(string): User's ID
Response:
{
"loans": [
{
"id": "67829bea-00ef-45eb-bc23-0d6798e048f5",
"user_id": "USER_ID",
"collection_id": "19d210ae-5836-4cf0-ad7a-8d8a6b0f08b3",
"nft_id": "nftCromo2",
"initial_payment_usd": 250,
"splits_left_no": 4,
"price_usd": 500,
"paid_status": 1,
"game_id": "e6d8a143-3d70-45e2-9e4c-75ff7805e0fd",
"initial_splits_payments": 2,
"initial_payment_token": 2500000000000000000,
"price_token": 5000000000000000000,
"wallet_address": "0x1234567890ABCDEF1234567890ABCDEF12345678",
"created_at": "2025-07-28T08:02:57.744Z",
"paid_date": "2025-07-29T05:00:54.838Z"
}
]
}Example Usage
Here's an example of how you can call the GET /user-loans endpoint using JavaScript:
const fetchUserLoans = async (userId, jwtToken) => {
try {
const response = await fetch(`https://api3.dev.merso.io/user-loans?userEmail=${userEmail}`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${jwtToken}`
}
});
if (!response.ok) {
throw new Error(`Error: ${response.statusText}`);
}
const data = await response.json();
console.log('User Loans:', data);
return data;
} catch (error) {
console.error('Failed to fetch user loans:', error);
throw error;
}
};
// Example usage
const userEmail = 'USER_EMAIL';
const jwtToken = 'YOUR_JWT_TOKEN';
fetchUserLoans(userId, jwtToken)
.then(loans => {
console.log('Loans data:', loans);
})
.catch(error => {
console.error('Failed to get loans:', error);
});Last updated