> ## Documentation Index
> Fetch the complete documentation index at: https://docs.0xmeta.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Pre-Settlement Fee Collection

> Understanding 0xmeta's trust-minimized payment architecture with pre-settlement fee collection

## Overview

0xmeta uses **pre-settlement fee collection** to maintain x402's core principle: **trust minimization**. Customer funds flow directly to merchants—never through the facilitator. Fees are collected **before settlement** via standard ERC-20 approval patterns.

<Note>
  **Trust-Minimized with Pre-Settlement:** Customer payments go DIRECTLY to merchants. The facilitator collects the \$0.01 fee from the merchant's pre-approved balance BEFORE executing the settlement. If fee collection fails, settlement is blocked.
</Note>

***

## Payment Architecture

### Trust-Minimized Flow with Pre-Settlement Fee Collection

```mermaid theme={null}
sequenceDiagram
    participant Client
    participant Merchant
    participant Facilitator
    participant Treasury

    Note over Merchant: ONE-TIME SETUP
    Merchant->>Facilitator: approve(treasury, 100 USDC)
    
    Note over Client,Merchant: PAYMENT FLOW
    Client->>Merchant: 1. Request /resource
    Merchant-->>Client: 2. 402 Payment Required<br/>payTo: merchant_address
    
    Client->>Client: 3. Create authorization<br/>to: merchant_address<br/>value: $0.02
    
    Client->>Facilitator: 4. Verify authorization
    Facilitator-->>Client: ✅ Valid
    
    Client->>Facilitator: 5. Settle payment
    
    rect rgb(255, 245, 230)
        Note over Facilitator,Treasury: PRE-SETTLEMENT Fee Collection
        Facilitator->>Treasury: transferFrom(merchant, treasury, $0.01)
        Treasury-->>Facilitator: ✅ Fee collected
    end
    
    rect rgb(230, 245, 255)
        Note over Facilitator,Merchant: Settlement (AFTER Fee)
        Facilitator->>Merchant: transferWithAuthorization<br/>(client → merchant, $0.02)
        Merchant-->>Facilitator: ✅ Payment received
    end
    
    Facilitator-->>Client: ✅ Settled
    Client->>Merchant: 6. Access resource
```

**Key Principle:** Fee collected FIRST (orange), then customer payment executes (blue). Customer funds go DIRECTLY to merchant. No fee = no settlement.

***

## Why This Architecture?

### x402 Trust-Minimization Requirement

**From x402 specification:**

> "The facilitator must never have custody or control over customer payments. All funds must flow directly from payer to payee."

**Previous approach (REJECTED):**

```
❌ Client → Treasury → Merchant
   Problem: Facilitator custody = trust required
```

**Current approach (APPROVED):**

```
✅ Fee: Merchant → Treasury (FIRST, via transferFrom)
✅ Payment: Client → Merchant (THEN, direct payment)
   Solution: No facilitator custody = trust-minimized
   Guarantee: No fee collection = no settlement
```

### Pre-Settlement Enforcement

**Why collect fee BEFORE settlement?**

1. **Prevents free service:** Merchants cannot exploit failed settlements
2. **Guarantees payment:** Facilitator only executes if paid
3. **Atomic guarantee:** Fee collection failure blocks settlement
4. **Economic sustainability:** Every settlement attempt costs merchant

**Trade-off:** Merchant pays \$0.01 even if settlement fails after fee collection.

**Rationale:** This is payment for the verification and settlement attempt service. Without this, merchants could intentionally cause settlement failures for free verification.

### ERC-20 Approval Pattern

Standard pattern used across DeFi:

```solidity theme={null}
// Merchant approves facilitator treasury (one-time)
USDC.approve(facilitatorTreasury, 100 * 10^6); // 100 USDC

// Before each settlement, facilitator collects fee FIRST
USDC.transferFrom(merchant, treasury, 0.01 * 10^6); // $0.01

// Then (and only then) executes customer payment
transferWithAuthorization(...);
```

