Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@
"group": "Merchant",
"pages": [
"sdk/merchant/getting-started",
"sdk/helpers/refundable",
"sdk/helpers/forward-to-arbiter",
"sdk/merchant/quickstart",
"sdk/merchant/refund-handling"
]
Expand Down
4 changes: 2 additions & 2 deletions sdk/deploy-operator.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -225,8 +225,8 @@ Deployment requires gas fees. Ensure your wallet has ETH on the target network.
<Card title="Examples" icon="code" href="/sdk/examples">
See working merchant and client examples.
</Card>
<Card title="Helpers" icon="wrench" href="/sdk/helpers/refundable">
Mark payment options as refundable with your operator.
<Card title="forwardToArbiter()" icon="wrench" href="/sdk/helpers/forward-to-arbiter">
Forward escrow settlements to an arbiter service.
</Card>
<Card title="Smart Contracts" icon="file-contract" href="/contracts/overview">
Understand the underlying contract architecture.
Expand Down
12 changes: 6 additions & 6 deletions sdk/examples.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ The SDK includes working examples in the `x402r-sdk/` repository. Each is a stan
Deploy a complete marketplace operator with escrow, freeze, and arbiter support.
</Card>
<Card title="server-express" icon="server" href="https://github.com/BackTrackCo/x402r-sdk/tree/main/examples/servers/express">
Express merchant server using `EscrowServerScheme`, `HTTPFacilitatorClient`, and `refundable()` to accept escrow payments via x402 middleware.
Express merchant server using `EscrowServerScheme` and `HTTPFacilitatorClient` to accept escrow payments via x402 middleware.
</Card>
<Card title="server-hono" icon="server" href="https://github.com/BackTrackCo/x402r-sdk/tree/main/examples/servers/hono">
Hono merchant server using `EscrowServerScheme`, `HTTPFacilitatorClient`, and `refundable()` to accept escrow payments via x402 middleware.
Hono merchant server using `EscrowServerScheme` and `HTTPFacilitatorClient` to accept escrow payments via x402 middleware.
</Card>
<Card title="merchant-cli" icon="terminal" href="https://github.com/BackTrackCo/x402r-sdk/tree/main/examples/dev-tools/merchant-cli">
CLI tool for merchants to release payments, approve/deny refunds, and query escrow state.
Expand Down Expand Up @@ -92,9 +92,9 @@ See [Deploy an Operator](/sdk/deploy-operator) for the full guide.

## Server Examples

Demonstrates minimal merchant servers (Express and Hono variants) that use `EscrowServerScheme`, `HTTPFacilitatorClient`, and `refundable()` via x402's standard middleware:
Demonstrates minimal merchant servers (Express and Hono variants) that use `EscrowServerScheme` and `HTTPFacilitatorClient` via x402's standard middleware:

1. Returns 402 with `refundable()` payment options
1. Returns 402 with inline escrow payment options
2. Delegates payment verification to the facilitator via `HTTPFacilitatorClient`
3. Delegates on-chain settlement to the facilitator after the handler runs
4. Returns weather data after successful payment
Expand All @@ -105,8 +105,8 @@ Demonstrates minimal merchant servers (Express and Hono variants) that use `Escr
<Card title="Deploy Operator" icon="rocket" href="/sdk/deploy-operator">
Deploy a PaymentOperator with escrow and freeze support.
</Card>
<Card title="refundable() Helper" icon="wrench" href="/sdk/helpers/refundable">
Mark payment options as refundable with escrow configuration.
<Card title="forwardToArbiter()" icon="wrench" href="/sdk/helpers/forward-to-arbiter">
Forward escrow settlements to an arbiter service.
</Card>
<Card title="Core Concepts" icon="lightbulb" href="/sdk/concepts">
Understand the payment lifecycle and key concepts.
Expand Down
161 changes: 161 additions & 0 deletions sdk/helpers/forward-to-arbiter.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
---
title: "forwardToArbiter()"
description: "Forward escrow settlement responses to an arbiter service for dispute evaluation"
icon: "wrench"
---

The `@x402r/helpers` package provides `forwardToArbiter()` — an `onAfterSettle` hook that forwards the response body to an arbiter service after successful escrow settlements. It is fire-and-forget and does not block the client response.

<Note>
This function lives in `@x402r/helpers`. Install it separately:
```bash
npm install @x402r/helpers
```

Peer dependency: `@x402/core >=2.5.0`
</Note>

## Usage

```typescript
import { forwardToArbiter } from '@x402r/helpers';

