{"message":"Client & agent samples (HTML).","url":"/docs/samples","markdown":"# Client and agent samples\n\nThis page documents **flows people actually use**: in a **browser** (visit site, pay, paste tx id or use a token) or with an **agent/CLI** (GET 402 → pay → call facilitator → GET with Bearer). All examples use the live site and facilitator; copy-paste curl and pseudocode only.\n\n---\n\n## Flows in practice\n\n**Browser (on the site):**\n\n1. Open the protected URL (e.g. https://xpr.testsitout.com/protected-route).\n2. You see payment required: send `maxAmountRequired` to `payTo` (e.g. 0.1000 XPR to cbeau).\n3. After paying, either:\n   - **Paste the transaction id** in the form and submit, or\n   - **Use a facilitator token:** POST your `tx_id` (and `audience` if the 402 showed `facilitatorAudience`) to `facilitatorUrl`, then call the protected URL with `Authorization: Bearer <token>` (e.g. via dev tools or a small script).\n\n**Agent / CLI:**\n\n1. GET the protected URL with `Accept: application/json` → 402 with JSON body.\n2. Parse `payTo`, `maxAmountRequired`, `resource`, and if present `facilitatorUrl`, `facilitatorAudience`.\n3. Pay (user pays and provides tx id, or automated wallet returns `transaction_id`).\n4. **If no facilitator:** GET the protected URL with header `X-Payment-Authorization: <id>` (or `Authorization: Payment tx_id=<id>`). `?tx_id=<id>` remains available for local/dev convenience.\n5. **If facilitator present:** POST to `facilitatorUrl` with `{ \"tx_id\", \"resource\", \"audience\"? }`; if response is 402 (indexer lag), wait 2–5s and retry; then GET the protected URL with `Authorization: Bearer <token>` and `Accept: application/json`.\n\n---\n\n\n## Easy test flows (copy-paste)\n\n**1. Get 402 and payment details (must use Accept: application/json for JSON):**\n\n```bash\ncurl -sS -H \"Accept: application/json\" https://xpr.testsitout.com/protected-route\n```\n\nYou get JSON with `payTo`, `maxAmountRequired`, `resource`, and when the site uses a facilitator: `facilitatorUrl`, `facilitatorAudience`.\n\n**2. Unlock with transaction id only (after you paid):**\n\n```bash\ncurl -sS -H \"Accept: application/json\" -H \"X-Payment-Authorization: YOUR_TX_ID\" https://xpr.testsitout.com/protected-route\n```\n\n**3. Full flow with facilitator (curl only):**\n\nAfter you have paid and have a real `TX_ID`, run the following. Retry on 402 (indexer lag): try immediately, then 2s, 3s, 5s.\n\n```bash\n# Set your transaction id from the wallet/explorer after paying\nTX_ID=\"YOUR_TX_ID\"\nPROTECTED_URL=\"https://xpr.testsitout.com/protected-route\"\nFACILITATOR_URL=\"https://facilitator-xpr.testsitout.com/verify\"\nRESOURCE=\"/protected-route\"\nAUDIENCE=\"mpc-test\"\n\n# POST to facilitator; retry on 402 (indexer lag)\nfor wait in 0 2 3 5; do\n  [ \"$wait\" -gt 0 ] && echo \"Retrying in ${wait}s...\" && sleep \"$wait\"\n  VERIFY=$(curl -sS -w \"\\n%{http_code}\" -X POST \"$FACILITATOR_URL\" \\\n    -H \"Content-Type: application/json\" \\\n    -d \"{\\\"tx_id\\\":\\\"$TX_ID\\\",\\\"resource\\\":\\\"$RESOURCE\\\",\\\"audience\\\":\\\"$AUDIENCE\\\"}\")\n  CODE=$(echo \"$VERIFY\" | tail -n1)\n  BODY=$(echo \"$VERIFY\" | sed '$d')\n  TOKEN=$(echo \"$BODY\" | jq -r '.token // empty')\n  [ -n \"$TOKEN\" ] && break\n  [ \"$CODE\" != \"402\" ] && break\ndone\n\n# Unlock the protected resource with the token\nif [ -n \"$TOKEN\" ]; then\n  curl -sS -H \"Accept: application/json\" -H \"Authorization: Bearer $TOKEN\" \"$PROTECTED_URL\"\nelse\n  echo \"No token (use Unlock URL with ?tx_id= as fallback)\"\nfi\n```\n\n---\n\n## Client sample (minimal integration)\n\n**1. Request the resource with `Accept: application/json`.**\n\n```bash\nRESP=$(curl -sS -w \"\\n%{http_code}\" -H \"Accept: application/json\" \"https://xpr.testsitout.com/protected-route\")\nCODE=$(echo \"$RESP\" | tail -n1)\nBODY=$(echo \"$RESP\" | sed '$d')\n```\n\n**2. If status is 402, parse the body (e.g. with `jq`):**\n\n- `payTo` — XPR account to send funds to\n- `maxAmountRequired` — e.g. `\"0.1000 XPR\"`\n- `resource` — e.g. `\"/protected-route\"`\n- `facilitatorUrl` — (optional) e.g. `\"https://facilitator-xpr.testsitout.com/verify\"`\n- `facilitatorAudience` — (optional) e.g. `\"mpc-test\"`\n\n**3a. Unlock with transaction id only (after user pays and gives you `tx_id`):**\n\n```bash\ncurl -sS -H \"Accept: application/json\" -H \"Authorization: Payment tx_id=$TX_ID\" \"https://xpr.testsitout.com/protected-route\"\n```\n\n**3b. Unlock via facilitator (after user pays, you have `tx_id`):**\n\nPOST to `facilitatorUrl` with body `{ \"tx_id\": \"<id>\", \"resource\": \"<resource from 402>\", \"audience\": \"<facilitatorAudience from 402 if present>\" }`. If the response is **402**, the chain may have finalized before the indexer; wait 2–5 seconds and retry the POST (see \"Full flow with facilitator\" above). On **200**, read `token` and call the protected URL with `Authorization: Bearer <token>` and `Accept: application/json`.\n\n```bash\n# Assume FACILITATOR_URL, RESOURCE, AUDIENCE, TX_ID from 402 and payment\nTOKEN=$(curl -sS -X POST -H \"Content-Type: application/json\" \\\n  -d \"{\\\"tx_id\\\":\\\"$TX_ID\\\",\\\"resource\\\":\\\"$RESOURCE\\\",\\\"audience\\\":\\\"$AUDIENCE\\\"}\" \\\n  \"$FACILITATOR_URL\" | jq -r '.token // empty')\n# If TOKEN empty and response was 402, retry after 2s, 3s, 5s (indexer lag)\ncurl -sS -H \"Accept: application/json\" -H \"Authorization: Bearer $TOKEN\" \"https://xpr.testsitout.com/protected-route\"\n```\n\n**4. If status is 200,** the body is the premium content (JSON or HTML depending on Accept).\n\n---\n\n## Agentic sample (AI agent / automated flow)\n\n**Step 1 — Get payment requirements**\n\n- GET the protected URL with header `Accept: application/json`.\n- If **200**, resource is already unlocked; use the body.\n- If **402**, parse JSON for: `payTo`, `maxAmountRequired`, `resource`, `facilitatorUrl` (optional), `facilitatorAudience` (optional).\n\n**Step 2 — Obtain payment proof**\n\n- **User pays:** Ask the user to send `maxAmountRequired` to `payTo` on XPR/Proton and provide the **transaction id**.\n- **Automated wallet:** Use proton CLI or SDK to transfer; capture `transaction_id` from the response.\n\n**Step 3 — Unlock the resource**\n\n- **No facilitator:** GET the same URL with header `X-Payment-Authorization: <TRANSACTION_ID>` or `Authorization: Payment tx_id=<TRANSACTION_ID>`, and `Accept: application/json` for JSON.\n- **Facilitator present:**\n  1. POST to `facilitatorUrl` with body `{ \"tx_id\": \"<id>\", \"resource\": \"<resource from 402>\", \"audience\": \"<facilitatorAudience if present>\" }`, `Content-Type: application/json`.\n  2. If response is **402**, wait 2s, 3s, or 5s and retry (indexer lag); repeat until 200 or give up.\n  3. From **200** response, read `token`.\n  4. GET the protected URL with `Authorization: Bearer <token>` and `Accept: application/json`.\n\n**Step 4 — Use the content**\n\n- If **200**, the body is the premium response. Each `tx_id` unlocks only once.\n\n**Pseudocode:**\n\n```\n1. res = GET(protected_url, Accept: application/json)\n2. if res.status == 200: return res.body\n3. if res.status != 402: return error\n4. payTo, amount, resource = res.body; facilitatorUrl = res.body.facilitatorUrl; facilitatorAudience = res.body.facilitatorAudience\n5. tx_id = [user provides or wallet transfer]\n6. if facilitatorUrl:\n     for wait in [0, 2, 3, 5]:\n       if wait > 0: sleep(wait)\n       r = POST(facilitatorUrl, {tx_id, resource, audience?})\n       if r.status == 200 and r.token: break\n       if r.status != 402: fail\n     GET(protected_url, Authorization: Bearer r.token, Accept: application/json)\n7. else: GET(protected_url, headers: {\"X-Payment-Authorization\": tx_id, \"Accept\": \"application/json\"})\n```\n\n---\n\n## References\n\n- **Site:** https://xpr.testsitout.com\n- **README (HTML):** https://xpr.testsitout.com/readme\n- **Facilitator flow (HTML):** https://xpr.testsitout.com/docs/facilitator\n- **This page (markdown):** https://xpr.testsitout.com/docs/samples?format=md\n- **llm.txt (for LLMs):** https://xpr.testsitout.com/llm.txt\n- **Source code:** https://github.com/French-River-Hosting/xpr-x402\n- **x402:** https://www.x402.org | https://docs.x402.org\n"}