# stampthisfile

> Timestamp files in Bitcoin. Send the SHA-256 hash of a file (never the file), pay 0.05 USDC per hash on Base with x402 (no account, no API key), and get a standard OpenTimestamps (.ots) proof. OpenTimestamps (https://opentimestamps.org) is the open protocol for Bitcoin timestamps; any OTS tool verifies our proofs. Within a few hours it is anchored in a Bitcoin block, and anyone can verify it without us.

What a proof shows: the file existed **no later than** the time of the Bitcoin block it is anchored in. It does not show who made the file, it is not a signature, and it is not an eIDAS qualified timestamp.

**Before you stamp, read https://stampthisfile.com/evidence.md.** It says what a stamp proves and doesn't, when stamping is worth it, when you need a signature, notary or qualified timestamp instead, how to keep a stamp useful as evidence, and how courts have treated Bitcoin timestamps so far. The full research is at https://stampthisfile.com/evidence/report.md.

## Stamp hashes (paid)

`POST https://stampthisfile.com/v1/stamps` with `Content-Type: application/json`:

```json
{
  "hashes": ["<sha256 hex>", "..."],
  "webhook": { "url": "https://example.com/hooks/stamps", "signing_key": "whsec_<base64>" }
}
```

- `hashes`: 1 to 100 SHA-256 hashes, each 64 hex characters, and each only once (a repeated hash is a 400). Each hash costs the unit price, so 3 hashes cost 3 × 0.05.
- `webhook`: optional. It must be a public https URL. `signing_key` is also optional (see Webhooks below).
- To hash a file: `sha256sum file.pdf` (Linux), `shasum -a 256 file.pdf` (macOS), or `crypto.subtle.digest('SHA-256', bytes)`.

### Paying with x402 (v2)

1. Send the request without payment. The answer is `402`, with the price in the JSON body and in the `PAYMENT-REQUIRED` header (base64 JSON). The relevant fields are `accepts[0]`: `scheme: "exact"`, `network` (CAIP-2, e.g. `eip155:8453` for Base), `asset` (the USDC contract), `amount` (atomic units, 6 decimals), `payTo`, `maxTimeoutSeconds`, and `extra` (the token's EIP-712 name and version).
2. Sign an EIP-3009 `TransferWithAuthorization` for exactly that amount, to `payTo`, with a random 32-byte nonce. Any x402 client does this (for example `@x402/fetch`, or `x402-fetch` with an EVM wallet). You need USDC on that network but no gas: the facilitator pays it.
3. Repeat the same request, with the same body, adding `PAYMENT-SIGNATURE: <base64 PaymentPayload>`.
4. You get `200` with the proofs, plus a `PAYMENT-RESPONSE` header (base64 JSON: `success`, `transaction`, `network`, `payer`).

Errors:
- A failed verification or settlement is `402` with the reason, and nothing is stamped.
- Invalid input is `400` and is never charged.
- If fewer than 2 timestamp calendars answer, you get `503` and nothing is charged.
- Retrying with the same payment and the same body returns the same 200, without paying twice. The same payment with a different body is a `402`.

### Response

```json
{
  "batch_id": "bat_…",
  "stamps": [
    { "id": "stp_…", "hash": "<sha256 hex>", "status": "pending",
      "ots": "<base64 .ots proof>", "ots_url": "https://stampthisfile.com/v1/stamps/stp_….ots", "status_url": "https://stampthisfile.com/v1/stamps/stp_…" }
  ],
  "receipt": { "format": "stampthisfile-receipt-v1", "batch_id": "…", "received_at": "…", "stamps": [{ "id": "…", "hash": "…" }],
    "payment": { "network": "…", "asset": "…", "amount": "…", "pay_to": "…", "payer": "…", "transaction": "0x…" },
    "signature": { "alg": "Ed25519", "kid": "…", "value": "<base64>" } }
}
```

- Save the `ots` file straight away. It is a valid proof that is still *pending*: it names the calendars that will commit it to Bitcoin.
- `status` becomes `complete` within a few hours, usually 1–6. Then download `ots_url` again to get the complete proof, which includes the Bitcoin attestation.
- The receipt is our signed statement that we received these hashes at `received_at`, paid by `payer`.
  - Signed content: `"stampthisfile-receipt-v1\n"` followed by the RFC 8785 canonical JSON of the receipt without `signature`.
  - Key: see `https://stampthisfile.com/.well-known/stampthisfile-keys`.
  - The .ots proof does not depend on the receipt, or on us.

## Read stamps (free)

- `GET https://stampthisfile.com/v1/stamps/{id}` returns `{id, hash, status: pending|complete|failed, bitcoin?: {height, block_time}, statement?, ots_url}`.
- `GET https://stampthisfile.com/v1/stamps/{id}.ots` returns the current proof (`application/vnd.opentimestamps.v1`).
- `failed` means the proof was not confirmed in Bitcoin within 7 days. This is rare. The pending proof stays downloadable; contact us for a refund to the paying address.

## Verify a proof (free)

`POST https://stampthisfile.com/v1/verify` with `{"hash": "<sha256 hex of the file>", "ots": "<base64 .ots>"}`. It returns one of:

- `{"valid": true, "status": "complete", "bitcoin": {"height", "block_time"}, "statement"}`. If the proof you sent was still pending but its calendars have since committed it, we fetch the rest of the path and add `"upgraded": true, "ots": "<base64 complete proof>"`: save that as your .ots.
- `{"valid": true, "status": "pending", "calendars": [...]}`
- `{"valid": false, "status": "invalid", "reason"}`

Nothing is stored. To verify without us, upload the file and its .ots to https://opentimestamps.org, or run `ots verify file.ots` (the opentimestamps-client, which needs a Bitcoin node).

## MCP server

`POST https://stampthisfile.com/mcp` is an MCP server (Streamable HTTP, stateless, no API key) with the same capabilities: `stamp_hashes` (paid), `get_stamp`, `get_proof` and `verify_proof`. `stamp_hashes` follows the x402 MCP transport: without a payment it returns a tool error whose `structuredContent` is the PaymentRequired; retry with the PaymentPayload in `_meta["x402/payment"]` (or the `payment` argument, as an object or base64), and the settlement comes back in `_meta["x402/payment-response"]`. Claude Code: `claude mcp add --transport http stampthisfile https://stampthisfile.com/mcp`.

## Webhooks

If you pass `webhook.url`, it receives one POST per request (per batch) when the stamps complete or fail:

```json
{ "type": "stamps.completed", "timestamp": "2026-10-19T22:00:00.000Z",
  "data": { "batch_id": "bat_…", "status": "complete", "bitcoin": { "height": 920000, "block_time": "…" },
            "stamps": [{ "id": "stp_…", "hash": "…", "ots_url": "…", "status_url": "…" }] } }
```

- `type` is `stamps.completed` or `stamps.failed` (the latter has `reason` instead of `bitcoin`).
- Deliveries follow Standard Webhooks (https://www.standardwebhooks.com). Each has the headers `webhook-id`, `webhook-timestamp` and `webhook-signature`, and the signed content is `{webhook-id}.{webhook-timestamp}.{raw body}`.
- The `webhook-signature` header holds one or two signatures, separated by a space:
  - **Always:** `v1a,<base64 Ed25519 signature>`, made with our key `whpk_KGA++FnB86CukP1EVU2J5UQ9hfFOh2fxbkIS/RoeRbE=` (also at `/.well-known/stampthisfile-keys`). This needs no shared secret.
  - **Only when you sent `webhook.signing_key`:** `v1,<base64 HMAC-SHA256>`, keyed with the base64-decoded part of your `whsec_…`, which must decode to 24–64 bytes. Standard Webhooks libraries verify this one out of the box. We store your key encrypted and never return it.
- Reject a `webhook-timestamp` more than 5 minutes old. Answer any 2xx quickly.
- Failed deliveries are retried after 1 m, 5 m, 15 m, 1 h, 3 h, 6 h and 12 h, with the same `webhook-id` (use it to drop duplicates) and a fresh timestamp and signature on each attempt. Redirects are not followed.

## Notes

- Price: 0.05 USDC per hash on Base. Payments are x402 v2, `exact` scheme, USDC (EIP-3009).
- Your payment is public on chain: the paying address is linked to the time of the stamp, but not to your hash.
- We never see your file, only its hash. Each hash is mixed with a random nonce before it goes into a Merkle tree, so other customers' proofs don't reveal your hash.
- Agent skill: `npx skills add stampthisfile/skills` (https://github.com/stampthisfile/skills), with a script that hashes, pays, stamps, upgrades and verifies.
- Evidence guidance: https://stampthisfile.com/evidence.md (court research: https://stampthisfile.com/evidence/report.md).
- More: OpenAPI at https://stampthisfile.com/openapi.json; the human version is https://stampthisfile.com/.
