Belong.net Logo
Crypto

Belong CheckIn Guide for MCP

End-to-end venue and payment processing on EVM chains using MCP tools for CheckIn features.

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
EnumDescriptionValues
PaymentTypesDefines accepted payment tokens.0: NoType · 1: USDC · 2: LONG · 3: Both
BountyTypesDefines reward trigger types.0: NoType · 1: VisitBounty · 2: SpendBounty · 3: Both
BountyAllocationTypesDefines bounty recipient.0: NoType · 1: ToPromoter · 2: ToCustomer · 3: Both
LongPaymentTypesDefines 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:

  • venueDeposit and updateVenueSettings validate ownership using ownerAddress.
  • 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: true enables sponsorship eligibility checks for the venue.
  • venue responses now include gasless.
  • 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):

  1. Bounty Type Validation (bountyType):
    • NoType (0): Both visitBountyAmount and spendBountyPercentage must be 0 for all allocations
    • VisitBounty (1): spendBountyPercentage must be 0 for all allocations
    • SpendBounty (2): visitBountyAmount must be 0 for all allocations
    • Both (3): visitBountyAmount and spendBountyPercentage must be non-negative. Active allocation can use visit, spend, or both.
  2. Bounty Allocation Type Validation (bountyAllocationType):
    • ToPromoter (1): toCustomerBounty must be { visitBountyAmount: 0, spendBountyPercentage: 0 }
    • ToCustomer (2): toPromoterBounty must be { visitBountyAmount: 0, spendBountyPercentage: 0 }
    • NoType (0): Both toCustomerBounty and toPromoterBounty must be zero
    • Both (3): Both can have non-zero values (subject to bountyType validation)
  3. During payment (payToVenue):
    • System validates that toCustomerBounty and toPromoterBounty are provided from the database
    • Validates venue token balance (must be > 0)
    • Validates promoter exists if bountyAllocationType is ToPromoter or Both
    • Validates customer address ownership

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 - toCustomerBounty must be zero when bountyAllocationType = ToPromoter

Bounty Allocation Types

The bountyAllocationType enum values match the contract:

  • 0: NoType — No bounty allocation
  • 1: ToPromoter — Bounty goes to promoter only
  • 2: ToCustomer — Bounty goes to customer only
  • 3: 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 with visitBountyAmount (USDC, human-readable) and spendBountyPercentage (0-100, human-readable)
  • toPromoterBounty: Required object with visitBountyAmount (USDC, human-readable) and spendBountyPercentage (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, then toCustomerBounty must be { visitBountyAmount: 0, spendBountyPercentage: 0 }
    • If bountyAllocationType = ToCustomer, then toPromoterBounty must be { visitBountyAmount: 0, spendBountyPercentage: 0 }
    • If bountyAllocationType = NoType, both must be zero
    • If bountyAllocationType = Both, both can have non-zero values
  • Values must match the bountyType constraints (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 = Both but 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.

Copyright © 2026