**Benefits:**

* ✅ Standard ERC-20 pattern (well understood)
* ✅ Merchant controls via approval amount
* ✅ Auditable on-chain
* ✅ Can revoke anytime (settlements will fail)
* ✅ Fee collection happens first (no free rides)

***

## Payment Flow Details

### Step 1: One-Time Merchant Approval

Merchant approves facilitator treasury for USDC spending:

```bash theme={null}
# Using provided script
EVM_PRIVATE_KEY=0x... node approve-facilitator.mjs

# Or manually via contract interaction
usdc.approve(
  "0x5D791e3554D0e83f171126905Bda1640Bf6f9A8B", // Treasury
  ethers.parseUnits("100", 6) // 100 USDC = 10,000 settlements
)
```

**Approval amount = settlements \* \$0.01**

Example: 100 USDC approval = 10,000 settlements

### Step 2: Client Requests Resource

Client makes GET request to protected endpoint:

```bash theme={null}
GET /premium-content HTTP/1.1
Host: merchant.com
```

### Step 3: Merchant Returns 402

Server responds with payment requirements:

```json theme={null}
HTTP/1.1 402 Payment Required
x402-accept: exact;price="$0.02";network="eip155:8453";payto="0xMERCHANT"

{
  "scheme": "exact",
  "price": "$0.02",
  "network": "eip155:8453",
  "payTo": "0xA821f428Ef8cC9f54A9915336A82220853059090" // ← Merchant address
}
```

**Critical:** `payTo` must be merchant address, NOT treasury.

### Step 4: Client Creates Authorization

Client signs EIP-3009 authorization to merchant:

```javascript theme={null}
const authorization = {
  from: clientAddress,
  to: merchantAddress,    // ← MERCHANT, not treasury
  value: "20000",         // $0.02 USDC (6 decimals)
  validAfter: "0",
  validBefore: "1735689600",
  nonce: randomNonce(),
  token: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913" // USDC
};

const signature = await signTypedData(authorization);
```

### Step 5: Facilitator Verification

Facilitator validates authorization cryptographically:

```python theme={null}
# Verify signature
recovered_address = recover_signer(authorization, signature)
assert recovered_address == authorization['from'], "Invalid signature"

# Verify recipient
assert authorization['to'] == merchant_address, "Must pay to merchant"

# Verify amount
assert authorization['value'] == expected_amount, "Amount mismatch"

# Return verification_id
```

### Step 6: Pre-Settlement Fee Collection

**BEFORE executing customer payment**, facilitator collects fee:

```python theme={null}
# Check merchant allowance
allowance = usdc.allowance(merchant, treasury)
required = 10000  # $0.01 in wei

if allowance < required:
    raise InsufficientAllowanceError(
        f"Merchant must approve {required} wei ($0.01). "
        f"Run: node approve-facilitator.mjs"
    )

# Collect fee FIRST (pre-settlement)
fee_tx = usdc.transferFrom(
    from_=merchant,
    to=treasury,
    value=required
)

# Wait for confirmation
receipt = wait_for_transaction(fee_tx)
assert receipt.status == 1, "Fee collection failed"

# Fee collection successful - proceed to settlement
```

**Critical:** If fee collection fails at this step, settlement is blocked. Customer is NOT charged.

This guarantees the facilitator never provides free service.

### Step 7: Settlement Execution (After Fee)

After fee successfully collected, execute customer → merchant payment:

```python theme={null}
# Execute via 1Shot API (only if fee was collected)
settlement_response = oneshot_api.execute_settlement(
    authorization=authorization,
    signature=signature
)

# Customer → Merchant payment executed on-chain
# Merchant receives 100% of customer payment
```

***

## Trust Model

### What Merchants Trust

✅ **Customer payments arrive directly**

* EIP-3009 authorization cryptographically bound to merchant address
* Facilitator cannot redirect customer funds
* 100% of customer payment received

✅ **Fee collection is explicit and controllable**

