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

# Plugins

> Build custom wallet adapters, payment schemes, and middleware integrations for faremeter.

Faremeter's plugin architecture allows community developers to create custom wallet adapters, payment schemes, and middleware integrations. Every layer of the stack is replaceable.

## What can be extended

| Plugin type             | Interface                     | Use case                                                  |
| ----------------------- | ----------------------------- | --------------------------------------------------------- |
| **Wallet adapter**      | `createLocalWallet()` pattern | Support a new wallet type (hardware, custodial, multisig) |
| **Payment handler**     | `PaymentHandler`              | Support a new blockchain or payment scheme on the client  |
| **Facilitator handler** | `FacilitatorHandler`          | Support a new blockchain or scheme on the facilitator     |
| **Middleware adapter**  | `handleMiddlewareRequest()`   | Integrate with a framework beyond Express and Hono        |

## Building a custom wallet adapter

A wallet adapter is a factory function that returns an object capable of signing payment proofs. The exact shape depends on the chain, but the pattern is the same: accept credentials, return a signer.

```typescript theme={null}
import type { Keypair } from "some-chain-sdk"

interface MyWallet {
  address: string
  network: string
  sign(data: Uint8Array): Promise<Uint8Array>
}

export async function createMyWallet(
  network: string,
  keypair: Keypair,
): Promise<MyWallet> {
  return {
    address: keypair.publicKey.toString(),
    network,
    sign: async (data) => {
      return keypair.sign(data)
    },
  }
}
```

The wallet is then passed to a payment handler. See [Wallets & Signing](/concepts/wallets-and-signing) for the full adapter pattern.

## Building a custom payment handler

A payment handler bridges a wallet and a payment scheme. It receives payment requirements from a 402 response and returns `PaymentExecer` objects for any requirements it can fulfill.

```typescript theme={null}
import type { PaymentHandler, PaymentExecer } from "@faremeter/types/client"

export function createMyPaymentHandler(wallet: MyWallet): PaymentHandler {
  return async (context, accepts) => {
    const execers: PaymentExecer[] = []

    for (const req of accepts) {
      // Only handle requirements this wallet can fulfill
      if (req.scheme !== "my-scheme" || req.network !== wallet.network) {
        continue
      }

      execers.push({
        requirements: req,
        exec: async () => {
          // Build and sign the payment proof
          const proof = buildProof(req, wallet)
          const signature = await wallet.sign(proof)

          return {
            payload: {
              signature: Buffer.from(signature).toString("base64"),
              address: wallet.address,
            },
          }
        },
      })
    }

    return execers
  }
}
```

Register the handler with the fetch wrapper:

```typescript theme={null}
import { wrap } from "@faremeter/fetch"

const wallet = await createMyWallet("my-network", keypair)
const handler = createMyPaymentHandler(wallet)

const fetchWithPayment = wrap(fetch, {
  handlers: [handler],
})
```

See [Payment Handlers](/concepts/payment-handlers) for the full interface and composition model.

## Building a custom facilitator handler

To support a new chain on the facilitator side, implement the `FacilitatorHandler` interface:

```typescript theme={null}
import type { FacilitatorHandler } from "@faremeter/types/facilitator"

export async function createMyFacilitatorHandler(
  network: string,
  rpcUrl: string,
  signerKey: string,
): Promise<FacilitatorHandler> {
  const client = createChainClient(rpcUrl, signerKey)

  return {
    getSupported: () => [
      Promise.resolve({
        x402Version: 2,
        scheme: "my-scheme",
        network,
      }),
    ],

    getRequirements: async ({ accepts }) => {
      // Enrich requirements with chain-specific fields
      return accepts
        .filter((r) => r.scheme === "my-scheme" && r.network === network)
        .map((r) => ({
          ...r,
          // Add facilitator-specific enrichment here
          extra: { signerAddress: client.address },
        }))
    },

    handleSettle: async (requirements, payment) => {
      if (requirements.scheme !== "my-scheme") return null

      // Verify and submit the transaction on-chain
      const txHash = await client.submitTransaction(payment.payload)

      return {
        success: true,
        transaction: txHash,
        network,
      }
    },
  }
}
```

Wire it into a facilitator:

```typescript theme={null}
import { createFacilitatorRoutes } from "@faremeter/facilitator"
import { Hono } from "hono"

const handler = await createMyFacilitatorHandler("my-network", rpcUrl, signerKey)

const app = new Hono()
app.route("/", createFacilitatorRoutes({ handlers: [handler] }))
```

Handlers return `null` from `handleSettle` and `handleVerify` for schemes they don't support, allowing multiple handlers to coexist. See [Facilitator](/server/facilitator) for the full setup.

## Building a custom middleware adapter

If you use a framework other than Express or Hono, use `handleMiddlewareRequest` from `@faremeter/middleware/common` to wire up the payment flow manually. You provide functions to read headers, send responses, and handle the request body.

```typescript theme={null}
import {
  handleMiddlewareRequest,
  createPaymentRequiredResponseCache,
  resolveSupportedVersions,
} from "@faremeter/middleware/common"

const { getPaymentRequiredResponse } = createPaymentRequiredResponseCache({})

// Example: Fastify integration
fastify.addHook("preHandler", async (request, reply) => {
  return await handleMiddlewareRequest({
    facilitatorURL: "https://facilitator.corbits.dev",
    accepts,
    supportedVersions: resolveSupportedVersions(),
    resource: request.url,
    getHeader: (key) => request.headers[key] as string | undefined,
    getPaymentRequiredResponse,
    sendJSONResponse: (status, body, headers) => {
      if (headers) {
        for (const [key, value] of Object.entries(headers)) {
          reply.header(key, value)
        }
      }
      reply.status(status).send(body)
    },
    body: async ({ settle }) => {
      const result = await settle()
      if (!result.success) return result.errorResponse
      // Request continues to the route handler
    },
  })
})
```

See [Middleware Overview](/server/middleware-overview#handlemiddlewarerequest--the-lower-level-api) for the full API reference.

## Publishing plugins

When publishing a faremeter plugin:

1. Use the naming convention `faremeter-*` or `@your-scope/faremeter-*` for discoverability.
2. Declare `@faremeter/types` as a peer dependency for type compatibility.
3. Export your factory functions as the package's public API.
4. Include a README with a working example.

## Plugin registry

Visit the [faremeter plugin registry](https://github.com/faremeter) to browse community-contributed packages.

## Further reading

* [Payment Handlers](/concepts/payment-handlers) -- The client-side plugin interface.
* [Wallets & Signing](/concepts/wallets-and-signing) -- The wallet adapter pattern.
* [Facilitator](/server/facilitator) -- Running and extending your own facilitator.
* [Middleware Overview](/server/middleware-overview) -- Server-side middleware and the `common` module.
