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

# Resource Server Guide

> Monetize an API endpoint with x402 — challenge, verify, and settle payments from paying agents.

This is the "you're getting paid" side of x402: your API responds `402` to unpaid requests, then verifies and settles a payment once the caller attaches one.

## Define what you accept

```ts theme={null}
import type { PaymentRequirement } from "@xentfi/x402-facilitator";

const requirement: PaymentRequirement = {
  scheme: "eip3009",
  network: "base-mainnet",
  blockchainId: "2fad7eb1-4405-4400-af4f-2b37401a6bd6",
  assetId: "b3d641bb-f28f-4d1f-b89c-a504ad51f453",
  maxAmountRequired: "1.00",
  payTo: "0xYourWalletAddress",
  resource: "GET /premium-report",
  maxTimeoutSeconds: 3600,
};
```

Use `facilitator.getSupported()` (see [Quickstart](/x402/quickstart)) to find valid `blockchainId`/`assetId` values for the network and token you want to accept.

## Challenge, verify, settle

```ts theme={null}
import Fastify from "fastify";
import { X402FacilitatorClient } from "@xentfi/x402-facilitator";
import type { PaymentPayload, PaymentRequirement } from "@xentfi/x402-facilitator";

const facilitator = new X402FacilitatorClient({
  apiKey: process.env.WAAS_API_KEY!,
  orgId: process.env.WAAS_ORG_ID!,
});

const app = Fastify();

app.get("/premium-report", async (req, reply) => {
  const proofHeader = req.headers["x-payment"];

  if (!proofHeader) {
    // No payment attached yet — issue the 402 challenge.
    return reply.status(402).send({
      x402Version: 1,
      accepts: [requirement],
    });
  }

  const paymentPayload: PaymentPayload = JSON.parse(
    Buffer.from(proofHeader as string, "base64").toString("utf8"),
  );

  try {
    // Throws on invalid signature, expired authorization, wrong amount, etc.
    await facilitator.verify(paymentPayload, requirement);

    // Submits the TransferWithAuthorization on-chain via your WAAS relayer wallet.
    const settlement = await facilitator.settle(paymentPayload, requirement);

    return {
      report: "... the actual paid content ...",
      txHash: settlement.txHash,
    };
  } catch (error) {
    return reply.status(402).send({
      x402Version: 1,
      accepts: [requirement],
      error: (error as Error).message,
    });
  }
});

app.listen({ port: 3000 });
```

<Steps>
  <Step title="No X-PAYMENT header">
    Respond `402` with `{ x402Version: 1, accepts: [requirement] }`. This is the machine-readable challenge the payer's agent parses to know what, where, and how much to pay.
  </Step>

  <Step title="X-PAYMENT header present">
    Base64-decode it into a `PaymentPayload` and call `facilitator.verify(payload, requirement)`. This checks the EIP-712 signature, amount, recipient, and validity window against your requirement — no funds move yet.
  </Step>

  <Step title="Verified — settle it">
    Call `facilitator.settle(payload, requirement)`. Your organization's WAAS wallet relays the `TransferWithAuthorization` on-chain and pays the gas; funds land at `payTo`.
  </Step>

  <Step title="Serve the content">
    Once `settle()` resolves, return the actual paid resource along with the `txHash` for the caller's records.
  </Step>
</Steps>

<Warning>
  Both `verify()` and `settle()` **throw** on failure rather than returning a `{ isValid: false }`-shaped result — catch the error and fold its message into your own `402` response's `error` field, as shown above. See [Error Handling](/x402/errors) for the exact error classes and HTTP status mapping.
</Warning>

## Next steps

<CardGroup cols={2}>
  <Card title="Payer Guide" icon="bot" href="/x402/payer">
    See the other side of this flow.
  </Card>

  <Card title="API Reference" icon="code" href="/x402/api-reference">
    Full `verify`/`settle`/`getSupported` signatures and types.
  </Card>
</CardGroup>