* Standard ERC-20 approval (revocable anytime)
* Exact fee amount known upfront (\$0.01)
* On-chain auditable

✅ **Pre-settlement enforcement**

* Fee collected BEFORE settlement executes
* No fee = no settlement (guaranteed)
* Prevents free service exploitation

✅ **No custody risk**

* Facilitator never holds customer funds
* Settlement executes customer → merchant directly

### What Merchants Don't Need to Trust

❌ **Facilitator custody**

* Never happens (funds go direct to merchant)

❌ **Fee calculation**

* Flat \$0.01, no dynamic pricing or hidden fees

❌ **Arbitrary fund movement**

* Approval limits what facilitator can collect

❌ **Settlement execution without payment**

* Pre-settlement fee collection guarantees payment

***

## Security Considerations

### Approval Safety

**Merchant controls:**

1. **Approval amount** - Decide how many settlements to fund
2. **Revocation** - Can revoke approval anytime via:
   ```javascript theme={null}
   usdc.approve(treasury, 0) // Revoke all access
   ```
3. **Monitoring** - Check remaining allowance:
   ```bash theme={null}
   node check-allowance.mjs
   ```

**Attack scenarios:**

| Scenario                               | Protection                                           |
| -------------------------------------- | ---------------------------------------------------- |
| Facilitator drains entire USDC balance | ❌ Impossible - only approved amount accessible       |
| Facilitator collects more than \$0.01  | ❌ Blocked by smart contract (exact amount hardcoded) |
| Facilitator redirects customer funds   | ❌ Impossible - EIP-3009 signature bound to merchant  |
| Merchant has insufficient approval     | ✅ Settlement blocked, customer not charged           |
| Settlement fails after fee collection  | ⚠️ Merchant paid for attempt (prevents free service) |

### Settlement Atomicity

**Pre-settlement fee collection ensures:**

1. Fee collected FIRST
2. If fee fails → settlement blocked, customer not charged
3. If settlement fails → fee already collected (payment for service)

**Critical difference from post-settlement:**

* **Pre-settlement:** Fee collection failure = no settlement = customer safe
* **Post-settlement (rejected):** Settlement could succeed but fee fail = free service

**Trade-off:** Merchant pays fee even if settlement fails after fee collection.

**Economic justification:** Merchant received verification and settlement attempt services worth \$0.01. This prevents exploitation via intentional settlement failures.

***

## Comparison: Pre-Settlement vs Post-Settlement

| Aspect                      | Pre-Settlement (Current)    | Post-Settlement (Rejected)               |
| --------------------------- | --------------------------- | ---------------------------------------- |
| **Fee collection timing**   | BEFORE settlement ✅         | AFTER settlement                         |
| **Free service risk**       | Zero (fee first) ✅          | High (could fail fee collection)         |
| **Customer protection**     | High (no fee = no charge) ✅ | Lower (could be charged with failed fee) |
| **Merchant risk**           | Pays for attempt            | Lower fee risk                           |
| **Economic sustainability** | Guaranteed ✅                | Exploitable                              |
| **Trust minimization**      | Maintained ✅                | Maintained                               |

**Why pre-settlement wins:**

1. Prevents free service exploitation
2. Guarantees facilitator payment
3. Customer never charged if fee collection fails
4. Economically sustainable business model

***

## Comparison: Old vs Current Architecture

| Aspect                | Treasury-First (Old)  | Pre-Settlement (Current)          |
| --------------------- | --------------------- | --------------------------------- |
| **Customer payment**  | → Treasury → Merchant | → Merchant (direct) ✅             |
| **Fee collection**    | Atomic split          | Pre-settlement via transferFrom ✅ |
| **Trust required**    | High (custody)        | Minimal (approval only) ✅         |
| **x402 compliant**    | ❌ No                  | ✅ Yes                             |
| **Merchant setup**    | None                  | One-time approval                 |
| **Revocability**      | Not applicable        | Standard ERC-20 revoke ✅          |
| **Free service risk** | N/A                   | Eliminated ✅                      |

