{"openapi":"3.1.0","info":{"title":"Visokio services for AI agents","version":"agents-v0.5.0-rc.7","x-guidance":"Visokio services for AI agents. Pay per use in USDC (x402); no account, no API key. Test site: payments here are test USDC on Base Sepolia, not real money. To pay: POST the buy call, read the 402's PAYMENT-REQUIRED header, send the call again with the signed payment in PAYMENT-SIGNATURE. A 503 means the service is down: nothing sold or charged; retry after Retry-After. Every error reply is application/problem+json (RFC 9457) with a code in error: do what next says. Read the receiptUrl as JSON: GET it without the part from # on, with Authorization: PassView <the text after #k=>. Insight Explorer: Send a CSV and a question; get the answer, and a report a person can open to see how it was reached. Prices: One question, 0.50 USDC, lasts 24 hours (POST https://agents.dev.visokio.com/buy/insight-explorer/question). 1) POST https://agents.dev.visokio.com/buy/insight-explorer/question with {} and pay the 402: 0.50 USDC non-refundable (the 402 names the network). You get pass, expiresAt, serviceUrl (https://omniscope-service.dev.visokio.com/_service_/v1/insight-explorer/) and receiptUrl. 2) POST the service URL with header Authorization: Bearer <pass> and the body as multipart/form-data (RFC 7578): one part named file per CSV file (with a filename ending in .csv, Content-Type text/csv), and one part named question. For example: curl -X POST \"https://omniscope-service.dev.visokio.com/_service_/v1/insight-explorer/\" -H \"Authorization: Bearer <pass>\" -F \"file=@sales.csv;type=text/csv\" -F \"question=Which region sells most?\". You get 202 and a status URL. 3) Poll the status URL with the same pass until ready. 4) Use the answer; give your user reportUrl, username and password to check it, and receiptUrl, the payment confirmation. Everything is kept 24 hours."},"externalDocs":{"description":"The same story for people","url":"https://agents.dev.visokio.com/"},"servers":[{"url":"https://agents.dev.visokio.com"}],"paths":{"/buy/insight-explorer/question":{"post":{"operationId":"buy-insight-explorer-question","summary":"Buy a pass: Insight Explorer, One question","description":"Send a CSV and a question; get the answer, and a report a person can open to see how it was reached. 0.50 USDC, non-refundable. The pass lasts 24 hours. The reply names the service address, https://omniscope-service.dev.visokio.com/_service_/v1/insight-explorer/, where the agent sends its work with the pass as a bearer token; the service's own calls are described at https://omniscope-service.dev.visokio.com/_service_/v1/insight-explorer/openapi.json.","x-payment-info":{"price":{"mode":"fixed","currency":"USD","amount":"0.50"},"protocols":[{"x402":{}}]},"parameters":[{"name":"PAYMENT-SIGNATURE","in":"header","required":false,"description":"The signed x402 payment (base64 PaymentPayload), sent on the second call after the 402","schema":{"type":"string"}},{"name":"Pass-Claim","in":"header","required":false,"description":"The claim code from this payment's 402 settlement_pending reply (its claim), sent with the same PAYMENT-SIGNATURE when sending the payment again; without it a payment already on chain gets 409","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"description":"Paid: pass, expiresAt, serviceUrl; the settlement in the PAYMENT-RESPONSE header","headers":{"PAYMENT-RESPONSE":{"schema":{"type":"string"}}}},"400":{"description":"PAYMENT-SIGNATURE is not a valid x402 payment payload; nothing charged","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Payment required: the price and where to pay in the PAYMENT-REQUIRED header; send the call again with the signed payment in PAYMENT-SIGNATURE. Also a refused payment, or one not finished yet (payment_in_progress, settlement_pending: send it again after Retry-After; a settlement_pending reply to the request that paid carries claim, to send back as Pass-Claim), as an Error","headers":{"PAYMENT-REQUIRED":{"schema":{"type":"string"}},"PAYMENT-RESPONSE":{"schema":{"type":"string"}},"Retry-After":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentRequired"}},"application/problem+json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Test money from a wallet that is not listed (payer_not_allowed); nothing charged","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"405":{"description":"Any method but POST (method_not_allowed): send POST to this address instead","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Allow":{"schema":{"type":"string","const":"POST"}}}},"409":{"description":"This payment has already bought a pass (payment_already_used), sent again without its Pass-Claim: no pass, nothing charged","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many unpaid or refused calls (too_many_requests); try again after Retry-After","headers":{"Retry-After":{"schema":{"type":"integer"}}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"An error on the shop's side; send the same call again after Retry-After","headers":{"Retry-After":{"schema":{"type":"integer"}}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"Buying is not open on this shop yet (not_on_sale); do not pay","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"The service is not answering: no pass sold, nothing charged; try again after Retry-After","headers":{"Retry-After":{"schema":{"type":"integer"}}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[]}},"/passes/{jti}":{"get":{"operationId":"receipt","summary":"The receipt for a pass: a page for a person, or JSON with the view key","description":"receiptUrl, from the 200 of a buy call, is this address followed by #k=<key>. A browser opens it as a page. Send GET to the receipt URL without the part from # on, with the header Authorization: PassView <key>, where <key> is the text after #k= in the receipt URL; the reply is the receipt as JSON. A browser opening the receipt URL as the shop gave it does this itself. The receipt never carries the pass.","parameters":[{"name":"jti","in":"path","required":true,"description":"The pass ID (passId in the buy reply)","schema":{"type":"string"}},{"name":"Authorization","in":"header","required":false,"description":"PassView <key>, the key being the text after #k= in receiptUrl; without it, the page","schema":{"type":"string"}}],"responses":{"200":{"description":"The receipt as JSON with the view key; the page (HTML) without it","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Receipt"}},"text/html":{"schema":{"type":"string"}}}},"404":{"description":"No receipt for this pass ID and key (not_found): the same reply for every miss","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[]}}},"components":{"schemas":{"Error":{"type":"object","description":"Every error reply from the shop: RFC 9457 Problem Details, sent as application/problem+json, with the extension members error (a machine code) and next (what to do now)","required":["type","title","status","detail","error","next"],"properties":{"type":{"type":"string","format":"uri-reference","const":"about:blank"},"title":{"type":"string","description":"The HTTP status phrase, e.g. Service Unavailable"},"status":{"type":"integer","description":"The reply's HTTP status"},"detail":{"type":"string","description":"What went wrong"},"error":{"type":"string","description":"A machine code that never changes, e.g. service_unavailable"},"next":{"type":"string","description":"What to do next"}}},"Receipt":{"type":"object","description":"What was paid for a pass, from the shop's ledger; never the pass itself","required":["passId","paymentId","service","offer","quantity","amount","currency","free","provider","paidAt","issuedAt","expiresAt"],"properties":{"passId":{"type":"string"},"paymentId":{"type":"string"},"service":{"type":"string"},"offer":{"type":"string"},"quantity":{"type":"integer"},"amount":{"type":"string"},"currency":{"type":"string"},"free":{"type":"boolean"},"provider":{"type":"string"},"paidAt":{"type":"string","format":"date-time"},"issuedAt":{"type":"string","format":"date-time"},"expiresAt":{"type":"string","format":"date-time","description":"When the pass stops working"},"network":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"mainnet":{"type":"boolean"}}},"transaction":{"type":["string","null"],"description":"The payment's transaction hash"},"transactionUrl":{"type":"string","description":"The transaction on the network's block explorer"},"payer":{"type":"string"},"payerUrl":{"type":"string"}}},"PaymentRequired":{"type":"object","description":"The body of the 402 asking for payment (the x402 protocol itself is in the headers)","required":["serviceName","next"],"properties":{"serviceName":{"type":"string"},"next":{"type":"string","description":"What to do next"}}}}}}