# SingleFax Machine Payment Protocol (MPP) Guide

This document is for autonomous agents that want to pay for a fax send
without a human in the loop, using the [Machine Payments Protocol
(MPP)](https://docs.stripe.com/payments/machine/mpp) pattern (HTTP 402 +
Stripe Shared Payment Token) via the pinned `mppx` SDK.

Chat apps (Cursor, Claude, Codex, ChatGPT) should start at
[https://singlefax.com/agents](https://singlefax.com/agents) and use **MCP +
Checkout**, not this flow. Cursor has no Stripe wallet. To pay MPP from a
coding agent that can run a terminal, use [Stripe Link CLI](https://link.com/agents)
against the REST URL below — never against `/mcp` (MCP returns JSON, not HTTP 402).

**Status: sandbox-ready (fiat SPT).** US legal entity + Stripe profile are configured.
Machine fax endpoints are live when `NUXT_STRIPE_PROFILE_ID` is set. Crypto/stablecoin Tempo payments are a separate path (Payment Methods →
Stablecoins); fiat SPT does **not** use that toggle — it needs the `profile_…` as
`networkId` and card/Link rails.

Configured profile id is stored as `NUXT_STRIPE_PROFILE_ID` (see `.env` / Nomad vars).

When enabled, challenges are persisted (request hash, quote version, amount,
idempotency key, status token). Reusing a `request_id` with a different body
returns `409`.

## Pay from Cursor / Claude Code / Codex

US Link account required. Approve each spend in the Link app.

```bash
npx skills add stripe/link-cli
# or: npx @stripe/link-cli --mcp   # add as an MCP server in the same client

npx @stripe/link-cli auth login

npx @stripe/link-cli mpp pay https://singlefax.com/api/v1/machine/faxes \
  -X POST \
  -d '{"to":"+14155552671","base64":"<real-pdf-base64>","request_id":"mpp-1"}' \
  --context "Send a fax via SingleFax after the user asked this agent to pay for the send."
```

Local: swap the origin for `http://localhost:3000`. Same E.164 / real-PDF rules
as `mppx validate`.

## Local validation

Use a **valid E.164** destination (not `+1555…` — those fail `libphonenumber` validity)
and real PDF base64 (not a placeholder string):

```bash
pnpm exec mppx validate http://localhost:3000 \
  -e 'POST:/api/v1/machine/faxes' \
  --body '{"to":"+14155552671","base64":"<real-pdf-base64>","request_id":"mpp-validate-1"}' \
  -j
```

Discovery document: `GET /openapi.json` (includes `x-payment-info` on the machine fax route).

## Endpoints

### 1. Validate (quote only, no side effects)

```
POST /api/v1/machine/faxes/validate
Content-Type: application/json

{
  "to": "+14155552671",
  "base64": "<pdf bytes, base64>",
  "request_id": "your-idempotent-request-id"
}
```

### 2. Create (MPP challenge)

```
POST /api/v1/machine/faxes
Content-Type: application/json

{ "to": "+14155552671", "base64": "<pdf bytes, base64>", "request_id": "…" }
```

Without payment → `402` + `WWW-Authenticate` + `status_token` in the problem body.

Retry with:

```
Authorization: Payment …
```

On success a fax order is created once and queued via the shared outbox.

### 3. Status (capability-token gated)

```
GET /api/v1/machine/faxes/:request_id?statusToken=…
```

### Refunds

On final delivery failure, the MPP PaymentIntent is refunded via the dedicated
MPP Stripe client (preview API version isolated from retail Checkout).

## Minimum charge

Stripe SPT enforces a $0.50 USD minimum. SingleFax retail floor is $0.99.