***

## Implementation Details

### On-Chain Transactions

**Setup (One-Time):**

```
Merchant → USDC.approve(treasury, 100 USDC)
Gas cost: ~50,000 gas (~$0.50 on Base)
```

**Per Settlement:**

```
1. Facilitator → USDC.transferFrom(merchant, treasury, $0.01)
   Gas: Paid by facilitator
   Timing: BEFORE settlement (pre-settlement)
   
2. Facilitator → 1Shot.executeSettlement(authorization, signature)
   Result: Client → Merchant ($0.02)
   Gas: Paid by 1Shot
   Timing: AFTER fee collection
```

**Total merchant gas cost: \$0** (after initial approval)

### Error Handling

**Insufficient Allowance:**

```json theme={null}
{
  "error": {
    "code": "insufficient_allowance",
    "message": "Merchant must approve facilitator for USDC spending",
    "details": {
      "required": "10000",
      "available": "0",
      "approval_command": "node approve-facilitator.mjs"
    }
  }
}
```

**Fee Collection Failed (Pre-Settlement):**

```json theme={null}
{
  "error": {
    "code": "fee_collection_failed",
    "message": "Could not collect $0.01 fee from merchant before settlement",
    "details": {
      "reason": "Insufficient USDC balance",
      "merchant_balance": "0",
      "note": "Settlement blocked - customer not charged"
    }
  }
}
```

***

## Alternatives Considered

### 1. Post-Settlement Fee Collection

Collect fee AFTER executing customer → merchant payment.

**Why rejected:**

* ❌ Merchants can exploit failed fee collection for free service
* ❌ Race condition between settlement and fee collection
* ❌ Customer could be charged even if fee collection fails
* ❌ Economically unsustainable (free service exploitation)

### 2. Smart Contract Atomic Split

```solidity theme={null}
contract AtomicSplit {
    function splitPayment(
        address merchant,
        address treasury,
        uint256 totalAmount
    ) external {
        usdc.transferFrom(msg.sender, merchant, totalAmount - fee);
        usdc.transferFrom(msg.sender, treasury, fee);
    }
}
```

**Why rejected:**

* ❌ Requires custom smart contract deployment
* ❌ Higher gas costs (contract interaction)
* ❌ Still requires customer to authorize contract (not direct to merchant)
* ❌ Violates trust-minimization (contract has custody)

### 3. Merchant Voluntary Fee Payment

Merchant manually pays fees after receiving customer payment.

**Why rejected:**

* ❌ Merchants can skip payment (free service)
* ❌ No enforcement mechanism
* ❌ Unsustainable business model

### 4. Treasury-First (Original)

