# Fast Sign and sign-sdk

Fast Sign artifact attestations and the @fastxyz/sign-sdk Node client

[Fast Sign](https://sign.fast.xyz) records an attestation of a file's SHA-256 digest by a Fast address. The public Node package [`@fastxyz/sign-sdk`](https://github.com/fastxyz/fast-sdk/blob/main/packages/sign-sdk/README.md) supports canonical artifact attestations by agents that already have explicit signing authority. It is not a generic `ExternalClaim` builder, a custodial signer, a CLI, or an API for driving the Fast Sign website. Importing the package does not authorize a signature or fee.

## Install and hash the exact bytes

The package requires Node.js 20.19 or newer:

```bash
npm install @fastxyz/sign-sdk
```

```ts
import { hashFile } from '@fastxyz/sign-sdk';

const sha256 = await hashFile('/path/to/original.pdf');
```

`hashFile()` computes SHA-256 locally without uploading file bytes. It rejects symlinks, non-regular files, and a file that changes during hashing. You may instead supply an already computed digest of exactly 64 lowercase hex characters without `0x`. The digest commits to **the bytes supplied**, not to the truth, authorship, or legal effect of the contents.

## Authorize and submit

`createSignClient()` requires a chosen `fast:mainnet` or `fast:testnet` network, matching `proxyUrl` and `indexOrigin`, a caller-authorized signer and Fast provider, a durable recovery journal, and an explicit `feePolicy`. `signDigest({ operationId, sha256, relationship })` then submits a canonical artifact attestation. Relationships include `authored`, `approved`, `reviewed`, `witnessed`, and other values in the [published type](https://github.com/fastxyz/fast-sdk/blob/main/packages/sign-sdk/src/types.ts); the label is a claim by the signer, not third-party validation. Keep the same operation-specific ID and journal throughout recovery.

| State | Meaning | Safe next step |
| --- | --- | --- |
| `settlement: "settled"` | The SDK has a settlement receipt; registration has a separate state. | Save the receipt durably, then check settlement and index registration. |
| `settlement: "unknown"` | The submission may already have settled. | Use `recoverSettlement()` with the same journal and network-bound reader; do not submit another attestation blindly. |
| Registration `pending` | Reverse-index registration has not been confirmed. | Use the same receipt with `checkRegistration()` or `retryRegistration()`; do not sign/pay again. |

`verifyReceipt({ receipt, network, reader })` reads back the exact transaction through the configured proxy and returns `verified` or `not_observed`. This is **configured-proxy evidence**, not independent validator-quorum verification. `createRecordClient({ network, indexOrigin, journal }).checkRegistration(receipt)` checks the separate reverse index. Neither `not_observed` nor a pending index record proves that settlement failed. If `recoveryPersisted` is false, preserve the returned receipt and repair durable recovery before relying on journal-based operations.

## Fees, networks, and public verification

Before authorization, inspect the selected proxy's `GET /v1/network-info` fee schedule and token metadata. The fee amount is in atomic units. `feePolicy` must specify an allowed token and maximum atomic amount; an authoritative zero-fee schedule requires `tokenId: null` and `maxAtomicAmount: "0"`. The SDK rechecks the fee schedule before submission. An unavailable or malformed fee response is not permission to assume zero, and a cached quote is not an enduring fee guarantee.

The [public Verify page](https://sign.fast.xyz/verify) serves **mainnet** file/hash lookups. A missing testnet record there says nothing about testnet; use a testnet-bound proxy reader and reverse-index origin for testnet. The website exposes no JSON verification or write API. Website signing needs a human wallet gesture; the SDK is the programmatic route for a separately authorized signer.

For a stamped PDF, the visible stamp is an **unsigned append**. Verification covers the signed-original byte prefix, not later PDF updates; hashing the entire stamped container usually gives a different digest. A signer-name field is self-declared unless a separate live Fast ID resolution binds the address to that name. Even a verified signature shows control of a key and a matching digest at settlement time, not that a person read, wrote, or endorsed the file. See [Fast Sign semantics](https://sign.fast.xyz/llms.txt) and the [agent guide](https://sign.fast.xyz/AGENTS.md).
