{
  "openapi": "3.1.0",
  "info": {
    "title": "Human Not Required API",
    "description": "The world's first AI-agent-only store. Humans can browse the storefront, but only an AI agent can place an order — it pays directly from its own wallet. There is no registration, no API key, and no card flow; the only order endpoint is POST /checkout.\n\nAgent flow:\n1. Call GET /orders/skus to see products and the live USDC price.\n2. POST /checkout with { sku, name, email, address } and no payment header. The server returns 402 with payment instructions.\n3. Sign an EIP-3009 transferWithAuthorization for the USDC amount using an x402 v2 client and retry the same request with the payment header (PAYMENT-SIGNATURE for v2, or X-PAYMENT for v1).\n4. USDC settles on Base and the hat ships to the provided address.\n\nRead the price, network, USDC contract, amount, and payee from the 402 envelope or /.well-known/payment-manifest.json — do not hard-code them. The store runs Base Sepolia (testnet) by default and flips to Base mainnet for production pricing.\n\nAlternatively, when the 402 also carries WWW-Authenticate: Payment method=\"stripe\" (Stripe Machine Payments Protocol), pay with a Stripe Link wallet: `link-cli mpp pay <checkout URL> -X POST -d '<body>'`. The client retries with Authorization: Payment <credential> (a Shared Payment Token); the server charges it through Stripe and returns 201 with a Payment-Receipt header.\n\nIf the human has a promo code, include it as promo_code (with no payment header) for a free order.",
    "version": "2.0.0"
  },
  "servers": [
    { "url": "https://web-production-77376.up.railway.app" }
  ],
  "paths": {
    "/orders/skus": {
      "get": {
        "operationId": "listSkus",
        "summary": "List available products and prices",
        "description": "Call this before placing an order to confirm the SKU exists and get the live price. No auth required. Price is single-sourced server-side, so it always matches what POST /checkout charges. Currently available: 'My Agent Bought Me This' embroidered hat (sku: hat-myagent-os), One Size.",
        "responses": {
          "200": {
            "description": "Full product catalog with SKUs, labels, sizes, and prices.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "skus": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "sku": { "type": "string", "description": "Use this value in POST /checkout" },
                          "label": { "type": "string", "description": "Human-readable product name" },
                          "size": { "type": "string" },
                          "price_usd": { "type": "number", "description": "Live USDC price (matches the x402 charge)" }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/checkout": {
      "post": {
        "operationId": "checkout",
        "summary": "Buy a hat with USDC over x402, a Stripe Link wallet (MPP), or a promo code — no registration",
        "description": "The only order endpoint. Fully agent-native: no registration, no saved card, no API key.\n\nx402 flow:\n1. POST with { sku, name, email, address } and no payment header — the server returns 402 with a Payment-Required header carrying accepts[] (network, USDC asset, amount in smallest units, payTo). An unpaid probe is answered with 402 regardless of body completeness; full body validation runs on the PAID retry, before settlement, so an invalid body returns 400 and no USDC is captured.\n2. Sign an EIP-3009 transferWithAuthorization with your Base wallet and retry the same request with the payment header (PAYMENT-SIGNATURE for x402 v2, or X-PAYMENT for v1).\n3. On 201 the Shopify order is created and USDC settles on Base.\n\nRead price/network/asset/payee from the 402 envelope — do not hard-code. Payment uses deferred capture: USDC is captured only after a 2xx, and cancelled on 4xx/5xx. A 502 means no USDC was captured (safe to retry). Idempotency is keyed on the payment nonce — replaying the same signed authorization returns your original order (200), not a duplicate.\n\nStripe MPP flow (when the 402 carries WWW-Authenticate: Payment method=\"stripe\"): retry the same body with Authorization: Payment <credential> containing a Shared Payment Token. The server validates the body, charges the token through Stripe (same USD price), creates the order and returns 201 with a Payment-Receipt header. Re-sending the same token returns the original order (200). If fulfillment fails after the charge, the payment is refunded (502).\n\nPromo flow: include promo_code (with no payment header) for a free order. Send exactly one of: promo_code, an x402 payment header, or an MPP credential.\n\nCollect the recipient's real name, email, and shipping address from the human — do not guess. All validation runs before payment settles, so a malformed body returns 400 with no charge.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["sku", "name", "email", "address"],
                "properties": {
                  "sku": {
                    "type": "string",
                    "description": "Product SKU from GET /orders/skus. Currently: 'hat-myagent-os'."
                  },
                  "name": {
                    "type": "string",
                    "description": "Full name (first and last) for the shipping label."
                  },
                  "email": {
                    "type": "string",
                    "format": "email",
                    "description": "Real, deliverable email for the order confirmation. Test domains are rejected."
                  },
                  "promo_code": {
                    "type": "string",
                    "description": "Optional promo code for a free order. If present, send NO payment header. Mutually exclusive with x402 payment."
                  },
                  "address": {
                    "type": "object",
                    "description": "Shipping address. Ask the human for all fields — do not guess or auto-fill.",
                    "required": ["line1", "city", "state", "postal_code", "country"],
                    "properties": {
                      "line1": { "type": "string", "description": "Street address line 1 (min 5 chars)" },
                      "line2": { "type": "string", "description": "Apartment, suite, unit, etc. (optional)" },
                      "city": { "type": "string" },
                      "state": { "type": "string", "description": "State or province, e.g. NY, CA, ON" },
                      "postal_code": { "type": "string" },
                      "country": { "type": "string", "description": "ISO 3166-1 alpha-2 country code, e.g. US, CA, GB" }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "402": {
            "description": "Payment required. The Payment-Required response header carries the x402 accepts[] (network, USDC asset, amount, payTo): sign an EIP-3009 transferWithAuthorization and retry with the payment header. When Stripe MPP is offered, WWW-Authenticate: Payment method=\"stripe\" carries the Stripe challenge: pay it with a Stripe Link wallet and retry with Authorization: Payment <credential>."
          },
          "201": {
            "description": "Order placed. For x402, USDC settles on Base; for a promo, no charge. The hat ships to the provided address.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "order_id": { "type": "string", "description": "Your order reference. Share with the human." },
                    "status": { "type": "string", "description": "'placed' on success." },
                    "sku": { "type": "string" },
                    "shopify_order_id": { "type": "string", "description": "Shopify fulfillment ID." },
                    "payment": { "type": "string", "description": "'x402_usdc_base', 'stripe_mpp' or 'promo_free'." },
                    "free_order": { "type": "boolean", "description": "true if a promo code covered this order." },
                    "message": { "type": "string" }
                  }
                }
              }
            }
          },
          "200": {
            "description": "Idempotent replay. The same payment authorization (or the same promo_code + email) was already processed — returns the original order with idempotent: true. No second order is created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "order_id": { "type": "string" },
                    "status": { "type": "string" },
                    "sku": { "type": "string" },
                    "shopify_order_id": { "type": "string" },
                    "payment": { "type": "string" },
                    "idempotent": { "type": "boolean" },
                    "message": { "type": "string" }
                  }
                }
              }
            }
          },
          "400": { "description": "Missing or invalid field (e.g. missing_field, invalid_sku, needs_address, invalid_name, invalid_email, invalid_address, invalid_country, field_too_long, invalid_promo_code, ambiguous_payment). No payment is charged — fix the body and retry." },
          "409": { "description": "One of: (a) a checkout for this x402 payment authorization or Stripe payment token is already in flight, previously failed, or was refunded — do NOT re-send the SAME authorization/token; (b) promo_exhausted — the promo code reached its redemption cap (terminal, no retry, no order exists); (c) redemption_in_progress — a redemption for this promo+email is being processed, retry shortly. Inspect the response body's error field to tell them apart." },
          "429": { "description": "Rate limited: too many promo attempts (per IP), or the optional per-email daily x402 cap was exceeded." },
          "502": { "description": "fulfillment_failed — Shopify order creation failed. With deferred capture, NO USDC was captured. Safe to retry." },
          "503": { "description": "Store closed, fulfillment unconfigured, payment system inactive, or a transient database error. No order created and no payment taken." }
        }
      }
    }
  }
}
