Belong CheckIn Guide for MCP
Overview
This guide explains how to manage venue deposits, customer payments, promoter distributions, venue rule updates, and payment cancellations using MCP tools for the Belong CheckIn workflow on EVM-compatible blockchains. The process supports bounty configurations (e.g., visit and spend bounties), referrals, sponsored gas eligibility, and venue settings. For detailed tool specifications, see CheckIn MCP Tools.
Prerequisites: Make sure MCP integration is set up and your API key is configured.
Process Flow
flowchart TD;
A[Start: Venue Setup] --> B[Venue Deposit]
B --> C[Configure Rules]
C --> D[Customer Payment to Venue]
D --> E[Promoter Payment Distribution]
E --> F[Rewards Distributed]
style A fill:#e1f5fe
style D fill:#fff3e0
style E fill:#f3e5f5
| Enum | Description | Values |
|---|---|---|
| PaymentTypes | Defines accepted payment tokens. | 0: NoType · 1: USDC · 2: LONG · 3: Both |
| BountyTypes | Defines reward trigger types. | 0: NoType · 1: VisitBounty · 2: SpendBounty · 3: Both |
| BountyAllocationTypes | Defines bounty recipient. | 0: NoType · 1: ToPromoter · 2: ToCustomer · 3: Both |
| LongPaymentTypes | Defines LONG token handling logic. | 0: NoType · 1: AutoStake · 2: AutoConvert |
Important Notes
Owner vs Venue Address
For venue management operations, the API now distinguishes two addresses:
ownerAddress— the main EOA wallet used for ownership/auth checks. It must belong to the authenticated user.venueAddress— the target venue account used in on-chain calls and signatures.
Behavior notes:
venueDepositandupdateVenueSettingsvalidate ownership usingownerAddress.- Transactions are still prepared for
venueAddress. - Existing venue records are protected: if a venue already belongs to another user, update/deposit is rejected with ownership error.
- Venue storage is keyed by
venueAddress + chainId, so one owner can manage multiple venue addresses. - Venue can be linked to one hub (
hubId) and one activity (activityId). - Each hub/activity can reference only one venue.
Gasless Venue Flag
venueDeposit and updateVenueSettings also support gasless?: boolean.
gasless: trueenables sponsorship eligibility checks for the venue.venueresponses now includegasless.- For sponsored flows, the venue flag is only one part of the check. The actual sponsor balance, allowed operations, and reservations are validated through the sponsorship API. See Sponsored Gas Ledger.
Bounty Configuration Validation
The system validates bounty configurations based on bountyType and bountyAllocationType at the service layer (in getAndValidateBountyAllocations method):
- Bounty Type Validation (
bountyType):NoType (0): BothvisitBountyAmountandspendBountyPercentagemust be0for all allocationsVisitBounty (1):spendBountyPercentagemust be0for all allocationsSpendBounty (2):visitBountyAmountmust be0for all allocationsBoth (3):visitBountyAmountandspendBountyPercentagemust be non-negative. Active allocation can use visit, spend, or both.
- Bounty Allocation Type Validation (
bountyAllocationType):ToPromoter (1):toCustomerBountymust be{ visitBountyAmount: 0, spendBountyPercentage: 0 }ToCustomer (2):toPromoterBountymust be{ visitBountyAmount: 0, spendBountyPercentage: 0 }NoType (0): BothtoCustomerBountyandtoPromoterBountymust be zeroBoth (3): Both can have non-zero values (subject tobountyTypevalidation)
- During payment (
payToVenue):- System validates that
toCustomerBountyandtoPromoterBountyare provided from the database - Validates venue token balance (must be > 0)
- Validates promoter exists if
bountyAllocationTypeisToPromoterorBoth - Validates customer address ownership
- System validates that
Example error scenarios:
bountyType = 3(Both),bountyAllocationType = 1(ToPromoter),toPromoter = {visitBountyAmount: 1, spendBountyPercentage: -1}- Result: Validation fails - values must be non-negative
bountyAllocationType = 1(ToPromoter),toCustomerBounty = {visitBountyAmount: 5, spendBountyPercentage: 2}- Result: Validation fails -
toCustomerBountymust be zero whenbountyAllocationType = ToPromoter
- Result: Validation fails -
Bounty Allocation Types
The bountyAllocationType enum values match the contract:
0: NoType — No bounty allocation1: ToPromoter — Bounty goes to promoter only2: ToCustomer — Bounty goes to customer only3: Both — Bounty split between customer and promoter
LONG Payment Preconditions
For LONG token payments (paymentIn = 2), the system validates that the escrow contract has sufficient LONG token balance before processing the payment. If the escrow balance is insufficient, the request will fail with INSUFFICIENT_BALANCE error.
Bounty Allocations
The API requires toCustomerBounty and toPromoterBounty in venueDeposit.
In updateVenueSettings, these fields are optional and used when reward config must be changed. These fields define the bounty distribution:
toCustomerBounty: Required object withvisitBountyAmount(USDC, human-readable) andspendBountyPercentage(0-100, human-readable)toPromoterBounty: Required object withvisitBountyAmount(USDC, human-readable) andspendBountyPercentage(0-100, human-readable)
Validation: All bounty allocations are validated at the service layer using the getAndValidateBountyAllocations method, which checks:
- Values must match the
bountyAllocationType:- If
bountyAllocationType = ToPromoter, thentoCustomerBountymust be{ visitBountyAmount: 0, spendBountyPercentage: 0 } - If
bountyAllocationType = ToCustomer, thentoPromoterBountymust be{ visitBountyAmount: 0, spendBountyPercentage: 0 } - If
bountyAllocationType = NoType, both must be zero - If
bountyAllocationType = Both, both can have non-zero values
- If
- Values must match the
bountyTypeconstraints (see Bounty Configuration Validation above)
MCP Integration
MCP tools for CheckIn live in the dedicated guide. See CheckIn MCP Tools for configuration, inputs, and outputs.
Usage Examples
Venue Deposit
/*
* venueDeposit(ownerAddress, venueAddress, rules, amount, referralAddress, toCustomerBounty, toPromoterBounty)
* Deposits funds into a venue contract and configures payment rules.
*/
const depositResult = await mcp.callTool("/crypto/evm/venue-deposit", {
method: "POST",
body: {
chainId: 56,
ownerAddress: "0xOwnerEOA", // Required: EOA used for ownership check
venueAddress: "0xVenueAddress",
amount: 10, // Deposit amount in USDC (human-readable format)
rules: {
paymentType: 3, // Both (USDC + LONG)
bountyType: 3, // Both (Visit + Spend)
bountyAllocationType: 3, // Both (ToCustomer + ToPromoter)
longPaymentType: 1, // AutoStake
},
referralAddress: "0xPromoterAddress", // Optional: promoter address for affiliate tracking
toCustomerBounty: {
// Required: customer bounty allocation
visitBountyAmount: 5, // USDC (human-readable)
spendBountyPercentage: 2, // 0-100 (human-readable)
},
toPromoterBounty: {
// Required: promoter bounty allocation
visitBountyAmount: 3, // USDC (human-readable)
spendBountyPercentage: 1, // 0-100 (human-readable)
},
dailyLimits: 100, // Optional: daily limits for venue
hubId: "68da7c5fadf298b35a9b411b", // Optional: hub ID for venue (MongoDB ObjectId)
activityId: "68da7c5fadf298b35a9b411b", // Optional: activity ID for venue (MongoDB ObjectId)
gasless: true, // Optional: enable sponsorship eligibility checks for this venue
},
});
// Response structure:
// {
// address_token: string, // Token address for approval (USDC)
// address: string, // Check-in contract address
// venueAddress: string,
// params: [venueInfo, protection],
// method: { ... }, // ABI-encoded method details
// totalAmountToApprove: string // Total amount needed for token approval (deposit amount + all fees)
// }
// venueInfo contains: rules, venue, amount, affiliateReferralCode, uri
// protection contains: nonce, deadline, signature
// venue-deposit is crypto-only and always returns signable transaction params.
// Sign and broadcast approve + deposit transaction
Pay to Venue
/*
* payToVenue(customer, venueToPayFor, promoter, amount, paymentIn)
* Processes customer payments to a venue with automatic bounty distribution.
* Note: promoter is optional, but required if bountyAllocationType is ToPromoter or Both.
*/
let promoter = testAddresses.promoter;
// Check if the promoter exists on-chain
const isExistsPromoter = await mcp.callTool("/crypto/evm/find-promoter", {
method: "POST",
body: {
chainId: 56,
promoter,
},
});
// If promoter does not exist, deploy a new one and use the user's address
if (isExistsPromoter === "failed") {
// You need to deploy a promoter first. See the guide here: Deploy Promoter
promoter = account.address.value!;
}
// Fetch venue data to determine which tokens are available for payment
const venueData = await mcp.callTool("/crypto/evm/venue", {
method: "POST",
body: {
address: "0xVenueAddress",
chainId: 56,
},
});
// Prepare payment request body
// Note: Requires authentication - customer address must be owned by authenticated user
const body = {
chainId: 56,
customer: "0xCustomerAddress", // Must be owned by authenticated user
venueToPayFor: "0xVenueAddress",
promoter: "0xPromoterAddress", // Optional: required if bountyAllocationType is ToPromoter or Both
amount: 5, // Payment amount in human-readable format
paymentIn: 1, // 1 = USDC, 2 = LONG (enum PaymentTypes)
};
// For LONG payments (paymentIn = 2), the system automatically validates
// that the escrow contract has sufficient LONG token balance.
// If balance is insufficient, the request will fail with INSUFFICIENT_BALANCE error.
// Get transaction parameters from MCP
const { params, address_token, address, method } = await mcp.callTool(
"/crypto/evm/pay-to-venue",
{
method: "POST",
body,
},
);
// params structure: [customerInfo, protection]
// customerInfo contains:
// - paymentInUSDtoken: boolean (true = USDC, false = LONG)
// - toCustomer: { visitBountyAmount: string, spendBountyPercentage: string }
// - toPromoter: { visitBountyAmount: string, spendBountyPercentage: string }
// - customer: address
// - venueToPayFor: address
// - promoterReferralCode: bytes32
// - amount: string (in wei)
// protection contains: nonce, deadline, signature
// Convert amount to the correct token units (if needed for approval)
const parseAmount: bigint =
body.paymentIn === PaymentTypes.LONG
? parseUnits(String(body.amount), 18) // LONG has 18 decimals
: parseUnits(String(body.amount), 6); // USDC has 6 decimals
// Approve the token for the payment contract (if using ERC20)
// Send the payment transaction and wait for confirmation
Distribute Promoter Payments
When a venue sponsor covers this operation, the backend can sign and broadcast
distributePromoterPayments itself and return only the transaction hash. If
backend submission is disabled or the sponsor is not eligible/funded, the tool
falls back to the legacy client-submitted transaction params.
/*
* distributePromoterPayments(promoter, venue, paymentInUSDC)
* Transfers accumulated promoter rewards from a venue contract.
*/
const distributeResult = await mcp.callTool(
"/crypto/evm/distribute-promoter-payments",
{
method: "POST",
body: {
chainId: 56,
promoter: "0xPromoterAddress",
venue: "0xVenueAddress",
paymentInUSDC: false, // true = USDC, false = LONG
},
},
);
// Backend-submitted response:
// {
// address: "0xCheckInAddress",
// submitted: true,
// txHash: "0x...",
// transactionStatus: "success" | "pending",
// signatureExpiresAt?: string
// }
//
// In this case, do not ask the user to sign another transaction. Store/show the
// txHash and refresh the rewards state.
// Client-submitted fallback response:
// {
// address: "0xCheckInAddress",
// params: [promoterInfo, protection],
// method: { ... }
// }
// promoterInfo contains: paymentInUSDtoken, promoterReferralCode, venue, amountInUSD
// protection contains: nonce, deadline, signature
// For fallback responses only, sign and broadcast the distribution transaction.
Get Venue Data
const venueData = await mcp.callTool("/crypto/evm/venue", {
method: "POST",
body: {
address: "0xVenueAddress",
chainId: 56,
},
});
// Response: {
// venue: "0xVenueAddress",
// hubId: "68da7c5fadf298b35a9b411b",
// activityId: "68da7c5fadf298b35a9b411b",
// gasless: true,
// rules: {...},
// remainingCredits: number,
// toCustomerBounty: { visitBountyAmount: number, spendBountyPercentage: number },
// toPromoterBounty: { visitBountyAmount: number, spendBountyPercentage: number },
// venueId: string,
// venueTokenBalance: string,
// usdTokenDeposits: string,
// longDeposits: string
// }
// venueData.venue - Venue address
// venueData.hubId - Linked hub ID
// venueData.activityId - Linked activity ID
// venueData.gasless - Whether sponsorship eligibility checks are enabled for this venue
// venueData.rules - Current venue rules (paymentType, bountyType, etc.)
// venueData.remainingCredits - Number of free deposits without commission (limit is 2)
// venueData.toCustomerBounty - Customer bounty allocation from database
// venueData.toPromoterBounty - Promoter bounty allocation from database
// venueData.venueId - Venue ID (on-chain identifier)
// venueData.venueTokenBalance - Venue ERC-1155 credit balance in USD token units (human-readable format)
// venueData.usdTokenDeposits - Current USD token balance remaining in escrow (human-readable format)
// venueData.longDeposits - Current LONG balance remaining in escrow (human-readable format)
Emergency Cancel Payment
/*
* emergencyCancelPayment(venue, promoter)
* Compatibility-only route.
* Server-side execution is temporarily disabled on the backend.
*/
const cancelResult = await mcp.callTool(
"/crypto/evm/emergency-cancel-payment",
{
method: "POST",
body: {
chainId: 56,
venue: "0xVenueAddress",
promoter: "0xPromoterAddress",
},
},
);
// Current behavior: backend returns a disabled error
Update Venue Settings
/*
* updateVenueSettings(ownerAddress, venueAddress, paymentType?, longPaymentType?, toCustomerBounty?, toPromoterBounty?, dailyLimits?, hubId?, activityId?, gasless?)
* Updates venue settings (payments, rewards, and venue links) in a single operation.
* Ownership is verified by ownerAddress, but on-chain venue rules apply to venueAddress.
* All fields are optional, but at least one must be provided: paymentType, longPaymentType, toCustomerBounty, toPromoterBounty, dailyLimits, hubId, activityId, or gasless.
* For payments: updates paymentType and/or longPaymentType.
* For rewards: automatically determines bountyType and bountyAllocationType based on provided bounty values.
* Validates all inputs and updates both on-chain rules (if changed) and off-chain database.
* If any rules changed, returns transaction parameters for updateVenueRules method.
* If rules unchanged, returns only updated data without transaction parameters.
*/
const updateResult = await mcp.callTool("/crypto/evm/update-venue-settings", {
method: "POST",
body: {
ownerAddress: "0xOwnerEOA", // Required: EOA used for ownership check
venueAddress: "0xVenueAddress",
chainId: 56,
// Payment settings (optional)
paymentType: 3, // Optional: 0=NoType, 1=USDC, 2=LONG, 3=Both
longPaymentType: 2, // Optional: 0=NoType, 1=AutoStake, 2=AutoConvert
// Reward settings (optional)
toCustomerBounty: {
// Optional: customer bounty allocation
// Used to automatically determine bountyType and bountyAllocationType
visitBountyAmount: 5, // USDC (human-readable)
spendBountyPercentage: 2, // 0-100 (human-readable)
},
toPromoterBounty: {
// Optional: promoter bounty allocation
// Used to automatically determine bountyType and bountyAllocationType
visitBountyAmount: 3, // USDC (human-readable)
spendBountyPercentage: 1, // 0-100 (human-readable)
},
// Additional settings (optional)
dailyLimits: 100, // Optional: daily limits for venue
hubId: "68da7c5fadf298b35a9b411b", // Optional: hub ID for venue (MongoDB ObjectId)
activityId: "68da7c5fadf298b35a9b411b", // Optional: activity ID for venue (MongoDB ObjectId)
gasless: true, // Optional: enable sponsorship eligibility checks for this venue
},
});
// Response structure (if rules changed):
// {
// venueAddress: "0xVenueAddress",
// chainId: 56,
// venueId: "1", // Venue ID from blockchain
// gasless: true,
// rules: { // Updated venue rules with automatically determined bountyType and bountyAllocationType
// paymentType: 3,
// bountyType: 3, // Automatically determined from bounty values
// bountyAllocationType: 3, // Automatically determined from bounty values
// longPaymentType: 2
// },
// dailyLimits: 100, // Present if provided
// hubId: "68da7c5fadf298b35a9b411b", // Present if provided
// activityId: "68da7c5fadf298b35a9b411b", // Present if provided
// toCustomerBounty: { visitBountyAmount: 5, spendBountyPercentage: 2 }, // Present only if provided in input
// toPromoterBounty: { visitBountyAmount: 3, spendBountyPercentage: 1 }, // Present only if provided in input
// address: "0xCheckInAddress", // Present only if rules changed
// params: [rules], // Array with VenueRules struct - present only if rules changed
// method: { ... } // ABI-encoded method details - present only if rules changed
// }
// Response structure (if rules unchanged):
// {
// venueAddress: "0xVenueAddress",
// chainId: 56,
// venueId: "1",
// gasless: true,
// rules: { ... }, // Updated venue rules
// dailyLimits: 100, // Present if provided
// hubId: "68da7c5fadf298b35a9b411b", // Present if provided
// activityId: "68da7c5fadf298b35a9b411b", // Present if provided
// toCustomerBounty: { visitBountyAmount: 5, spendBountyPercentage: 2 }, // Present only if provided in input
// toPromoterBounty: { visitBountyAmount: 3, spendBountyPercentage: 1 } // Present only if provided in input
// // No address, params, or method fields
// }
// Note: This method replaces the old update-accepted-payments and update-rewards endpoints.
// You can now update payments, rewards, and additional settings in a single call.
// The method automatically determines bountyType and bountyAllocationType based on
// the provided toCustomerBounty and toPromoterBounty values. If these types changed
// compared to current venue rules, transaction parameters are returned for on-chain update.
// The database is always updated with validated settings.
// Sign and broadcast update transaction if address, params, and method are present
Deploy Promoter
/*
* deployPromoter(promoter)
* Deploys a promoter contract for the specified wallet address.
* Requires authentication and checks for promoter uniqueness and ownership.
*/
const deployResult = await mcp.callTool("/crypto/evm/deploy-promoter", {
method: "POST",
body: {
chainId: 56,
promoter: "0xPromoterAddress",
},
});
// Response: { address: "0xFactoryAddress", method: {...} }
// Sign and broadcast the transaction to create a referral code
Find Promoter
/*
* findPromoter(promoter)
* Verifies if a promoter is registered in the system.
* Returns 'success' if the promoter exists with a valid referral code, or 'failed' otherwise.
*/
const promoterStatus = await mcp.callTool("/crypto/evm/find-promoter", {
method: "POST",
body: {
chainId: 56,
promoter: "0xPromoterAddress",
},
});
// Response: "success" | "failed"
// Promoter status: promoterStatus
Get Belong CheckIn Storage
/*
* getBelongCheckInStorage(chainId)
* Retrieves the Belong CheckIn contract storage data including contract addresses,
* payment configuration, fees structure, and helper/check-in contract addresses.
* Returns data with BigInt values converted to strings for JSON serialization.
*/
const storage = await mcp.callTool("/crypto/evm/get-belong-check-in-storage", {
method: "POST",
body: {
chainId: 56,
},
});
// Response structure:
// {
// contracts: {
// factory: string, // Factory contract address
// escrow: string, // Escrow contract address
// staking: string, // Staking contract address
// venueToken: string, // Venue token contract address
// promoterToken: string, // Promoter token contract address
// longPF: string, // LONG price feed address
// },
// paymentsInfo: {
// dexType: number, // DEX type enum value
// slippageBps: number, // Max slippage in basis points
// router: string, // DEX router address
// usdToken: string, // USD token address (USDC)
// long: string, // LONG token address
// maxPriceFeedDelay: number, // Max delay for price feeds (seconds)
// poolKey: string, // Pool key bytes
// hookData: string, // Hook data bytes
// },
// fees: {
// referralCreditsAmount: number, // Referral credit value
// affiliatePercentage: number, // Affiliate fee percentage
// longCustomerDiscountPercentage: number, // LONG discount for customers
// platformSubsidyPercentage: number, // Platform subsidy percentage
// processingFeePercentage: number, // Processing fee
// buybackBurnPercentage: number, // Buyback and burn percentage
// },
// helperContract: string, // Helper contract address
// checkInContract: string, // Check-In contract address
// }
Error Handling
MCP tools return standardized errors in the response's error field.
Example:
{
"error": "VENUE_NOT_FOUND",
"message": "The specified venue contract was not found on this chain."
}
Common Errors:
VENUE_NOT_FOUND— Venue address not registered or has no venue token balance.INSUFFICIENT_FUNDS— Insufficient deposit balance.INSUFFICIENT_BALANCE— Insufficient balance (e.g., LONG escrow balance insufficient for LONG payments).INVALID_SIGNATURE— Authentication or signing issue.UNSUPPORTED_CHAIN— Chain ID not supported by MCP.INVALID_BOUNTY_CONFIGURATION— Bounty configuration violates contract requirements (e.g.,bountyType = Bothbut missing visit or spend bounty).INVALID_BOUNTY_PERCENTAGE— Spend bounty percentage is outside valid range (0-100).NO_BOUNTY_CREDITS— Venue has no venue token balance (venueToken balance is zero).PAYMENT_TYPE_NOT_SUPPORTED— Payment type not compatible with venue rules.
✅ Result: You now have a complete flow for deposits, payments, promoter rewards, and vesting management in the Belong CheckIn system.