# CSV Quality Report: one-shot x402 client

A small client for `https://172-93-215-200.sslip.io/api/x402/csv-quality`.
A successful new payment costs **0.10 native USDC on Base** (100000 atomic units).
The service returns a Markdown structural-quality report inside `{"output":"..."}`.
It does not clean the CSV or establish its factual correctness.

This release was tested **offline on Linux with Node 26.11.1**. Runtime requires
Linux and Node 22 or later. Its local record custody uses Linux/POSIX open flags,
0600 permissions and file/directory fsync; other operating systems are not qualified.
There is no completed live paid-client or chain-settlement test claimed here.

## Install

Unzip `csv-quality-client-1.0.1.zip`, then:

```sh
cd csv-quality-client-1.0.1
npm ci --ignore-scripts --no-audit --no-fund
node client.mjs
```

Dependencies are pinned: `@x402/core` 2.28.0, `@x402/evm` 2.28.0 and
`viem` 2.57.11. `package-lock.json` pins the transitive graph and registry integrity.
Installation downloads packages; lifecycle scripts are disabled by the command.
No arguments prints usage: **no request, wallet loading, signature or payment**.

## Request the unpaid quote

```sh
node client.mjs --quote --csv fixtures/example.csv
```

This deliberately makes one unsigned POST. A valid 402 challenge is checked against
the fixed canonical URL, Base, native USDC, recipient and exact 0.10 amount.
No key is loaded and no signature is created. The synthetic fixture has one missing
quantity and one duplicate record. Supply only data you may send to this service.

## Make one deliberate purchase

Only the customer should run this on a trusted local machine with a customer-owned
wallet. Configure `CSV_BUYER_PRIVATE_KEY` locally through your normal secret manager
or a non-echoing shell prompt. Its value is a `0x`-prefixed 32-byte EVM key. Do not
put it in command arguments, source files, shared screenshots or messages to us.
A dedicated low-balance customer wallet limits exposure to locally installed code.

After reviewing the source and quote:

```sh
node client.mjs --pay --csv fixtures/example.csv --attempt customer-local.attempt.json
```

`--pay` permits one unsigned discovery POST and **at most one signed POST**. Only
0.10 USDC is authorized. Wallet/network/provider costs are not quoted by this client.
The SDK signs locally; no private key is sent to the service. The client does not call RPC or send an approval or direct wallet transaction.
Its signed authorization permits the facilitator to transfer the authorized USDC.
The merchant receives the CSV and signed authorization. Its facilitator receives
payment information, rather than the CSV; see the service's data-handling statement.

The merchant requires a five-field v2 payload, unchanged accepted requirement and
Bazaar extensions. Its EIP-3009 window requires `validAfter < server now < validBefore
<= server now + 60s`. The pinned SDK creates `validAfter="0"` and a 60-second expiry.
The client rejects an expired payload before sending it. Correct local UTC time
matters. A changed quote stops before the signer is loaded.

The attempt filename **must not already exist**. Before sending a paid request, the
client saves the exact input JSON and signed PAYMENT-SIGNATURE into that local file
with exclusive creation, mode 0600 and fsync. This file contains your CSV and a
financial authorization: keep it private, retain it for recovery/review, and never
upload it to a repository, support chat or public site. It contains no private key.
Use a local filesystem where those custody guarantees apply.

A successful response prints the report and normalized settlement acknowledgement.
That acknowledgement does not prove chain finality. If the command times out,
returns an unqualified receipt, or reports an unknown outcome, **stop**. Keep the
attempt file and consult the merchant operator. Do not choose a new filename or
create another authorization to pay again while the first result is unresolved.
The client makes no automatic payment retry, recovery request, redirect or pagination.
A prepared record alone is not proof the paid POST was sent, settled or delivered.

## Limits

The client accepts one regular, non-symlink UTF-8 CSV file up to 65536 bytes and sends
one immutable JSON body for both steps. The service also limits records to 1000
including the header, columns to 64 and report output to 16384 UTF-8 bytes. Response bodies are capped at 65536 bytes; encoded JSON requests at 393280 bytes;
payment headers at 24576 characters. A 25s cancellation deadline covers the
discovery/sign/payment exchange inside run(); local CSV/attempt-file preflight
in main() occurs before that timer. Responses other than 200/402 have no body parsed. Unknown paid
outcomes remain unknown and require review.

## Validation status

Eight internal offline test groups passed using the actual pinned SDK, a synthetic
signer and the existing merchant validation with fake journal/facilitator objects.
They cover exact payload and receipt fields, 64/65-byte signature shapes, quote
changes before signer loading, expiry, deadlines, unknown outcomes and no automatic
retry. No actual wallet/key, merchant request, facilitator, RPC or settlement was
used. These validate compatibility of payload shape and control flow, not a real
cryptographic signature or completed production payment. Internal tests and the
server/report implementation are deliberately not included in this client archive.
There is no public npm test command.

Primary SDK guide: https://docs.x402.org/getting-started/quickstart-for-buyers
Package metadata: https://registry.npmjs.org/@x402/core/2.28.0 and
https://registry.npmjs.org/@x402/evm/2.28.0 . This client uses the SDK payload API
instead of its automatic paid-fetch wrapper to keep the single paid dispatch explicit.