const resourceServer = new x402ResourceServer(facilitatorClient)
.register(networkId, new EscrowServerScheme())
.onAfterSettle(
forwardToArbiter('http://arbiter:3001')
);
```

After a successful escrow settlement, the hook POSTs `{ responseBody, network, transaction, scheme }` to `{arbiterUrl}/verify`. Non-escrow schemes, failed settlements, and missing response bodies are silently skipped.

## Function signature

```typescript
function forwardToArbiter(
arbiterUrl: string,
options?: ForwardToArbiterOptions
): (context: SettleResultContext) => Promise<void>
```

### Parameters

| Parameter | Type | Description |
|-----------|------|-------------|
| `arbiterUrl` | `string` | Base URL of your arbiter service (e.g., `http://arbiter:3001`) |
| `options` | `ForwardToArbiterOptions` | Optional configuration (see below) |

### Options

```typescript
interface ForwardToArbiterOptions {
/** Custom error handler. Defaults to `console.warn`. */
onError?: (error: unknown) => void;
}
```

| Option | Default | Description |
|--------|---------|-------------|
| `onError` | `console.warn` | Called when the POST to the arbiter fails. Use this to integrate with your error tracking (e.g., Sentry). |

### Return value

Returns an async callback compatible with `onAfterSettle`. The callback:

1. Skips if the settlement failed (`context.result.success === false`)
2. Skips if the scheme is not `escrow`
3. Skips if there is no response body in the transport context
4. POSTs to `{arbiterUrl}/verify` with the settlement data
5. Catches errors via the `onError` handler (default: `console.warn`)

## Examples

### Basic usage

```typescript
import { forwardToArbiter } from '@x402r/helpers';

const resourceServer = new x402ResourceServer(facilitatorClient)
.register(networkId, new EscrowServerScheme())
.onAfterSettle(
forwardToArbiter('http://arbiter:3001')
);
```

### Custom error handling

```typescript
import { forwardToArbiter } from '@x402r/helpers';

const resourceServer = new x402ResourceServer(facilitatorClient)
.register(networkId, new EscrowServerScheme())
.onAfterSettle(
forwardToArbiter('http://arbiter:3001', {
onError: (err) => sentry.captureException(err),
})
);
```

<Tip>
You should always provide an `onError` handler in production. The x402 `onAfterSettle` runner does not catch errors internally — without a handler, an unreachable arbiter could break your post-settlement flow.
</Tip>

### POST payload

The hook sends a JSON POST to `{arbiterUrl}/verify` with this shape:

```json
{
"responseBody": "<utf-8 string of the HTTP response body>",
"network": "eip155:84532",
"transaction": "0xabc...",
"scheme": "escrow"
}
```

## Behavior details

- **Escrow-only** — Only fires for `scheme: "escrow"` settlements. Non-escrow schemes (e.g., `exact`) are silently skipped.
- **Fire-and-forget** — The POST happens asynchronously and does not block the HTTP response to the client.
- **Trailing slash safe** — `forwardToArbiter('http://arbiter:3001/')` resolves to `http://arbiter:3001/verify`.

## Migration from refundable()

The `refundable()` helper has been removed. If you were using it to wrap payment options with escrow configuration, you should now inline the escrow `extra` config directly:

```typescript
// Before (removed)
import { refundable } from '@x402r/helpers';
const option = refundable(
{ scheme: 'escrow', price: '$0.01', network: 'eip155:84532', payTo: address },
operatorAddress
);

// After — inline the extra config
const option = {
scheme: 'escrow',
network: 'eip155:84532',
price: '$0.01',
payTo: address,
extra: {
escrowAddress: authCaptureEscrow, // from getChainConfig()
operatorAddress,
feeReceiver: operatorAddress,
maxFeeBps: 500,
},
};
```

## Next steps

<CardGroup cols={2}>
<Card title="Arbiter quickstart" icon="gavel" href="/sdk/arbiter/quickstart">
Build an arbiter service that receives forwarded settlements.
</Card>
<Card title="Deploy operator" icon="rocket" href="/sdk/deploy-operator">
Deploy a PaymentOperator for escrow payments.
</Card>
<Card title="Examples" icon="code" href="/sdk/examples">
See merchant and arbiter examples.
</Card>
</CardGroup>
167 changes: 0 additions & 167 deletions sdk/helpers/refundable.mdx

This file was deleted.

2 changes: 1 addition & 1 deletion sdk/limitations.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ const details = await client.getPaymentDetails(hash, recentBlockNumber);

### No Express/Hono Middleware

The `refundable()` helper in `@x402r/helpers` is framework-agnostic. There is no dedicated Express or Hono middleware — use `refundable()` directly when constructing payment options.
The `forwardToArbiter()` hook in `@x402r/helpers` is framework-agnostic. There is no dedicated Express or Hono middleware — configure escrow payment options inline and use `forwardToArbiter()` as an `onAfterSettle` hook.

## Getting Updates

Expand Down
Loading
Loading