Sponsored Gas Ledger Guide
Overview
Belong API includes a sponsorship ledger for shared sponsored-gas flows.
This is a general backend layer, not a CheckIn-only feature. It is designed to support:
- CheckIn
- NFT mint
- future NFT membership flows
- other sponsored EVM operations
For browser-based thirdweb sponsorship, the backend does not broadcast the transaction. It only:
- verifies sponsor top-ups into the shared platform wallet
- tracks sponsor balances inside Belong API
- stores sponsor operation settings
- checks eligibility before a sponsored operation
- verifies thirdweb sponsored-gas callbacks against the checked calldata
- records sponsored usage from transaction receipts after completion
There is one server-side exception: CheckIn promoter reward withdrawals can be
backend-submitted when the venue sponsor has explicitly enabled
distribute_promoter_payments and has enough gas-bank balance. In that flow,
Belong API reserves the estimated gas, signs and broadcasts
distributePromoterPayments, returns the tx hash to the client, and later records
actual receipt gas against the sponsor ledger.
For browser-based thirdweb sponsored gas, the enforced flow is:
- call
POST /api/v3/sponsorship/check - submit the sponsored transaction through thirdweb
- thirdweb calls
POST /api/v3/sponsorship/thirdweb/verify - after the transaction has a receipt, the frontend calls
POST /api/v3/sponsorship/thirdweb/complete
If thirdweb rejects the sponsored transaction before broadcast and there is no txHash, the frontend may call POST /api/v3/sponsorship/thirdweb/cancel to release the temporary reservation. Once a transaction is broadcast or a receipt exists, use /thirdweb/complete even when the receipt failed, because sponsored gas may already have been spent.
For server-side integrations that do not use thirdweb verifier callbacks, a trusted backend can still call POST /api/v3/sponsorship/usage/record directly with a Belong API key.
There should be no sponsored execution path that bypasses the check and ledger reservation.
Core Model
Ledger key:
sponsorAddress + chainId
Balance formula:
remainingWei = confirmed deposits - recorded/confirmed/failed usage
failed usage is counted as spent because a failed on-chain transaction can still burn sponsored gas. Do not record failed usage for operations that were never broadcast.
Important properties:
- one shared sponsorship wallet can be topped up by many sponsors
- sponsor balances are isolated inside Belong API
- deposits are idempotent by
txHash - usage records are idempotent by
txHash
POST /api/v3/sponsorship/check reserves a maximum gas budget. Completion records actual gas from on-chain proof:
direct tx / EIP-7702 sponsored tx:
actualGasWei = receipt.gasUsed * receipt.effectiveGasPrice
ERC-4337:
actualGasWei = UserOperationEvent.actualGasCost
Actual gas may be lower than the reservation. Usage is rejected only when actual gas exceeds the reserved amount.
Supported Operation Types
Current preflight sponsorship checks support:
approvemintpay_to_venue
Behavior:
approveis implicit when a target isgasless: truemintandpay_to_venuemust be explicitly enabled in sponsor settingsdistribute_promoter_paymentscan be enabled in sponsor settings, but it is used only by the CheckIn backend-submitted promoter withdrawal flow. It is not a browser/sponsorship/checkoperation.
Gasless Targets
Sponsorship eligibility depends on both the sponsor and the target:
Venue.gasless- linked
Activity.gasless - linked
Hub.gasless NftCollection.gasless
For venues, sponsorship is enabled when the venue itself, its linked activity, or its linked hub has gasless: true. For NFT collections, sponsorship is enabled by NftCollection.gasless.
If gasless is disabled for the resolved target, sponsorship check returns canSponsor: false.
Toggle Gasless Targets
Venue gasless eligibility can be toggled with:
POST /api/v3/crypto/evm/venue-gasless
{
"ownerAddress": "0xOwnerAddress",
"venueAddress": "0xVenueAddress",
"chainId": 137,
"enabled": true
}
This route requires authentication and venue ownership. It updates off-chain gasless settings only; it does not send or sponsor a transaction.
NFT collection gasless eligibility can be toggled with:
POST /api/v3/nft-collection/:id/gasless
{
"enabled": true
}
This route requires authentication and collection ownership. It updates NftCollection.gasless and keeps the linked hub/activity gasless flag in sync when present.
API Routes
Get Balance
GET /api/v3/sponsorship/balance?walletAddress=0x...&chainId=137
- owner-only
- returns:
totalDepositedWeitotalSpentWeiremainingWei
Get Usage
GET /api/v3/sponsorship/usage?walletAddress=0x...&chainId=137
- owner-only
- returns sponsorship usage history for that sponsor wallet and chain
Get Deposits
GET /api/v3/sponsorship/deposits?walletAddress=0x...&chainId=137
- owner-only
- returns sponsorship deposit history for that sponsor wallet and chain
Get Settings
GET /api/v3/sponsorship/settings?walletAddress=0x...&chainId=137
- owner-only
- returns:
defaultOperationTypes: ["approve"]additionalOperationTypes
Update Settings
POST /api/v3/sponsorship/settings
{
"walletAddress": "0x...",
"chainId": 137,
"additionalOperationTypes": ["mint", "pay_to_venue", "distribute_promoter_payments"]
}
- owner-only
- updates sponsor-level allowed operation types
Record Deposit
POST /api/v3/sponsorship/deposits/record
{
"sponsorAddress": "0x...",
"chainId": 137,
"txHash": "0x...",
"amountWei": "10000000000000000"
}
Behavior:
- verifies the on-chain transaction
- checks:
chainIdfrom == sponsorAddressto == platform sponsorship wallet for the chainvalue == amountWei
- records the deposit idempotently by
txHash - rate-limited to reduce repeated RPC lookups
- does not move funds or withdraw from any wallet
Check Sponsorship Eligibility
POST /api/v3/sponsorship/check
For approve:
{
"chainId": 137,
"operationType": "approve",
"amountWei": "25000000000000000",
"approveAmountWei": "50000000",
"venueAddress": "0xVenueAddress",
"ownerAddress": "0xUserWallet",
"tokenAddress": "0xTokenAddress",
"spenderAddress": "0xSpenderAddress"
}
For mint:
{
"chainId": 137,
"operationType": "mint",
"amountWei": "6000000000000000",
"collectionId": "collection-id",
"actorAddress": "0xUserWallet"
}
For pay_to_venue:
{
"chainId": 137,
"operationType": "pay_to_venue",
"amountWei": "2500000000000000",
"venueAddress": "0xVenueAddress",
"actorAddress": "0xUserWallet"
}
Behavior:
- validates actor ownership for the authenticated user
- checks target existence and
gasless - checks sponsor settings
- checks sponsor balance
- for
approve, verifies whether allowance is already sufficient forapproveAmountWei - creates a temporary reservation lock to reduce double-spend races
- rate-limited per authenticated user/client to reduce reservation spam
amountWei is the maximum gas reservation amount. For approve, approveAmountWei is the token allowance amount being checked. These values are intentionally separate.
Typical response:
{
"canSponsor": true,
"reasonCode": "ok",
"reasonMessage": "Sponsorship can cover this operation",
"chainId": 137,
"contextType": "checkin",
"operationType": "pay_to_venue",
"sponsorAddress": "0xsponsoraddress",
"gasless": true,
"remainingWei": "7500000000000000",
"amountWei": "2500000000000000",
"venueAddress": "0xvenueaddress",
"collectionId": null,
"actorAddress": "0xuserwallet",
"ownerAddress": null,
"tokenAddress": null,
"spenderAddress": null,
"approveAmountWei": null,
"additionalOperationTypes": ["mint", "pay_to_venue", "distribute_promoter_payments"]
}
When the authenticated actor does not own the sponsor wallet, sponsor details are hidden in the response:
sponsorAddress: nullremainingWei: nulladditionalOperationTypes: []
Backend-Submitted CheckIn Promoter Withdrawals
distribute_promoter_payments is not a browser preflight operation. It is an
allowed sponsor setting for CheckIn promoter reward withdrawals.
When a promoter withdraws venue-funded rewards, Belong API can submit the contract call itself if all conditions are true:
- the venue target is
gasless: true - the sponsor settings include
distribute_promoter_payments - the sponsor gas-bank ledger can reserve the estimated gas cost
- signer policy allows backend distribution submission
The client receives:
{
"address": "0xCheckInContract",
"submitted": true,
"txHash": "0x...",
"transactionStatus": "success",
"signatureExpiresAt": "2026-07-05T12:00:00.000Z"
}
If the sponsor is not eligible or the gas reservation cannot be created, the same CheckIn endpoint falls back to client-submitted transaction params instead of spending platform gas.
Gas accounting is based on transaction receipts for tx hashes the backend
already submitted. It does not require broad eth_getLogs scans.
Thirdweb Verifier
POST /api/v3/sponsorship/thirdweb/verify
Set this URL in the thirdweb dashboard as the Server Verifier URL:
https://<api-host>/api/v3/sponsorship/thirdweb/verify
Configure thirdweb to send this custom header:
x-belong-thirdweb-verifier-secret: <THIRDWEB_SPONSORSHIP_VERIFIER_SECRET>
Environment:
THIRDWEB_SPONSORSHIP_VERIFIER_SECRETis required for verifier callbacksTHIRDWEB_SPONSORSHIP_CLIENT_IDSis an optional comma-separated allowlist of thirdweb client IDsTHIRDWEB_SPONSORSHIP_ENTRYPOINT_ADDRESSESis an optional comma-separated allowlist of ERC-4337 EntryPoint addresses accepted by/thirdweb/complete
For EIP-7702/direct EOA sponsored execution, thirdweb sends the EOA execution account plus one call. The backend accepts equivalent field names used by thirdweb payload variants: from, accountAddress, or sender for the EOA; targetAddress, to, or contractAddress for the target; callData or data for calldata; and nativeValueWei or value for native value.
{
"clientId": "thirdweb-client-id",
"chainId": 137,
"accountAddress": "0xUserEOA",
"targetAddress": "0xContract",
"callData": "0x...",
"nativeValueWei": "0",
"gasLimit": "120000",
"gasPrice": "30000000000"
}
The legacy ERC-4337 payload is still supported:
{
"clientId": "thirdweb-client-id",
"chainId": 137,
"userOp": {
"sender": "0xSmartAccount",
"targets": ["0xContract"],
"gasLimit": "120000",
"gasPrice": "30000000000",
"data": {
"targets": ["0xContract"],
"callDatas": ["0x..."],
"values": ["0"]
}
}
}
Response:
{
"isAllowed": true
}
Policy denials return 200:
{
"isAllowed": false,
"reason": "Matching sponsorship reservation was not found"
}
Missing or invalid verifier secret returns 401.
Verifier behavior:
- rejects batch operations; exactly one target, calldata, and value are allowed
- rejects non-zero native value for ERC20
approve;mintandpay_to_venuemay use native value when the decoded operation and reservation match - calculates
gasBudgetWei = gasLimit * gasPrice - decodes calldata instead of trusting frontend labels
- checks target contract, business context, sponsor settings, gasless state, and active reservation
- rejects approve calldata if token, spender, or approve amount differs from the checked reservation
- stores a short-lived server-side approval marker for the exact EOA actor/owner, execution account, target, calldata, native value, sponsor, chain, and operation that was allowed
Supported calldata:
- ERC20
approve(address spender, uint256 amount) - CheckIn
payToVenue(...) - NFT
mintDynamicPrice(...) - NFT
mintStaticPrice(...)
Complete Thirdweb Usage
POST /api/v3/sponsorship/thirdweb/complete
Frontend calls this route after the thirdweb-sponsored transaction has a receipt.
For direct EOA and thirdweb EIP-7702 transactions, smartAccountAddress is not required. The backend records the operation against actorAddress or ownerAddress and uses the execution account from smartAccountAddress, accountAddress, from, or the actor/owner address.
Direct EOA completion verifies that the RPC transaction from, to, input, and value match the completed operation. Thirdweb EIP-7702 sponsored completion verifies the transaction type 4 / authorizationList proof, requires tx.to to be the delegated EOA execution account, decodes the wrapped executeWithSig call, and verifies the inner target, calldata, and native value.
{
"clientId": "thirdweb-client-id",
"chainId": 137,
"txHash": "0x...",
"targetAddress": "0xCollectionContract",
"callData": "0x...",
"nativeValueWei": "0",
"operationType": "mint",
"contextType": "nft",
"collectionId": "collection-id",
"actorAddress": "0xUserWallet"
}
For approve:
{
"clientId": "thirdweb-client-id",
"chainId": 137,
"txHash": "0x...",
"targetAddress": "0xTokenAddress",
"callData": "0x...",
"nativeValueWei": "0",
"operationType": "approve",
"contextType": "checkin",
"venueAddress": "0xVenueAddress",
"ownerAddress": "0xUserWallet",
"tokenAddress": "0xTokenAddress",
"spenderAddress": "0xSpenderAddress",
"approveAmountWei": "50000000"
}
For ERC-4337 account-abstraction transactions, include the EntryPoint proof fields:
{
"entryPointAddress": "0xEntryPointAddress",
"userOpHash": "0xOptionalUserOperationHash"
}
Security rules:
- requires ordinary Belong user auth
- frontend does not send
sponsorAddress - frontend does not send
amountWei - backend resolves the sponsor from the venue or collection
- backend reads the transaction receipt from RPC
- backend computes actual gas as
gasUsed * effectiveGasPricefor direct and EIP-7702 transactions - for ERC-4337 transactions, backend uses
UserOperationEvent.actualGasCost - backend records
confirmedfor successful receipts andfailedfor reverted receipts - backend verifies authenticated ownership of
actorAddressorownerAddress - backend requires a matching active reservation
- backend requires the matching verifier approval marker for the same
clientId, EOA actor/owner, execution account, target, calldata, native value, sponsor, chain, and operation - for direct transactions, backend also checks that the RPC transaction
from,to,input, andvaluematch the completed operation - for EIP-7702 transactions, backend requires type 4 /
authorizationList, checkstx.toagainst the execution account, decodes thirdwebexecuteWithSig, and verifies the single inner call target, calldata, and native value - for ERC-4337 account-abstraction transactions, frontend must also send
entryPointAddressand may senduserOpHash - for ERC-4337 transactions, backend decodes
EntryPoint.handleOps, verifies the inner smart-accountexecute/executeBatchtarget, value, and calldata, and reads actual gas/status fromUserOperationEvent - if
txHashis already recorded, the route returns idempotent success only after ownership, sponsor, chain, context, operation, and metadata match
If the transaction was not broadcast or no receipt exists, usage is not recorded.
Cancel Thirdweb Reservation
POST /api/v3/sponsorship/thirdweb/cancel
Frontend calls this route only when thirdweb rejects a sponsored transaction before broadcast, for example because a thirdweb sponsor policy denies the target contract. The request does not include txHash, receipt data, or sponsorAddress.
For approve:
{
"chainId": 137,
"contextType": "checkin",
"operationType": "approve",
"amountWei": "25000000000000000",
"approveAmountWei": "50000000",
"venueAddress": "0xVenueAddress",
"ownerAddress": "0xUserWallet",
"tokenAddress": "0xTokenAddress",
"spenderAddress": "0xSpenderAddress"
}
For mint:
{
"chainId": 137,
"contextType": "nft",
"operationType": "mint",
"amountWei": "6000000000000000",
"collectionId": "collection-id",
"actorAddress": "0xUserWallet"
}
For pay_to_venue:
{
"chainId": 137,
"contextType": "checkin",
"operationType": "pay_to_venue",
"amountWei": "2500000000000000",
"venueAddress": "0xVenueAddress",
"actorAddress": "0xUserWallet"
}
Response:
{
"success": true,
"released": true
}
Behavior:
- requires ordinary Belong user auth
- frontend does not send
sponsorAddress - frontend does not send
txHashor receipt data - backend resolves the sponsor from the venue or collection using the same target resolution as
/sponsorship/check - backend verifies authenticated ownership of
ownerAddressforapprove, oractorAddressformintandpay_to_venue - backend releases only the active reservation matching the resolved sponsor,
chainId, operation type, and operation metadata - for
approve, the matching metadata isownerAddress,tokenAddress,spenderAddress, andapproveAmountWei - for
mint, the matching metadata isactorAddressandcollectionId - for
pay_to_venue, the matching metadata isactorAddressandvenueAddress - if no matching reservation exists, the route is idempotent and returns
success: true, released: false - the route never records usage
Do not use cancellation for failed on-chain transactions. If a transaction was broadcast or has a receipt, call /api/v3/sponsorship/thirdweb/complete so the backend can record actual gas usage and release the reservation.
Record Usage
POST /api/v3/sponsorship/usage/record
{
"sponsorAddress": "0x...",
"chainId": 137,
"txHash": "0x...",
"amountWei": "2500000000000000",
"status": "confirmed",
"contextType": "checkin",
"operationType": "pay_to_venue",
"metadata": {
"actorAddress": "0xUserWallet",
"venueAddress": "0xVenueAddress"
}
}
Authentication:
- requires a Belong API key with
sponsorship:write - permission shape:
{ "sponsorship": ["write"] } - API key must be kept server-side only and rotated if exposed
Notes:
- this is a trusted server-only completion route
- use it after the external sponsored transaction succeeds or fails
- browsers should use
/api/v3/sponsorship/thirdweb/completefor thirdweb-sponsored flows sponsorAddressmust be an EVM address- endpoint is rate-limited before API-key verification by client fingerprint and after verification by authenticated API-key session
- for
approve,mint, andpay_to_venue, metadata is required so reservation locks can be released correctly - for reserved operations,
amountWeimust be less than or equal to the active reservation amount failedusage counts as spent and should only be recorded after a transaction was broadcast- usage is rejected if the sponsor balance is no longer sufficient after accounting for active reservations
- usage records are idempotent by
txHash; retries may advance status fromrecorded, but cannot change amount, context, operation, sponsor, chain, or metadata
End-to-End Flow
- Owner enables
gaslesson a venue or collection. - Sponsor updates allowed operations if needed.
- Sponsor tops up the shared platform wallet.
- Client calls
POST /api/v3/sponsorship/deposits/record. - Before
approve,mint, orpay_to_venue, client callsPOST /api/v3/sponsorship/check. - Thirdweb calls
POST /api/v3/sponsorship/thirdweb/verifybefore sponsoring gas. - External wallet or executor signs and broadcasts only the checked transaction.
- Frontend calls
POST /api/v3/sponsorship/thirdweb/completeafter the transaction has a receipt, passing the same target, calldata, and native value that thirdweb sent to the verifier.
For non-thirdweb server integrations, step 8 can be replaced by a trusted backend call to POST /api/v3/sponsorship/usage/record.
Notes on Privacy and Auth
balanceandusageare owner-onlycheckis actor-owned, not publicusage/recordis not a browser route- thirdweb verifier is unauthenticated but protected by
x-belong-thirdweb-verifier-secret usage/recordis a server-only integration route; call it only from a trusted executor/integration- sponsorship is tracked in Belong API, not inferred from shared wallet balances