{
  "openapi": "3.1.0",
  "info": {
    "title": "penny402",
    "version": "0.1.0",
    "summary": "The penny arcade of the x402 economy. Every attraction a quarter-penny; the unpaid 402 is the quote.",
    "description": "Small, self-contained, instantly-answered attractions for agents, each a flat $0.0025 in USDC on Base or Solana. No account and no API key: an unpaid POST answers 402 with the exact terms, and paying that 402 is the whole authentication story. Quote and charge come from one function, so the number advertised is the number that settles.",
    "x-guidance": "penny402 is a penny arcade for agents: small, self-contained, instantly-answered attractions, each a flat $0.0025 in USDC on Base or Solana over x402. No account, no API key, no minimum.\n\nTHE QUOTE IS THE 402. POST an unpaid request to any attraction and the 402 that comes back carries the exact terms — amount, asset, payTo, network — for that call. Pay it by repeating the identical request with the payment header, and the amount that settles is the amount that was quoted. There is one pricing function and both sides read it.\n\nHeaders: send X-PAYMENT for x402 v1, or PAYMENT-SIGNATURE for x402 v2. The v1 envelope is the 402 response body; the v2 envelope is standard base64 in the PAYMENT-REQUIRED response header. Both versions are served from the same 402, so use whichever your client speaks.\n\nRails: Base — USDC 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913, network \"base\" in x402 v1 and \"eip155:8453\" in v2; Solana — USDC EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v, network \"solana\" in x402 v1 and \"solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp\" in v2. Every rail carries the SAME quote — a second rail is a second way to pay, never a second price. The accepts array in the 402 you were handed is authoritative; pay the first entry you can, which is the order they are listed in.\n\nPOST is how you buy. A GET or HEAD on an attraction answers the same payable 402 so a prober can read the terms without spending, but a payment presented on GET is refused without settling.\n\nEvery attraction is SYNCHRONOUS. The paid response body is the answer: there is no job id, nothing to poll, and no expiring link. Attractions take no parameters — POST {} — so a bare probe and a real purchase send the identical body.\n\nGET /v1/attractions is the directory: every attraction id, its path, its price in dollars and in atomic USDC, and what it returns. It is free, it is the catalog every other surface here is rendered from, and it is the cheapest way to find out what is open.",
    "contact": {
      "email": "hello@penny402.fun",
      "url": "https://penny402.fun"
    }
  },
  "servers": [
    {
      "url": "https://penny402.fun"
    }
  ],
  "paths": {
    "/": {
      "get": {
        "operationId": "getLandingPage",
        "summary": "the landing page",
        "description": "The human surface. Rendered from the same catalog as /v1/attractions, so its prices are the live ones.",
        "security": [],
        "responses": {
          "200": {
            "description": "the page",
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/llms.txt": {
      "get": {
        "operationId": "getLlmsTxt",
        "summary": "the same facts, terse, for a machine reader",
        "description": "Endpoints, payment terms and the attraction list as plain text. Cheaper to read than this document if you already know x402.",
        "security": [],
        "responses": {
          "200": {
            "description": "plain text",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/v1/attractions": {
      "get": {
        "operationId": "getAttractions",
        "summary": "the directory",
        "description": "Every attraction: id, path, price in dollars and atomic USDC, title and description. This is the catalog every other surface — including this document — is rendered from.",
        "security": [],
        "responses": {
          "200": {
            "description": "the directory",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "service",
                    "attractions"
                  ],
                  "properties": {
                    "service": {
                      "type": "string",
                      "const": "penny402"
                    },
                    "tagline": {
                      "type": "string"
                    },
                    "attractions": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "required": [
                          "id",
                          "path",
                          "price",
                          "price_atomic",
                          "title",
                          "description"
                        ],
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "path": {
                            "type": "string",
                            "description": "POST here to buy it"
                          },
                          "price": {
                            "type": "string",
                            "description": "the flat price, in dollars",
                            "examples": [
                              "$0.0025"
                            ]
                          },
                          "price_atomic": {
                            "type": "string",
                            "description": "the same price in USDC base units"
                          },
                          "title": {
                            "type": "string"
                          },
                          "description": {
                            "type": "string"
                          }
                        }
                      }
                    },
                    "estate": {
                      "type": "array",
                      "description": "the same operator's other paid services",
                      "items": {
                        "type": "object",
                        "properties": {
                          "url": {
                            "type": "string"
                          },
                          "what": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/openapi.json": {
      "get": {
        "operationId": "getOpenApi",
        "summary": "this document",
        "description": "Rendered from the catalog on each request, so the prices and schemas here are the live ones.",
        "security": [],
        "responses": {
          "200": {
            "description": "this document",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/robots.txt": {
      "get": {
        "operationId": "getRobotsTxt",
        "summary": "crawl policy",
        "description": "Everything is allowed.",
        "security": [],
        "responses": {
          "200": {
            "description": "plain text",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/og.svg": {
      "get": {
        "operationId": "getOgCard",
        "summary": "the share card",
        "description": "The social card as SVG.",
        "security": [],
        "responses": {
          "200": {
            "description": "an SVG image",
            "content": {
              "image/svg+xml": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/penny": {
      "post": {
        "operationId": "buyPenny",
        "summary": "buy A penny for your thoughts",
        "description": "The arcade turnstile: pay a quarter-penny and receive the full penny402.fun directory — every attraction, its path, price, and what it returns — plus one hand-picked thought about the x402 economy to take with you. The cheapest way for an agent to learn what this arcade sells and verify the payment loop works. A flat $0.0025 per call. Unpaid: 402 carrying exactly those terms. Paid: the answer is the response body, synchronously — no job, no polling, nothing that expires. This attraction takes no parameters, so POST {} either way. A GET or HEAD answers the same payable 402 for probing; the sale happens on POST.",
        "requestBody": {
          "required": false,
          "description": "this attraction takes no parameters. Send {}, or nothing at all.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {},
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "the attraction. Payment is settling behind this response.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "thought": {
                      "type": "string",
                      "description": "one thought, yours to keep"
                    },
                    "attractions": {
                      "type": "array",
                      "description": "the full arcade directory: path, price, and pitch per attraction",
                      "items": {
                        "type": "object",
                        "properties": {
                          "path": {
                            "type": "string"
                          },
                          "price": {
                            "type": "string"
                          },
                          "title": {
                            "type": "string"
                          },
                          "description": {
                            "type": "string"
                          }
                        }
                      }
                    },
                    "estate": {
                      "type": "array",
                      "description": "the serious side of this operator: related paid services",
                      "items": {
                        "type": "object",
                        "properties": {
                          "url": {
                            "type": "string"
                          },
                          "what": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "the body is not a JSON object. Nothing was charged, even if a payment was presented.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error"
                  ],
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "what went wrong, in prose"
                    }
                  },
                  "additionalProperties": true
                }
              }
            }
          },
          "402": {
            "description": "Payment Required",
            "headers": {
              "PAYMENT-REQUIRED": {
                "description": "the x402 v2 envelope, standard base64 of JSON. A v1 client ignores it and reads the body.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "x402Version",
                    "accepts"
                  ],
                  "properties": {
                    "x402Version": {
                      "type": "integer",
                      "const": 1
                    },
                    "error": {
                      "type": "string"
                    },
                    "quote": {
                      "type": "object",
                      "description": "the price in words. The same number as the envelope, from the same catalog.",
                      "properties": {
                        "usd": {
                          "type": "string",
                          "examples": [
                            "$0.0025"
                          ]
                        },
                        "atomic_usdc": {
                          "type": "string",
                          "description": "the amount that settles, in USDC base units (6 decimals)"
                        },
                        "asset": {
                          "type": "string",
                          "examples": [
                            "USDC on Base",
                            "USDC on Base or Solana"
                          ]
                        }
                      }
                    },
                    "accepts": {
                      "type": "array",
                      "minItems": 1,
                      "description": "every rail this call can be paid on, best first. Each entry carries the SAME maxAmountRequired — a second rail is a second way to pay, not a second price.",
                      "items": {
                        "type": "object",
                        "required": [
                          "scheme",
                          "network",
                          "maxAmountRequired",
                          "resource",
                          "payTo",
                          "asset"
                        ],
                        "properties": {
                          "scheme": {
                            "type": "string",
                            "const": "exact"
                          },
                          "network": {
                            "type": "string",
                            "enum": [
                              "base",
                              "solana"
                            ]
                          },
                          "maxAmountRequired": {
                            "type": "string",
                            "description": "the quote, in USDC base units. This is the amount that settles."
                          },
                          "resource": {
                            "type": "string",
                            "format": "uri"
                          },
                          "description": {
                            "type": "string"
                          },
                          "mimeType": {
                            "type": "string"
                          },
                          "payTo": {
                            "type": "string",
                            "description": "the receiving address on this entry's network"
                          },
                          "maxTimeoutSeconds": {
                            "type": "integer"
                          },
                          "asset": {
                            "type": "string",
                            "description": "the USDC contract or mint on this entry's network"
                          },
                          "extra": {
                            "type": "object",
                            "description": "on Base, the token's EIP-712 domain; on Solana, {feePayer} — the account the facilitator will pay the transaction fee from"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "413": {
            "description": "the request body is larger than the 4 KB limit",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error"
                  ],
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "what went wrong, in prose"
                    }
                  },
                  "additionalProperties": true
                }
              }
            }
          },
          "503": {
            "description": "payments cannot be verified right now, so nothing was served and nothing was charged. Retry in a few minutes.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error"
                  ],
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "what went wrong, in prose"
                    }
                  },
                  "additionalProperties": true
                }
              }
            }
          }
        },
        "x-price": "$0.0025",
        "x-price-atomic-usdc": "2500",
        "x-payment-info": {
          "protocols": [
            {
              "x402": {}
            }
          ],
          "price": {
            "mode": "fixed",
            "currency": "USD",
            "amount": "0.0025"
          }
        }
      }
    }
  }
}
