{
    "openapi": "3.0.1",
    "info": {
        "title": "RSMAD Art Catalog API",
        "description": "Ryan Seslow's machine-readable art catalog and agent commerce endpoints. Structured for AI agent discovery, browsing, and programmatic artwork acquisition.",
        "version": "1.7.0",
        "contact": {
            "email": "ryan@ryanseslow.com",
            "url": "https://aremes-enterprises.com/contact/"
        },
        "license": {
            "name": "All rights reserved — Ryan Seslow / RSMAD",
            "url": "https://www.ryanseslow.com/licensing-acquisitions/"
        }
    },
    "servers": [
        {
            "url": "https://www.ryanseslow.com",
            "description": "ryanseslow.com production"
        }
    ],
    "paths": {
        "/search/search.php": {
            "get": {
                "operationId": "searchFullArchive",
                "summary": "Search Ryan Seslow's full archive (~22,000 works, 9 sources)",
                "description": "Keyword / full-text search across Ryan's entire 20-year body of work — blog, NET-ART teaching archive, graffanimation.com, aremes-enterprises.com, Instagram, Tumblr, Giphy, YouTube, and ~12,000 of his original tweets. Broader than the purchasable catalog. Search-only, no AI generation. Source-prioritized (Ryan's own sites first) then recency-ranked. Use this to DISCOVER works, then license or purchase a result via the catalog + x402 endpoints below.",
                "parameters": [
                    {
                        "name": "q",
                        "in": "query",
                        "required": true,
                        "description": "Search query (keywords; include a 4-digit year to prioritize that year)",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "limit",
                        "in": "query",
                        "description": "Max results (1-100)",
                        "schema": {
                            "type": "integer",
                            "default": 30
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Search results: { archive, query, count, results:[{title,year,url,source,text}], license }",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/catalog.json": {
            "get": {
                "operationId": "getFullCatalog",
                "summary": "Full art catalog",
                "description": "Returns all 10,000+ artworks as schema.org VisualArtwork / Product objects. Cached; use the REST API for filtered or paginated access.",
                "responses": {
                    "200": {
                        "description": "CollectionPage + Museum schema with hasPart array of VisualArtwork items",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/wp-json/rsmad/v1/catalog": {
            "get": {
                "operationId": "getCatalogPaginated",
                "summary": "Paginated / filtered catalog",
                "description": "Browse the catalog with optional pagination and source filtering.",
                "parameters": [
                    {
                        "name": "page",
                        "in": "query",
                        "description": "Page number (1-based)",
                        "schema": {
                            "type": "integer",
                            "default": 1
                        }
                    },
                    {
                        "name": "per_page",
                        "in": "query",
                        "description": "Items per page (0 = all)",
                        "schema": {
                            "type": "integer",
                            "default": 0
                        }
                    },
                    {
                        "name": "source",
                        "in": "query",
                        "description": "Filter by source type",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "post",
                                "page",
                                "woocommerce",
                                "media",
                                "nft"
                            ]
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Paginated catalog with pagination metadata",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/wp-json/rsmad/v1/purchase-intent": {
            "post": {
                "operationId": "createPurchaseIntent",
                "summary": "Create a purchase intent",
                "description": "Initiate a programmatic artwork purchase. Creates a pending WooCommerce order and returns a Stripe-powered paymentUrl. Only works for artworks that have an agentPurchase block in the catalog.",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "product_id",
                                    "buyer_email"
                                ],
                                "properties": {
                                    "product_id": {
                                        "type": "integer",
                                        "description": "WooCommerce product ID from catalog agentPurchase block"
                                    },
                                    "buyer_email": {
                                        "type": "string",
                                        "format": "email",
                                        "description": "Buyer email address for order confirmation"
                                    },
                                    "buyer_name": {
                                        "type": "string",
                                        "description": "Full name of buyer"
                                    },
                                    "buyer_org": {
                                        "type": "string",
                                        "description": "Buyer organization (optional)"
                                    },
                                    "agent_id": {
                                        "type": "string",
                                        "description": "Identifying string for the agent making the purchase"
                                    },
                                    "message": {
                                        "type": "string",
                                        "description": "Optional note to artist"
                                    },
                                    "callback_url": {
                                        "type": "string",
                                        "format": "uri",
                                        "description": "URL to POST when payment is confirmed. If provided, no polling needed — webhook fires automatically on order.processing or order.completed."
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Order created successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean"
                                        },
                                        "orderId": {
                                            "type": "integer"
                                        },
                                        "orderKey": {
                                            "type": "string"
                                        },
                                        "paymentUrl": {
                                            "type": "string",
                                            "format": "uri",
                                            "description": "Stripe checkout URL — direct principal here"
                                        },
                                        "statusUrl": {
                                            "type": "string",
                                            "format": "uri"
                                        },
                                        "amount": {
                                            "type": "number"
                                        },
                                        "currency": {
                                            "type": "string"
                                        },
                                        "status": {
                                            "type": "string",
                                            "example": "pending_payment"
                                        },
                                        "expiresAt": {
                                            "type": "string",
                                            "format": "date-time"
                                        },
                                        "callbackUrl": {
                                            "type": "string",
                                            "format": "uri",
                                            "nullable": true,
                                            "description": "Echo of callback_url if provided"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "Product not found or not purchasable"
                    },
                    "409": {
                        "description": "Product out of stock"
                    }
                }
            }
        },
        "/wp-json/rsmad/v1/x402/quote": {
            "get": {
                "operationId": "x402GetQuote",
                "summary": "Request a crypto payment quote (HTTP 402)",
                "description": "Returns an HTTP 402 response containing a payment quote for the specified product. Quote includes a quoteId (UUID), the USDC amount required, the destination wallet on Base, and step-by-step agentFlow instructions. Quote expires in 10 minutes. After sending USDC to the wallet, POST to /wp-json/rsmad/v1/x402/verify with the quote_id and tx_hash to complete the purchase.",
                "parameters": [
                    {
                        "name": "product_id",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        },
                        "description": "WooCommerce product ID from catalog x402Purchase block"
                    },
                    {
                        "name": "quantity",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "integer",
                            "default": 1
                        },
                        "description": "Quantity (default 1)"
                    }
                ],
                "responses": {
                    "402": {
                        "description": "Payment Required — standard x402 response. Body and X-Payment-Required header contain the payment details.",
                        "headers": {
                            "X-Payment-Required": {
                                "description": "JSON-encoded payment details (same as response body)",
                                "schema": {
                                    "type": "string"
                                }
                            },
                            "Access-Control-Expose-Headers": {
                                "description": "Exposes X-Payment-Required to browser/agent clients",
                                "schema": {
                                    "type": "string"
                                }
                            }
                        },
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "quoteId": {
                                            "type": "string",
                                            "format": "uuid",
                                            "description": "Unique quote identifier — include in verify request"
                                        },
                                        "network": {
                                            "type": "string",
                                            "example": "base",
                                            "description": "Blockchain network (always \"base\")"
                                        },
                                        "chainId": {
                                            "type": "integer",
                                            "example": 8453
                                        },
                                        "token": {
                                            "type": "string",
                                            "example": "USDC"
                                        },
                                        "tokenContract": {
                                            "type": "string",
                                            "example": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
                                            "description": "USDC contract address on Base"
                                        },
                                        "recipient": {
                                            "type": "string",
                                            "description": "Destination wallet (ryanseslow.eth)"
                                        },
                                        "amountUSDC": {
                                            "type": "number",
                                            "description": "Amount to send in USDC (human-readable)"
                                        },
                                        "amountRaw": {
                                            "type": "string",
                                            "description": "Amount in USDC atomic units (6 decimals)"
                                        },
                                        "quoteEndpoint": {
                                            "type": "string",
                                            "format": "uri"
                                        },
                                        "verifyEndpoint": {
                                            "type": "string",
                                            "format": "uri"
                                        },
                                        "resource": {
                                            "type": "string",
                                            "format": "uri",
                                            "description": "Same as verifyEndpoint"
                                        },
                                        "description": {
                                            "type": "string"
                                        },
                                        "expiresAt": {
                                            "type": "string",
                                            "format": "date-time"
                                        },
                                        "maxTimeoutSeconds": {
                                            "type": "integer",
                                            "example": 600
                                        },
                                        "agentFlow": {
                                            "type": "object",
                                            "description": "Step-by-step instructions for completing payment",
                                            "properties": {
                                                "step1": {
                                                    "type": "string"
                                                },
                                                "step2": {
                                                    "type": "string"
                                                },
                                                "step3": {
                                                    "type": "string"
                                                },
                                                "step4": {
                                                    "type": "string"
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Missing product_id"
                    },
                    "404": {
                        "description": "Product not found or not purchasable via x402"
                    }
                }
            }
        },
        "/wp-json/rsmad/v1/x402/verify": {
            "post": {
                "operationId": "x402VerifyPayment",
                "summary": "Verify an on-chain USDC payment and create order",
                "description": "After sending USDC on Base, POST the quote_id and tx_hash here. The server calls the Base mainnet RPC to verify the ERC-20 Transfer event, then burns the quote, locks the tx_hash against reuse (30 days), creates a WooCommerce order, and marks it as paid. Returns isPaid: true on success.",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "quote_id",
                                    "tx_hash",
                                    "buyer_email"
                                ],
                                "properties": {
                                    "quote_id": {
                                        "type": "string",
                                        "format": "uuid",
                                        "description": "quoteId from the /x402/quote response"
                                    },
                                    "tx_hash": {
                                        "type": "string",
                                        "description": "0x-prefixed Base transaction hash (66 hex chars)"
                                    },
                                    "buyer_email": {
                                        "type": "string",
                                        "format": "email",
                                        "description": "Email address for order confirmation"
                                    },
                                    "buyer_name": {
                                        "type": "string",
                                        "description": "Full name (optional)"
                                    },
                                    "agent_id": {
                                        "type": "string",
                                        "description": "Identifying string for the purchasing agent"
                                    },
                                    "callback_url": {
                                        "type": "string",
                                        "format": "uri",
                                        "description": "Webhook URL to POST when order status changes (optional — same fire-and-forget webhook as Stripe flow)"
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Payment verified and order created",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "isPaid": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "orderId": {
                                            "type": "integer"
                                        },
                                        "orderKey": {
                                            "type": "string"
                                        },
                                        "statusUrl": {
                                            "type": "string",
                                            "format": "uri"
                                        },
                                        "txHash": {
                                            "type": "string"
                                        },
                                        "network": {
                                            "type": "string",
                                            "example": "base"
                                        },
                                        "token": {
                                            "type": "string",
                                            "example": "USDC"
                                        },
                                        "amount": {
                                            "type": "number"
                                        },
                                        "currency": {
                                            "type": "string",
                                            "example": "USD"
                                        },
                                        "status": {
                                            "type": "string",
                                            "example": "processing"
                                        },
                                        "agentNote": {
                                            "type": "string"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "202": {
                        "description": "Transaction found but not yet confirmed on Base. Retry in 15 seconds."
                    },
                    "400": {
                        "description": "Invalid tx_hash format or missing required fields"
                    },
                    "402": {
                        "description": "Payment not verified — USDC Transfer event not found for given tx_hash, recipient, and amount"
                    },
                    "409": {
                        "description": "Transaction hash already used for a previous purchase"
                    },
                    "410": {
                        "description": "Quote expired or not found (10-min TTL)"
                    },
                    "500": {
                        "description": "Payment verified on-chain but WooCommerce order creation failed"
                    }
                }
            }
        },
        "/wp-json/rsmad/v1/purchase-status/{orderId}": {
            "get": {
                "operationId": "getPurchaseStatus",
                "summary": "Check purchase status",
                "description": "Poll this endpoint to confirm payment completion. Requires the order_key returned by purchase-intent.",
                "parameters": [
                    {
                        "name": "orderId",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        },
                        "description": "Order ID from purchase-intent response"
                    },
                    {
                        "name": "order_key",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Order key from purchase-intent response"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Order status",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "orderId": {
                                            "type": "integer"
                                        },
                                        "status": {
                                            "type": "string",
                                            "example": "processing"
                                        },
                                        "isPaid": {
                                            "type": "boolean"
                                        },
                                        "isComplete": {
                                            "type": "boolean",
                                            "description": "true when status is processing or completed"
                                        },
                                        "amount": {
                                            "type": "number"
                                        },
                                        "currency": {
                                            "type": "string"
                                        },
                                        "agentInitiated": {
                                            "type": "boolean"
                                        },
                                        "agentId": {
                                            "type": "string"
                                        },
                                        "paidAt": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "Invalid order key"
                    },
                    "404": {
                        "description": "Order not found"
                    }
                }
            }
        },
        "/wp-json/rsmad/v1/museum/passes": {
            "get": {
                "summary": "List museum pass tiers",
                "description": "Prices, product ids and x402 quote urls for every pass tier. Public, no pass required.",
                "operationId": "listMuseumPasses",
                "responses": {
                    "200": {
                        "description": "An OfferCatalog of pass tiers."
                    }
                }
            }
        },
        "/wp-json/rsmad/v1/pass/{orderId}": {
            "get": {
                "summary": "Collect the pass for a paid order",
                "description": "Returns the pass token once the order is paid. Requires the order key issued at purchase.",
                "operationId": "collectMuseumPass",
                "parameters": [
                    {
                        "name": "orderId",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "order_key",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "isPaid true with the pass token, tier, scope and expiry. isPaid false while awaiting payment."
                    },
                    "404": {
                        "description": "No such order."
                    }
                }
            }
        },
        "/wp-json/rsmad/v1/museum": {
            "get": {
                "summary": "Enter the museum",
                "description": "Three rooms and forty works as structured data. Present the pass as Authorization: Bearer <token>. Entry only, no license to reproduce or train.",
                "operationId": "enterMuseum",
                "parameters": [
                    {
                        "name": "Authorization",
                        "in": "header",
                        "required": false,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Bearer <pass token>"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "The museum: rooms in order, their contents, and the programme."
                    },
                    "402": {
                        "description": "No valid pass. The body carries passesUrl so an agent can buy one and retry."
                    },
                    "429": {
                        "description": "Too many invalid passes from this address."
                    }
                }
            }
        },
        "/wp-json/rsmad/v1/x402/v2/pass/{tier}": {
            "get": {
                "summary": "Buy a museum pass (x402 v2)",
                "description": "Standard x402 v2 purchase. Paid response carries the pass token; enter with GET /wp-json/rsmad/v1/museum and Authorization: Bearer. Entry only.",
                "operationId": "buyMuseumPassX402",
                "parameters": [
                    {
                        "name": "tier",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "enum": [
                                "day",
                                "seasonal",
                                "institutional"
                            ]
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Paid. orderId, pass, tier, expiresAt, museumEndpoint. PAYMENT-RESPONSE header."
                    },
                    "402": {
                        "description": "Payment required. PAYMENT-REQUIRED header carries base64 x402 v2 PaymentRequired (USDC on Base, eip155:8453). Retry with PAYMENT-SIGNATURE."
                    }
                }
            }
        },
        "/wp-json/rsmad/v1/x402/v2/license/{tier}": {
            "get": {
                "summary": "License named works (x402 v2)",
                "description": "Standard license for 1 to 25 of the 379 hand-picked works. Work ids from https://www.ryanseslow.com/license/archive-manifest.json. Files and the written license are delivered by e-mail. Terms: https://www.ryanseslow.com/license/terms.html",
                "operationId": "licenseWorksX402",
                "parameters": [
                    {
                        "name": "tier",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "enum": [
                                "single",
                                "bundle5",
                                "bundle25"
                            ]
                        }
                    },
                    {
                        "name": "works",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Comma separated work ids, 1 to 1/5/25 by tier"
                    },
                    {
                        "name": "email",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "format": "email"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Paid. orderId and a license receipt: tier, works, grant, excludes, delivery, terms. PAYMENT-RESPONSE header."
                    },
                    "400": {
                        "description": "Invalid selection or e-mail. Nothing quoted, nothing charged."
                    },
                    "402": {
                        "description": "Payment required. PAYMENT-REQUIRED header carries base64 x402 v2 PaymentRequired (USDC on Base, eip155:8453). Retry with PAYMENT-SIGNATURE."
                    }
                }
            }
        },
        "/wp-json/rsmad/v1/x402/v2/product/{id}": {
            "get": {
                "summary": "Buy any catalog product (x402 v2)",
                "operationId": "buyProductX402",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Paid. orderId and any downloads."
                    },
                    "402": {
                        "description": "Payment required. PAYMENT-REQUIRED header carries base64 x402 v2 PaymentRequired (USDC on Base, eip155:8453). Retry with PAYMENT-SIGNATURE."
                    }
                }
            }
        }
    }
}