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

# x402 Earnings (Merchant)

> Per-merchant rollup of x402 settlement events. Reads X402SettlementLog scoped to the authenticated merchant. Returns empty rows until X402_ENABLED is flipped on the platform. Fail-open semantics.

`GET /v2/merchant/x402-earnings` returns the authenticated merchant's rollup of
x402 settlement events: per-row settlement detail, totals envelope (settlement
amount + count), and pagination. This endpoint is the data source for the
merchant **x402 Earnings** page in the dashboard.

<Note>
  This endpoint requires:

  * **Merchant JWT** — any authenticated merchant role (`OWNER`, `MEMBER`, `PRODUCER`)

  The merchant scope is **derived from the JWT `sub` claim**. There is no
  `merchantId` query parameter. If a client passes one anyway it is silently
  ignored — the response is always scoped to the JWT-bound merchant.
</Note>

## GET /v2/merchant/x402-earnings

### Authentication

| Guard | Requirement                                                     |
| ----- | --------------------------------------------------------------- |
| JWT   | Required, any authenticated merchant role                       |
| Scope | `merchantId` derived from JWT `sub` — **not** from query / body |

Obtain a merchant JWT via `POST /merchant/admin/login` — see
[Authentication](/authentication).

### Query parameters

| Param       | Type            | Required | Default | Description                                                                   |
| ----------- | --------------- | -------- | ------- | ----------------------------------------------------------------------------- |
| `page`      | integer         | No       | `1`     | 1-indexed page number.                                                        |
| `limit`     | integer         | No       | `20`    | Rows per page.                                                                |
| `startDate` | ISO-8601 string | No       | —       | Filter to settlements with `settledAt >= startDate`. Omit for no lower bound. |
| `endDate`   | ISO-8601 string | No       | —       | Filter to settlements with `settledAt <= endDate`. Omit for no upper bound.   |

### Example

```bash theme={null}
curl "https://apiv3.droplinked.com/v2/merchant/x402-earnings?page=1&limit=20" \
  -H "Authorization: Bearer <MERCHANT_JWT>"
```

With a date filter:

```bash theme={null}
curl "https://apiv3.droplinked.com/v2/merchant/x402-earnings?page=1&limit=20&startDate=2026-01-01T00:00:00Z&endDate=2026-06-14T23:59:59Z" \
  -H "Authorization: Bearer <MERCHANT_JWT>"
```

### Response — 200 OK

```json theme={null}
{
  "rows": [],
  "totalSettlementsUsdCents": 0,
  "totalCount": 0,
  "asOf": "2026-06-14T23:41:10.180Z",
  "pagination": {
    "page": 1,
    "limit": 20,
    "total": 0
  }
}
```

### Fields

| Field                      | Type            | Nullable | Description                                                                                                                                                            |
| -------------------------- | --------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `rows`                     | array           | No       | One entry per x402 settlement event matching the filter. Empty array until `X402_ENABLED` is flipped on, or when the merchant has no settlements in the filter window. |
| `rows[].settlementId`      | string          | No       | `X402SettlementLog` row `_id`.                                                                                                                                         |
| `rows[].settledAt`         | ISO-8601 string | No       | Settlement timestamp (UTC) — when the x402 settlement event was captured on chain and recorded.                                                                        |
| `rows[].amountUsdCents`    | integer         | No       | Settlement amount in **USD cents**, integer. x402 settles natively in USDC on Base; the read path snapshots the FX at settlement time.                                 |
| `rows[].productId`         | string          | Yes      | Source product `_id` if the settlement is tied to a specific product. `null` for storefront-wide payouts.                                                              |
| `rows[].orderId`           | string          | Yes      | Source order `_id` if available. `null` for legacy rows.                                                                                                               |
| `rows[].txHash`            | string          | Yes      | Base transaction hash. `null` for legacy rows pre-dating chain-hash capture.                                                                                           |
| `totalSettlementsUsdCents` | integer         | No       | Sum of `amountUsdCents` for **the merchant across the filter window** (not just the current page).                                                                     |
| `totalCount`               | integer         | No       | Total settlement count for the merchant across the filter window.                                                                                                      |
| `asOf`                     | ISO-8601 string | No       | Snapshot timestamp (server clock, UTC).                                                                                                                                |
| `pagination`               | object          | No       | Pagination envelope.                                                                                                                                                   |
| `pagination.page`          | integer         | No       | Echoed `page` query param (1-indexed).                                                                                                                                 |
| `pagination.limit`         | integer         | No       | Echoed `limit` query param.                                                                                                                                            |
| `pagination.total`         | integer         | No       | Total number of settlement rows matching the filter (across pages). Equal to `totalCount`.                                                                             |

### Errors

| Status | Body                                                                               | When                                                              |
| ------ | ---------------------------------------------------------------------------------- | ----------------------------------------------------------------- |
| `401`  | `{ "statusCode": 401, "status": "failed", "data": { "message": "Unauthorized" } }` | Missing or invalid JWT                                            |
| `5xx`  | `{ "statusCode": 500, "status": "failed", ... }`                                   | Hard backend failure — see Notes below for the fail-open contract |

### Notes

* **`X402_ENABLED` gating.** Until the platform flag `X402_ENABLED` is set to
  `true`, `X402SettlementLog` accepts no writes and this endpoint always
  returns `rows: []`, `totalSettlementsUsdCents: 0`, `totalCount: 0`. The
  endpoint itself is always reachable — the gate is at the write path, not
  the read path. Merchants safely linkable to the page before the flip; it
  renders an empty-state.
* **Auth scope.** The endpoint reads `merchantId` from the JWT `sub` claim
  only. Any `?merchantId=` is silently ignored. A merchant cannot read
  another merchant's settlements through this endpoint — even with a
  syntactically valid query parameter pointing at the target.
* **Fail-open semantics.** If the underlying `X402SettlementLog` aggregation
  throws, the endpoint returns the empty-state envelope (`rows: []`,
  totals `0`) with `200 OK` rather than propagating the error. Inspect server
  logs / Sentry for the underlying failure.
* **Currency.** All monetary fields are **USD cents, integer** — same contract
  as the [admin x402-earnings rollup](/api-reference/admin/monetization/x402-earnings).
  Divide by `100` for major-unit display.
* **Pagination.** `total` and `totalCount` count **settlement rows**, not
  products / orders. A merchant with 50 settlements across 3 products
  reports `total: 50`, `totalCount: 50`.
* **Date filter semantics.** `startDate` and `endDate` are inclusive bounds on
  `settledAt`. Omit either to leave that side of the window unbounded; omit
  both for the full per-merchant history (capped at the merchant's earliest
  settlement).

## Related

* [Billing Invoices (Merchant)](/api-reference/public/monetization/billing-invoices) — companion merchant-facing billing history (trailing 365 days, paid subscription invoices).
* [x402 Earnings (Admin)](/api-reference/admin/monetization/x402-earnings) — admin-side per-merchant x402 settlement rollup (network-wide view).
* [Platform Fee Summary (Admin)](/api-reference/admin/monetization/platform-fee-summary) — network-wide MRR / ARR / 30d / 365d rollup that includes x402 in `revenue30dUsdCents` / `revenue365dUsdCents`.
