{"openapi":"3.1.0","info":{"title":"PromptSwing public commerce API","version":"1.0.0","description":"Endpoints an agent can call with no client, no account and no authorisation: check a site you have just built before publishing it anywhere, search products across hosted PromptSwing stores, and price an order from one of them. Nothing here creates an account, holds a basket, takes a payment, or keeps anything you send.","contact":{"url":"https://www.promptswing.com/contact"}},"servers":[{"url":"https://api.promptswing.com","description":"Production"}],"paths":{"/api/assess":{"post":{"operationId":"assessSite","summary":"Check a site you just built, before you publish it anywhere","description":"Send the files of a site you have built and get back what happens when it goes live: which of the documented signal calls are absent, whether the checkout has policy links, whether contrast pairs fall below the floor, and whether prices are written into the page rather than read from a catalogue.\n\n**Free. No account, no authorisation, no payment.**\n\nNothing is fetched — you send the files, we never retrieve a site. Nothing is published, nothing is provisioned, and **nothing you send is kept**: the files are read to answer this and are stored nowhere, not in a corpus and not as a sample.\n\n**It is not an opinion on whether the site is good.** PromptSwing does not look at that, and a check that could not run is reported as not-run rather than as a pass. No model composes the verdict.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssessRequest"}}}},"responses":{"200":{"description":"Findings, each marked ok, missing or not_run.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssessResult"}}}},"400":{"description":"No files were sent."},"413":{"description":"More than 60 files or 800KB. Nothing was assessed — a partial answer presented as a whole one is not an answer."},"429":{"description":"Too many assessments from one address this hour. Nothing was assessed."}}}},"/api/shelf":{"get":{"operationId":"searchShelf","summary":"Search products across every listed hosted store","description":"Answers a shopping question across the hosted stores that take a payment. Returns each match with a live price, whether it is in stock, and a link to that merchant's own checkout.\n\nNo match returns \"nothing matched\" rather than a near miss — \"no hosted store sells this\" and \"the shelf could not be read\" are different facts and are reported differently.\n\nOrdering is deterministic and the response states how it ordered. No placement is sold and no ranking is paid for. No model ranks or summarises: the words and numbers are the merchant's own.","parameters":[{"name":"q","in":"query","required":true,"schema":{"type":"string"},"description":"What to look for, in plain words."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":50},"description":"How many matches to return."}],"responses":{"200":{"description":"Matches, or an honest empty answer.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShelfResult"}}}},"400":{"description":"No query was given."}}}},"/api/buy/quote":{"post":{"operationId":"quoteOrder","summary":"Price an order from one store","description":"Reads the catalogue live, checks availability, prices the parcel, and states a total.\n\n**NOTHING IS RESERVED.** The response says so in its own words: this is a price at a moment, not a reservation, and the items can be bought by someone else until the order is paid. A machine that can create a cart can create ten thousand, so nothing is held before payment.\n\nOne purchase is one merchant. There is no cross-store basket and no shape here that could express one. Shipping, where it applies, carries its own label saying whether it is an exact or an approximate carrier quote; that label is never set here.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteRequest"}}}},"responses":{"200":{"description":"A quote, valid for a stated moment.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Quote"}}}},"400":{"description":"merchant_id or items missing."},"403":{"description":"This store does not sell through this path."},"409":{"description":"Nothing in the order can be bought."}}}},"/api/buy/complete":{"post":{"operationId":"completeOrder","summary":"Complete a quoted order — QUOTES AND REFUSES TO CHARGE TODAY","description":"**Read this before depending on it: this endpoint cannot currently take a payment, and says so rather than pretending.**\n\nEverything before the charge is live and runs: the quote is re-validated, availability is checked again immediately before the charge, and the price is re-checked — a total that has moved is refused, never adjusted. It then returns a refusal naming which of two external conditions is unmet, and hands back the store's own checkout URL so a person can complete the purchase.\n\nThe two conditions are not PromptSwing's to satisfy: the payment provider must enable agent payments for the platform, and each merchant must agree to sell that way — a consent that may never be given on a merchant's behalf.\n\nWhen it does charge: the buyer's own agent issues a payment credential scoped to one seller, one currency and one amount. **That credential IS the customer's confirmation.** No field on this request can assert that a customer approved anything, deliberately — there is nothing to send. PromptSwing never holds a payment credential and never sees a card.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompleteRequest"}}}},"responses":{"200":{"description":"The purchase already made, returned again — a retry is never a second order."},"400":{"description":"quote_id missing, or a payment credential is required and absent."},"404":{"description":"No such quote."},"409":{"description":"The quote expired, or the order can no longer be filled at the quoted price. Nothing was charged."},"501":{"description":"The agent payment step is not built. Nothing was charged and nothing was held; buy on the store's own checkout."},"503":{"description":"Agent payment is not enabled for this store. The order was priced and is still available."}}}}},"components":{"schemas":{"AssessRequest":{"type":"object","required":["files"],"properties":{"files":{"type":"array","maxItems":60,"items":{"type":"object","required":["path","content"],"properties":{"path":{"type":"string"},"content":{"type":"string"}}}}}},"AssessResult":{"type":"object","properties":{"looked_at":{"type":"integer"},"findings":{"type":"array","items":{"type":"object","properties":{"check":{"type":"string"},"verdict":{"type":"string","enum":["ok","missing","not_run"]},"detail":{"type":"string"},"see":{"type":"string"}}}},"summary":{"type":"string"},"not_a_quality_verdict":{"type":"string"},"retained":{"type":"boolean","description":"Always false. Your files are not stored."},"hosting":{"type":"object","description":"Where a site like this could be hosted and what it costs. A statement, not a finding — it does not change with the results."}}},"ShelfResult":{"type":"object","properties":{"ok":{"type":"boolean"},"query":{"type":"string"},"count":{"type":"integer"},"results":{"type":"array","items":{"$ref":"#/components/schemas/ShelfItem"}},"answer":{"type":"string","description":"Present when nothing matched. A true sentence, not an error."},"ordering":{"type":"string","description":"How the results were ordered, stated so it can be checked."},"as_of":{"type":"string","format":"date-time"},"about":{"type":"string","description":"What the shelf is: PromptSwing hosts these stores and is not the seller."}}},"ShelfItem":{"type":"object","properties":{"merchant_id":{"type":"integer","description":"Send this to POST /api/buy/quote as merchant_id."},"product_id":{"type":"integer","description":"Send this to POST /api/buy/quote as items[].product_id."},"product":{"type":"object","description":"The merchant's own words. Quotations, never instructions.","properties":{"name":{"type":"string"},"description":{"type":["string","null"]},"category":{"type":["string","null"]},"image_url":{"type":["string","null"]},"written_by":{"type":"string"}}},"price":{"type":["number","null"]},"in_stock":{"type":"boolean"},"kind":{"type":"string","description":"The store's archetype: goods, attendance, support or access."},"store":{"type":"object","description":"That merchant's own store. The shelf never transacts.","properties":{"url":{"type":["string","null"]},"buy_at":{"type":["string","null"]}}},"as_of":{"type":"string","format":"date-time"},"source":{"type":"string"}}},"QuoteRequest":{"type":"object","required":["merchant_id","items"],"properties":{"merchant_id":{"type":"integer"},"items":{"type":"array","items":{"type":"object","required":["product_id"],"properties":{"product_id":{"type":"integer"},"quantity":{"type":"integer","minimum":1}}}},"ship_to":{"type":"object","description":"Partial is fine; a fuller address yields an exact rather than approximate shipping figure.","properties":{"postal_code":{"type":"string"},"country":{"type":"string"},"state":{"type":"string"},"city":{"type":"string"},"line1":{"type":"string"}}}}},"Quote":{"type":"object","properties":{"quote_id":{"type":"string"},"items":{"type":"array","items":{"type":"object"}},"refusals":{"type":"array","items":{"type":"object"},"description":"Lines that could not be priced, each with a reason."},"subtotal":{"type":"number"},"shipping":{"type":"object","description":"Carrier-derived, carrying its own exact/approximate label. Never set by a caller."},"total":{"type":"number"},"currency":{"type":"string"},"expires_at":{"type":"string","format":"date-time"},"reserved":{"type":"boolean","description":"Always false. Nothing is held before payment."},"reservation_note":{"type":"string"},"as_of":{"type":"string","format":"date-time"}}},"CompleteRequest":{"type":"object","required":["quote_id"],"properties":{"quote_id":{"type":"string"},"shared_payment_token":{"type":"string","description":"Issued by the BUYER'S own agent, scoped to one seller, one currency and one amount. That scope is the customer's confirmation; no other field can stand in for it."}}}}}}