Belong.net Logo
Crypto

Sponsored Gas Ledger Guide

End-to-end sponsorship ledger, eligibility checks, and usage recording for sponsored EVM flows in Belong API.

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:

  1. call POST /api/v3/sponsorship/check
  2. submit the sponsored transaction through thirdweb
  3. thirdweb calls POST /api/v3/sponsorship/thirdweb/verify
  4. 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:

  • approve
  • mint
  • pay_to_venue

Behavior:

  • approve is implicit when a target is gasless: true
  • mint and pay_to_venue must be explicitly enabled in sponsor settings
  • distribute_promoter_payments can be enabled in sponsor settings, but it is used only by the CheckIn backend-submitted promoter withdrawal flow. It is not a browser /sponsorship/check operation.

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:
    • totalDepositedWei
    • totalSpentWei
    • remainingWei

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:
    • chainId
    • from == sponsorAddress
    • to == platform sponsorship wallet for the chain
    • value == 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 for approveAmountWei
  • 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: null
  • remainingWei: null
  • additionalOperationTypes: []

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_SECRET is required for verifier callbacks
  • THIRDWEB_SPONSORSHIP_CLIENT_IDS is an optional comma-separated allowlist of thirdweb client IDs
  • THIRDWEB_SPONSORSHIP_ENTRYPOINT_ADDRESSES is 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; mint and pay_to_venue may 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 * effectiveGasPrice for direct and EIP-7702 transactions
  • for ERC-4337 transactions, backend uses UserOperationEvent.actualGasCost
  • backend records confirmed for successful receipts and failed for reverted receipts
  • backend verifies authenticated ownership of actorAddress or ownerAddress
  • 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, and value match the completed operation
  • for EIP-7702 transactions, backend requires type 4 / authorizationList, checks tx.to against the execution account, decodes thirdweb executeWithSig, and verifies the single inner call target, calldata, and native value
  • for ERC-4337 account-abstraction transactions, frontend must also send entryPointAddress and may send userOpHash
  • for ERC-4337 transactions, backend decodes EntryPoint.handleOps, verifies the inner smart-account execute/executeBatch target, value, and calldata, and reads actual gas/status from UserOperationEvent
  • if txHash is 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 txHash or receipt data
  • backend resolves the sponsor from the venue or collection using the same target resolution as /sponsorship/check
  • backend verifies authenticated ownership of ownerAddress for approve, or actorAddress for mint and pay_to_venue
  • backend releases only the active reservation matching the resolved sponsor, chainId, operation type, and operation metadata
  • for approve, the matching metadata is ownerAddress, tokenAddress, spenderAddress, and approveAmountWei
  • for mint, the matching metadata is actorAddress and collectionId
  • for pay_to_venue, the matching metadata is actorAddress and venueAddress
  • 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/complete for thirdweb-sponsored flows
  • sponsorAddress must 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, and pay_to_venue, metadata is required so reservation locks can be released correctly
  • for reserved operations, amountWei must be less than or equal to the active reservation amount
  • failed usage 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 from recorded, but cannot change amount, context, operation, sponsor, chain, or metadata

End-to-End Flow

  1. Owner enables gasless on a venue or collection.
  2. Sponsor updates allowed operations if needed.
  3. Sponsor tops up the shared platform wallet.
  4. Client calls POST /api/v3/sponsorship/deposits/record.
  5. Before approve, mint, or pay_to_venue, client calls POST /api/v3/sponsorship/check.
  6. Thirdweb calls POST /api/v3/sponsorship/thirdweb/verify before sponsoring gas.
  7. External wallet or executor signs and broadcasts only the checked transaction.
  8. Frontend calls POST /api/v3/sponsorship/thirdweb/complete after 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

  • balance and usage are owner-only
  • check is actor-owned, not public
  • usage/record is not a browser route
  • thirdweb verifier is unauthenticated but protected by x-belong-thirdweb-verifier-secret
  • usage/record is 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
Copyright © 2026