See [comparison above](#comparison-old-vs-current-architecture).

**Why rejected:**

* ❌ Violates x402 trust-minimization
* ❌ Facilitator custody of customer funds
* ❌ Rejected by Coinbase x402 ecosystem

***

## Monitoring & Operations

### Check Allowance

Merchants can monitor remaining allowance:

```bash theme={null}
node check-allowance.mjs

Output:
📍 Base Mainnet
   USDC Balance: 500.00 USDC
   Fee Allowance: 95.50 USDC
   Settlements: 9,550
   ✅ Good
```

### Top Up Allowance

When allowance runs low:

```bash theme={null}
# Approve additional 100 USDC
node approve-facilitator.mjs
```

### Revoke Access

To stop allowing settlements:

```bash theme={null}
# Set allowance to 0
APPROVAL_AMOUNT=0 node approve-facilitator.mjs
```

**Effect:** All future settlements will fail with `insufficient_allowance` error at the pre-settlement fee collection step.

***

## Best Practices

<AccordionGroup>
  <Accordion title="Approve Reasonable Amounts">
    **Recommended:** 100-1000 USDC (10,000-100,000 settlements)

    **Avoid:** Infinite approval (max uint256)

    **Why:** Limits exposure if facilitator compromised. With pre-settlement, you only risk the approved amount.
  </Accordion>

  <Accordion title="Monitor Allowance">
    Set up alerts when allowance drops below threshold:

    ```javascript theme={null}
    const allowance = await checkAllowance();
    if (allowance.settlements < 100) {
      alert("Low allowance - top up soon");
    }
    ```
  </Accordion>

  <Accordion title="Test on Sepolia First">
    Always test approval and settlements on Base Sepolia before mainnet:

    ```bash theme={null}
    NETWORK=sepolia node approve-facilitator.mjs
    ```
  </Accordion>

  <Accordion title="Maintain USDC Balance">
    Ensure merchant address has USDC for fee payment:

    * Minimum: 1 USDC (100 settlements)
    * Recommended: Match approval amount

    Pre-settlement means fee is collected BEFORE settlement, so you need sufficient balance.
  </Accordion>
</AccordionGroup>

***

## FAQ

<AccordionGroup>
  <Accordion title="Why collect fee BEFORE settlement instead of after?">
    **Economic security:** Pre-settlement prevents free service exploitation.

    **Without pre-settlement:** Merchants could:

    1. Receive customer payment
    2. Intentionally cause fee collection to fail
    3. Get free verification/settlement service

    **With pre-settlement:** Fee collected first = no free rides.

    **Trade-off:** Merchant pays \$0.01 even if settlement fails after fee. This is payment for the service attempt.
  </Accordion>

  <Accordion title="What if settlement fails after fee collection?">
    **You paid \$0.01 for the settlement attempt.**

    **Why this is fair:**

    * Facilitator provided verification service
    * Facilitator attempted settlement
    * Resources were consumed
    * Service was rendered

    **Prevents exploitation:** Without charging for attempts, merchants could intentionally fail settlements for free verification.

    **Mitigation:** Test thoroughly on Sepolia testnet before production.
  </Accordion>

  <Accordion title="Can facilitator drain my USDC balance?">
    **No.** Only the approved amount is accessible. Pre-settlement doesn't change this.

    * Approve 100 USDC → max risk is 100 USDC
    * Your remaining USDC: Safe
  </Accordion>

  <Accordion title="What happens if I have insufficient USDC for the fee?">
    **Settlement is blocked at pre-settlement fee collection step.**

    Flow:

    1. Customer submits payment authorization
    2. Facilitator attempts fee collection
    3. Fee collection fails (insufficient balance)
    4. Settlement NEVER executes
    5. Customer NOT charged

    Error: `fee_collection_failed - Settlement blocked`
  </Accordion>

  <Accordion title="How is pre-settlement different from post-settlement?">
    **Timing and guarantees:**

    **Pre-settlement (current):**

    ```
    1. Collect $0.01 from merchant
    2. IF successful → Execute customer → merchant
    3. IF failed → Block settlement, customer safe
    ```

    **Post-settlement (rejected):**

    ```
    1. Execute customer → merchant
    2. TRY to collect $0.01 from merchant
    3. IF failed → Merchant got free service
    ```

    Pre-settlement eliminates free service risk.
  </Accordion>
</AccordionGroup>

***

## Next Steps

<CardGroup cols={2}>
  <Card title="Approve Facilitator" icon="check" href="/guides/getting-started#step-1-approve-facilitator">
    Set up one-time USDC approval
  </Card>

  <Card title="Server Integration" icon="code" href="/integration/nodejs">
    Add x402 middleware to your app
  </Card>

  <Card title="Test Settlement" icon="flask" href="/guides/getting-started#step-3-test-payment">
    Complete end-to-end payment flow
  </Card>

  <Card title="Monitor Allowance" icon="chart-line" href="#monitoring--operations">
    Track remaining settlements
  </Card>
</CardGroup>

<Check>
  **Trust-Minimized with Pre-Settlement:** Customer funds go DIRECTLY to merchants. Facilitator collects \$0.01 fee BEFORE settlement. If fee collection fails, settlement is blocked and customer is never charged. No free rides, fully auditable.
</Check>
