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

# X402

> About X402 (Coinbase) and how to use it with markdown2pdf.ai

## X402: HTTP-native stablecoin payments

X402 is an open payment protocol from Coinbase that reactivates the HTTP `402 Payment Required`
status code for machine-to-machine stablecoin payments. It is complementary to
[L402](/l402) — same goal of programmable, accountless payments inside HTTP — just settling in
USDC on Solana instead of sats on the Lightning Network.

### Key properties

* **Stablecoin-denominated.** Payments settle in USDC on Solana, so the amount a
  client sees in the 402 response is the exact number of dollars they will spend. No FX.
* **On-chain and low-friction.** Solana settlement is sub-second and costs a fraction
  of a cent in gas. No counterparty risk after the facilitator returns success.
* **Header-driven.** The client attaches one base64 `X-PAYMENT` header to the original
  request and re-submits. The server verifies + settles via a facilitator and returns
  `200` with an `X-Payment-Response` header carrying the settlement proof.
* **Agent-friendly.** The flow is the same for humans and autonomous agents, and it's
  supported out of the box by the Coinbase SDK as well as the open `x402-axios`, `x402-fetch`,
  and Python `x402[httpx]` clients. Learn more at [x402.org](https://x402.org).

## markdown2pdf.ai and X402

markdown2pdf.ai accepts both L402 (Lightning) and X402 (USDC on Solana). Pick whichever rail
your agent already has a wallet for.

* **L402:** 5 sats per PDF, instant via Lightning.
* **X402:** \$0.01 USDC per PDF, instant via Solana.

You pay per document. Re-submitting the same markdown reuses the paid receipt — our server
dedupes on a `sha256` of the markdown body for both rails.

## Flow

<Steps>
  <Step title="POST /markdown with your markdown content.">
    If you haven't paid yet, the server returns `402` with a body that contains an `offers[]`
    array. When X402 is enabled there are two entries — one for Lightning and one for X402.
  </Step>

  <Step title="Read the X402 offer.">
    The X402 offer carries `payment_methods: ["x402"]` and a `metadata.x402` block with the
    native x402 `accepts[]` array — the payment requirements the facilitator will validate
    against (network, asset, `payTo`, `maxAmountRequired`, scheme).
  </Step>

  <Step title="Sign an X-PAYMENT payload.">
    Use any x402-aware client (Coinbase SDK, `x402-axios`, `x402-fetch`, or Python
    `x402[httpx]`) to construct and base64-encode a `PaymentPayload` authorising the transfer.
  </Step>

  <Step title="Re-submit POST /markdown with X-PAYMENT.">
    Send the exact same request body, plus `X-PAYMENT: <base64>` as a header.
  </Step>

  <Step title="Server verifies + settles via the facilitator, returns 200.">
    A successful response carries `X-Payment-Response: <base64>` — the base64-encoded
    `SettleResponse` with the on-chain transaction hash. Your agent can log this for
    auditing, or ignore it and proceed straight to polling the job status.
  </Step>
</Steps>

<Tip>
  **Alternative shortcut.** If your client already speaks x402 natively and does not want to
  parse the L402 envelope, it can ignore the outer body entirely and read `accepts[]`
  straight from `offers[].metadata.x402.accepts` — no second round-trip required. We also
  expose a dedicated `POST /payment_request/x402` endpoint for clients that prefer an
  explicit per-offer lookup.
</Tip>

## REST example

Python, using [`x402[httpx]`](https://github.com/coinbase/x402). Set `SOLANA_SIGNER_KEY`
to your wallet's base58 private key (64-byte keypair as exported by most Solana wallets).

```python theme={null}
import os
import asyncio
from solders.keypair import Keypair
from x402 import x402Client, prefer_network
from x402.http.clients.httpx import x402HttpxClient
from x402.mechanisms.svm import KeypairSigner
from x402.mechanisms.svm.exact import ExactSvmScheme

async def main():
    # 1. Initialize signer from base58 private key
    keypair = Keypair.from_base58_string(os.environ["SOLANA_SIGNER_KEY"])
    signer = KeypairSigner(keypair)

    # 2. Configure x402 client for Solana Mainnet
    NETWORK = "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp"
    x402 = x402Client()
    x402.register(NETWORK, ExactSvmScheme(signer=signer))
    x402.register_policy(prefer_network(NETWORK))

    # 3. The async client handles the 402 → sign → retry loop
    async with x402HttpxClient(x402, timeout=120.0) as client:
        resp = await client.post(
            "https://api.markdown2pdf.ai/markdown",
            json={
                "data": {"text_body": "# Hello from X402"},
                "options": {"document_name": "hello.pdf"},
            },
        )
        resp.raise_for_status()
        print("Paid tx proof:", resp.headers.get("payment-response"))
        print("Poll path:", resp.json()["path"])

if __name__ == "__main__":
    asyncio.run(main())
```

The `x402HttpxClient` handles the 402 → sign → retry loop for you. If you want to do it
manually (e.g. to customise the flow), the recipe is:

```python theme={null}
import base64, json, httpx
from x402.http.utils import encode_payment_signature_header

# 1. First request returns 402
r = httpx.post(url, json=payload)
assert r.status_code == 402
accepts = r.json()["offers"][1]["metadata"]["x402"]["accepts"][0]  # x402 offer

# 2. Build + sign a PaymentPayload using the scheme's client-side helper
# (see x402 docs for ExactSvmClientScheme.build_payment_payload)
payment_header = encode_payment_signature_header(signed_payload)

# 3. Re-POST with X-PAYMENT
r = httpx.post(url, json=payload, headers={"X-PAYMENT": payment_header})
r.raise_for_status()
```

## When to pick X402 vs L402

<CardGroup cols={2}>
  <Card title="Pick L402 if..." icon="bitcoin">
    Your agent already holds sats and/or uses Lightning wallets such as Alby, LNbits, or
    Fewsats. Lightning settlement is instant and fees are negligible. See the
    [L402 page](/l402).
  </Card>

  <Card title="Pick X402 if..." icon="coins">
    Your agent already holds USDC on Solana, or you want dollar-denominated predictability.
    X402 is well-supported by the Coinbase CDP SDK and by `x402-axios` / `x402-fetch` on
    the TypeScript side.
  </Card>
</CardGroup>

Either way, the document generation backend is identical — the choice is purely about how
you want to pay.
