{"openapi":"3.1.0","info":{"title":"BotMarket","description":"A data marketplace for bots, AI agents, and automated research workflows. Datasets cover international trade (BACI, US Customs), US demographics (ACS), and international debt statistics. Supports per-query API access (USD balance). Bulk Parquet downloads coming soon.","version":"1.0.0"},"paths":{"/api/datasets/{slug}/sample":{"get":{"tags":["datasets"],"summary":"Get Sample","description":"Free sample of the dataset (up to 100 rows). No authentication required.\nServed from sample.csv in DATA_OUT_DIR when present, else from full.parquet LIMIT.","operationId":"get_sample_api_datasets__slug__sample_get","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/datasets/{slug}/query":{"get":{"tags":["datasets"],"summary":"Query Dataset","description":"Query a dataset with optional column filters. Authenticate with a BotMarket API key (prefix bot_market_ak_)\nwith USD balance, or an OEC API token (32 lowercase hex characters) for eligible subscribers.\n\nBotMarket and OEC (after sync to a synthetic api_keys row): each query deducts the dataset's per_query_usd from that key's balance.\n\nFilter columns are dataset-specific and listed in /api/datasets/{slug} as query_filters.\nMultiple values for a filter use SQL IN: pass the same param repeatedly\n(?geo=ES&geo=FR) or comma-separated (?geo=ES,FR).\n\nExample:\n    GET /api/datasets/ilostat-key-metrics/query?ref_area=US&year=2023&limit=50\n    GET /api/datasets/ilostat-key-metrics/query?ref_area=US&ref_area=CA&year=2023\n    Authorization: Bearer bot_market_ak_<your_key>","operationId":"query_dataset_api_datasets__slug__query_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":1,"description":"Rows to return","default":1000,"title":"Limit"},"description":"Rows to return"},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Rows to skip","default":0,"title":"Offset"},"description":"Rows to skip"},{"name":"format","in":"query","required":false,"schema":{"type":"string","description":"Response format: json or csv","default":"json","title":"Format"},"description":"Response format: json or csv"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/catalog":{"get":{"tags":["catalog"],"summary":"List or search catalog","description":"**GET /api/catalog** — List all datasets (paginated).\n\n**GET /api/catalog?q=<terms>** — Search by free text. Each term in `q` is matched against name, description, slug, domain, scope, and tags. Matching is fuzzy (typos allowed via pg_trgm). All terms must match (AND). Results are ranked by relevance (name/slug > description > rest).\n\n**Without `q`:** Returns datasets ordered by domain, scope, geo, slug. Optional filters: `domain`, `scope`, `geo`, `tag`.\n\n**With `q`:** Returns datasets matching the search terms. Optional filters: `domain`, `scope`, `tag` (same semantics). `geo` is not applied when searching.\n\n**Response (both):** `{ \"total\", \"limit\", \"offset\", \"domains\", \"scopes\", \"datasets\" }`. Each dataset is a summary; use the detail URL for full schema, pricing, query_filters.","operationId":"get_catalog_api_catalog_get","parameters":[{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Optional search terms (space-separated). When provided, filters datasets by free text over name, description, slug, domain, scope, tags (fuzzy/typo-tolerant). When omitted, returns all datasets.","title":"Q"},"description":"Optional search terms (space-separated). When provided, filters datasets by free text over name, description, slug, domain, scope, tags (fuzzy/typo-tolerant). When omitted, returns all datasets."},{"name":"domain","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by domain (e.g. economics)","title":"Domain"},"description":"Filter by domain (e.g. economics)"},{"name":"scope","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by scope (e.g. global)","title":"Scope"},"description":"Filter by scope (e.g. global)"},{"name":"geo","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by geo (ISO-3 for country scope, or region slug); only when not using q","title":"Geo"},"description":"Filter by geo (ISO-3 for country scope, or region slug); only when not using q"},{"name":"tag","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by tag (exact)","title":"Tag"},"description":"Filter by tag (exact)"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"Page size","default":24,"title":"Limit"},"description":"Page size"},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Number of datasets to skip","default":0,"title":"Offset"},"description":"Number of datasets to skip"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/catalog/summary":{"get":{"tags":["catalog"],"summary":"Catalog overview grouped by domain","description":"Returns a preview of the catalog grouped by domain — useful for bots and humans\nwho want a quick overview of what data is available before drilling into a\nspecific domain.\n\nEach domain entry includes:\n- **`domain`** — domain slug (e.g. `trade`, `economics`)\n- **`total`** — total number of datasets in this domain\n- **`preview`** — number of datasets returned in this response (up to 12)\n- **`more_url`** — URL to fetch **all** datasets in this domain\n  (`GET /api/catalog?domain=<domain>`)\n- **`datasets`** — the first `preview` datasets, same schema as\n  `GET /api/catalog`\n\nTo retrieve all datasets for a domain, follow `more_url`:\n```\nGET /api/catalog?domain=trade&limit=100&offset=0\n```\n\nTo list all domains with full pagination, use `GET /api/catalog` directly.","operationId":"get_catalog_summary_api_catalog_summary_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/datasets/{slug}":{"get":{"tags":["datasets"],"summary":"Get Dataset","description":"Full dataset detail including schema, pricing, and source information.","operationId":"get_dataset_api_datasets__slug__get","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/datasets/{slug}/members/{col}":{"get":{"tags":["datasets"],"summary":"Get Members","description":"Return distinct values (members) for a filter column with dataset context.","operationId":"get_members_api_datasets__slug__members__col__get","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}},{"name":"col","in":"path","required":true,"schema":{"type":"string","title":"Col"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/checkout/stripe":{"post":{"tags":["payments"],"summary":"Checkout Stripe","description":"Initiate a Stripe Checkout session (human / browser flow).\n\nRequires an active session cookie (sign in via /api/magic-link first).\nThe buyer email is taken from the session — never from the request body.\nThe Stripe payment URL is sent to the verified inbox; it is NOT returned\nin the API response (eliminates phishing via response interception).\n\nBody:\n  - amount_usd (required): USD to add to balance\n  - api_key (optional): existing key to top up instead of creating a new one","operationId":"checkout_stripe_api_checkout_stripe_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StripeCheckoutRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/checkout/x402":{"post":{"tags":["payments"],"summary":"Checkout X402","description":"Initiate an x402 balance top-up (agent flow, no session required).\n\nReturns x402 payment instructions. The agent should:\n  1. GET the payment_url → receive 402 with PAYMENT-REQUIRED header\n  2. Create and sign payment with an x402 client\n  3. Retry GET with PAYMENT-SIGNATURE header → receive API key\n\nBody:\n  - buyer_email (required): email for order lookup\n  - amount_usd (optional, default 10): USD to add\n  - api_key (optional): top up an existing key instead of creating a new one","operationId":"checkout_x402_api_checkout_x402_post","parameters":[{"name":"Authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/X402CheckoutRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/checkout/ap2":{"post":{"tags":["payments"],"summary":"Checkout Ap2","description":"AP2 payments use a dedicated intent/purchase flow.","operationId":"checkout_ap2_api_checkout_ap2_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/orders/{order_id}":{"get":{"tags":["payments"],"summary":"Get Order","description":"Poll this endpoint to check payment status.\nRequires ?buyer_email= matching the email used at checkout.\nWhen status='paid':\n  - bulk_download: includes download_url\n  - add_balance: includes api_key (shown once, then cleared)\n\nWhen session_id is present (Stripe redirect), renders an HTML receipt page.","operationId":"get_order_api_orders__order_id__get","parameters":[{"name":"order_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Order Id"}},{"name":"session_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Session Id"}},{"name":"buyer_email","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Buyer Email"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/x402/balance":{"get":{"tags":["x402"],"summary":"X402 Balance","description":"x402-protected balance top-up (no dataset). Agent flow:\n\n1. GET /api/x402/balance?amount_usd=N with X-Buyer-Email (or ?buyer_email=) → 402\n2. Agent creates payment, signs with wallet\n3. Retry GET with PAYMENT-SIGNATURE → 200 + API key\n\nOptional: pass Authorization: Bearer <key> or X-BotMarket-Api-Key to add to existing key.","operationId":"x402_balance_api_x402_balance_get","parameters":[{"name":"amount_usd","in":"query","required":false,"schema":{"type":"number","minimum":0.99,"description":"USD to add to balance","default":10,"title":"Amount Usd"},"description":"USD to add to balance"},{"name":"buyer_email","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Buyer Email"}},{"name":"buyer_name","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Buyer Name"}},{"name":"buyer_company","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Buyer Company"}},{"name":"buyer_role","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Buyer Role"}},{"name":"agent_name","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Agent Name"}},{"name":"agent_goal","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Agent Goal"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/x402/info":{"get":{"tags":["x402"],"summary":"X402 Info","description":"Discovery endpoint: x402 support and configuration (for agents).","operationId":"x402_info_api_x402_info_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/ap2/agent-card":{"get":{"tags":["ap2"],"summary":"Agent Card","description":"AP2 Merchant Agent Card — capabilities and supported payment methods.\n\nShopping Agents use this to discover what this merchant supports.\nFollows the agent card format from the AP2 spec samples.","operationId":"agent_card_api_ap2_agent_card_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/ap2/intent":{"post":{"tags":["ap2"],"summary":"Process Intent","description":"Accept an IntentMandate from a Shopping Agent, return a signed CartMandate.\n\nThe Shopping Agent describes what the user wants. BotMarket validates the\nintent, resolves pricing, and returns a CartMandate with a JWT\nmerchant_authorization binding the cart contents.\n\nThe Shopping Agent then presents this cart to the user for approval.","operationId":"process_intent_api_ap2_intent_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IntentMandate"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/ap2/purchase":{"post":{"tags":["ap2"],"summary":"Execute Purchase","description":"Execute a purchase with a signed CartMandate and PaymentMandate.\n\nVerification chain:\n  1. Verify merchant_authorization JWT on CartMandate\n  2. Check cart_expiry\n  3. Validate user_authorization on PaymentMandate (dev mode: permissive)\n  4. Check payment response tokenization\n  5. Create order and return PaymentReceipt\n\nTop-up: pass api_key in intent_mandate.api_key (preferred) or\nAuthorization: Bearer <key> header. If neither is provided, a new key is created.\n\nReturns an AP2 PaymentReceipt with BotMarket extensions\n(download_url, api_key, etc.).","operationId":"execute_purchase_api_ap2_purchase_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PurchaseRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/ap2/jwks":{"get":{"tags":["ap2"],"summary":"Ap2 Jwks","description":"JWKS endpoint — public key for verifying merchant_authorization JWTs.\n\nShopping Agents can fetch this to cryptographically verify CartMandate\nmerchant_authorization JWTs without trusting BotMarket's server.\nOnly available when RS256 is configured (AP2_PUBLIC_KEY_PEM is set).","operationId":"ap2_jwks_api_ap2_jwks_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/ap2/info":{"get":{"tags":["ap2"],"summary":"Ap2 Info","description":"AP2 protocol discovery — what this merchant supports.","operationId":"ap2_info_api_ap2_info_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/account/lookup":{"post":{"tags":["account"],"summary":"Lookup By Email","description":"Look up all orders and API keys for an email address.\nValidates format and existence (at least one order).\nSends a summary email to that address via Mailgun.\n\nFor agents: POST with JSON body `{\"email\": \"user@example.com\"}`.\nFor humans: POST form with `email` field (from web page).","operationId":"lookup_by_email_api_account_lookup_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/account/balance":{"get":{"tags":["account"],"summary":"Get Balance","description":"Return the current balance for the authenticated API key.\nDoes NOT deduct funds — safe to call before paying or when balance is zero.\n\nAuthorization: Bearer bot_market_ak_<key>  or  Bearer <OEC API token> (32 lowercase hex)\nQuery param: buyer_email=<email>  (required — must match the email used at purchase time,\nor for OEC tokens the email on the linked OEC account)\n\nReturns: { api_key_prefix, balance_usd, label, auth_source }","operationId":"get_balance_api_account_balance_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/promo/claim":{"get":{"tags":["payments"],"summary":"Claim free welcome credit (GET)","description":"GET alternative to POST /api/promo/claim — for agents that cannot send a request body.\n\nPass all fields as query parameters:\n```\nGET /api/promo/claim?buyer_email=you@example.com\n```\n\nSame rules and response as the POST version.","operationId":"claim_promo_get_api_promo_claim_get","parameters":[{"name":"buyer_email","in":"query","required":true,"schema":{"type":"string","description":"Your email address — receipt and key delivered here.","title":"Buyer Email"},"description":"Your email address — receipt and key delivered here."},{"name":"buyer_name","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Buyer Name"}},{"name":"buyer_company","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Buyer Company"}},{"name":"buyer_role","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Buyer Role"}},{"name":"agent_name","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Agent Name"}},{"name":"agent_goal","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Agent Goal"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["payments"],"summary":"Claim free welcome credit (POST)","description":"Claim the free welcome credit: receive a free API key preloaded with USD balance.\n\nRules:\n- One promo per email address — subsequent claims from the same email are rejected.\n\nAfter your promo balance runs out, top it up with any other payment method\n(stripe, x402, ap2) by passing your API key as the api_key field or\nAuthorization: Bearer header in the checkout request.\n\n**Tip for agents that cannot send a request body:** use the GET version instead —\n`GET /api/promo/claim?buyer_email=you@example.com`","operationId":"claim_promo_api_promo_claim_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PromoClaimRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/transfers":{"post":{"tags":["account"],"summary":"Agent Transfer","description":"Transfer balance between two API keys owned by the same email.\n\nSource key is identified by the Authorization: Bearer header.\nDestination key: provide to_key_id (UUID) or to_api_key (raw key).","operationId":"agent_transfer_api_transfers_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransferRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/survey/{token}":{"get":{"tags":["survey"],"summary":"Survey Form","operationId":"survey_form_survey__token__get","parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string","title":"Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["survey"],"summary":"Survey Submit","operationId":"survey_submit_survey__token__post","parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string","title":"Token"}}],"requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_survey_submit_survey__token__post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"AP2TransactionModality":{"type":"string","enum":["HUMAN_PRESENT","HUMAN_NOT_PRESENT"],"title":"AP2TransactionModality"},"Body_survey_submit_survey__token__post":{"properties":{"use_case":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Use Case"},"datasets_useful":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Datasets Useful"},"got_value":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Got Value"},"would_pay_for":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Would Pay For"},"feedback":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Feedback"},"cf_turnstile_response":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cf Turnstile Response"}},"type":"object","title":"Body_survey_submit_survey__token__post"},"CartContents":{"properties":{"id":{"type":"string","title":"Id","description":"Unique cart identifier."},"user_cart_confirmation_required":{"type":"boolean","title":"User Cart Confirmation Required","description":"If true, user must confirm the cart before purchase.","default":true},"payment_request":{"$ref":"#/components/schemas/PaymentRequest"},"cart_expiry":{"type":"string","title":"Cart Expiry","description":"When this cart expires, ISO 8601 format."},"merchant_name":{"type":"string","title":"Merchant Name","description":"Merchant name.","default":"BotMarket"},"buyer_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Buyer Email","description":"BotMarket: buyer email for order lookup (required)."}},"type":"object","required":["id","payment_request","cart_expiry"],"title":"CartContents","description":"Cart contents, signed by the merchant to create a CartMandate."},"CartMandate":{"properties":{"contents":{"$ref":"#/components/schemas/CartContents"},"merchant_authorization":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Merchant Authorization","description":"JWT signing the cart contents. Verifiable by the Shopping Agent."}},"type":"object","required":["contents"],"title":"CartMandate","description":"Merchant-signed cart guaranteeing items and price.\n\nmerchant_authorization is a JWT (HS256 in dev, RS256/ES256 in production)\ncontaining a cart_hash claim that binds the signature to the cart contents."},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"IntentMandate":{"properties":{"user_cart_confirmation_required":{"type":"boolean","title":"User Cart Confirmation Required","description":"If false, the agent can purchase without showing the cart. Must be true if the intent mandate is not signed by the user.","default":true},"natural_language_description":{"type":"string","maxLength":500,"title":"Natural Language Description","description":"Agent's understanding of the user's prompt, in natural language. Confirmed by the user before signing."},"merchants":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Merchants","description":"Allowed merchants. None = any merchant."},"skus":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Skus","description":"Specific product SKUs. For BotMarket, use dataset slugs."},"requires_refundability":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Requires Refundability","default":false},"intent_expiry":{"type":"string","title":"Intent Expiry","description":"When this intent expires, ISO 8601 format."},"dataset_slug":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Dataset Slug","description":"BotMarket: which dataset to purchase."},"buyer_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Buyer Email","description":"BotMarket: buyer email (required). Used for order lookup, no login/session."},"order_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Order Type","description":"BotMarket: 'add_balance' or 'bulk_download'."},"amount_usd":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Amount Usd","description":"BotMarket: USD to add to balance (for add_balance)."},"api_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Api Key","description":"BotMarket: existing API key to top up (for add_balance). If provided, balance is added to this key instead of creating a new one."},"max_amount":{"anyOf":[{"$ref":"#/components/schemas/PaymentCurrencyAmount"},{"type":"null"}],"description":"BotMarket: maximum price the user will accept."},"buyer_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Buyer Name","description":"Full name of the human behind the purchase."},"buyer_company":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Buyer Company","description":"Organization the human belongs to."},"buyer_role":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Buyer Role","description":"Job title or role (e.g. 'Data Engineer')."},"agent_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Agent Name","description":"Agent framework or product name (e.g. 'Claude', 'AutoGPT')."},"agent_goal":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Agent Goal","description":"What task the agent is trying to accomplish."}},"type":"object","required":["natural_language_description","intent_expiry"],"title":"IntentMandate","description":"User's purchase intent, confirmed and signed.\n\nMatches the official AP2 IntentMandate structure.\nBotMarket extension fields (dataset_slug, order_type, amount_usd) are\nclearly marked — they map to the spec's `skus` concept for digital goods."},"PaymentCurrencyAmount":{"properties":{"currency":{"type":"string","title":"Currency","description":"ISO 4217 currency code.","default":"USD"},"value":{"type":"number","title":"Value","description":"Monetary value."}},"type":"object","required":["value"],"title":"PaymentCurrencyAmount"},"PaymentDetailsInit":{"properties":{"id":{"type":"string","title":"Id","description":"Unique payment request identifier."},"display_items":{"items":{"$ref":"#/components/schemas/PaymentItem"},"type":"array","title":"Display Items"},"total":{"$ref":"#/components/schemas/PaymentItem"},"shipping_options":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}],"title":"Shipping Options"},"modifiers":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}],"title":"Modifiers"}},"type":"object","required":["id","total"],"title":"PaymentDetailsInit"},"PaymentItem":{"properties":{"label":{"type":"string","title":"Label","description":"Human-readable description."},"amount":{"$ref":"#/components/schemas/PaymentCurrencyAmount"},"pending":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Pending","description":"True if amount is not final."},"refund_period":{"type":"integer","title":"Refund Period","description":"Refund window in days.","default":30}},"type":"object","required":["label","amount"],"title":"PaymentItem"},"PaymentMandate":{"properties":{"payment_mandate_contents":{"$ref":"#/components/schemas/PaymentMandateContents"},"user_authorization":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User Authorization","description":"Verifiable presentation (sd-jwt-vc) of user's payment authorization."}},"type":"object","required":["payment_mandate_contents"],"title":"PaymentMandate","description":"Payment credential shared with the payment ecosystem.\n\nuser_authorization should be a base64url-encoded verifiable presentation\n(e.g., sd-jwt-vc) signing over the cart and payment mandate hashes.\nIn dev mode, any non-empty string is accepted."},"PaymentMandateContents":{"properties":{"payment_mandate_id":{"type":"string","title":"Payment Mandate Id"},"payment_details_id":{"type":"string","title":"Payment Details Id"},"payment_details_total":{"$ref":"#/components/schemas/PaymentItem"},"payment_response":{"$ref":"#/components/schemas/PaymentResponse"},"merchant_agent":{"type":"string","title":"Merchant Agent","default":"BotMarket"},"transaction_modality":{"$ref":"#/components/schemas/AP2TransactionModality","default":"HUMAN_PRESENT"},"timestamp":{"type":"string","title":"Timestamp","description":"ISO 8601 timestamp."}},"type":"object","required":["payment_mandate_id","payment_details_id","payment_details_total","payment_response"],"title":"PaymentMandateContents"},"PaymentMethodData":{"properties":{"supported_methods":{"type":"string","title":"Supported Methods","description":"Payment method identifier."},"data":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Data"}},"type":"object","required":["supported_methods"],"title":"PaymentMethodData"},"PaymentOptions":{"properties":{"request_payer_name":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Request Payer Name","default":false},"request_payer_email":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Request Payer Email","default":false},"request_payer_phone":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Request Payer Phone","default":false},"request_shipping":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Request Shipping","default":false},"shipping_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Shipping Type"}},"type":"object","title":"PaymentOptions"},"PaymentRequest":{"properties":{"method_data":{"items":{"$ref":"#/components/schemas/PaymentMethodData"},"type":"array","title":"Method Data"},"details":{"$ref":"#/components/schemas/PaymentDetailsInit"},"options":{"anyOf":[{"$ref":"#/components/schemas/PaymentOptions"},{"type":"null"}]}},"type":"object","required":["method_data","details"],"title":"PaymentRequest"},"PaymentResponse":{"properties":{"request_id":{"type":"string","title":"Request Id"},"method_name":{"type":"string","title":"Method Name"},"details":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Details","description":"Payment-method-specific data (e.g., {'token': 'tok_xxx'}). Must be tokenized — raw card numbers are rejected."},"payer_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Payer Name"},"payer_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Payer Email"},"payer_phone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Payer Phone"}},"type":"object","required":["request_id","method_name"],"title":"PaymentResponse","description":"User's chosen payment method and approval of a PaymentRequest."},"PromoClaimRequest":{"properties":{"buyer_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Buyer Name"},"buyer_company":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Buyer Company"},"buyer_role":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Buyer Role"},"agent_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Agent Name"},"agent_goal":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Agent Goal"},"buyer_email":{"type":"string","title":"Buyer Email"}},"type":"object","required":["buyer_email"],"title":"PromoClaimRequest"},"PurchaseRequest":{"properties":{"cart_mandate":{"$ref":"#/components/schemas/CartMandate"},"payment_mandate":{"$ref":"#/components/schemas/PaymentMandate"},"intent_mandate":{"anyOf":[{"$ref":"#/components/schemas/IntentMandate"},{"type":"null"}]}},"type":"object","required":["cart_mandate","payment_mandate"],"title":"PurchaseRequest","description":"BotMarket API wrapper for AP2 purchase.\n\nCombines the mandate chain into a single POST body.\nThe AP2 spec defines the mandate flow but not a specific\npurchase request envelope — this is our implementation."},"StripeCheckoutRequest":{"properties":{"buyer_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Buyer Name"},"buyer_company":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Buyer Company"},"buyer_role":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Buyer Role"},"agent_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Agent Name"},"agent_goal":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Agent Goal"},"amount_usd":{"type":"number","title":"Amount Usd"},"api_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Api Key"}},"type":"object","required":["amount_usd"],"title":"StripeCheckoutRequest","description":"Body for POST /api/checkout/stripe (session-gated; email comes from session)."},"TransferRequest":{"properties":{"to_key_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"To Key Id"},"to_api_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"To Api Key"},"amount_usd":{"type":"number","title":"Amount Usd"}},"type":"object","required":["amount_usd"],"title":"TransferRequest"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"X402CheckoutRequest":{"properties":{"buyer_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Buyer Name"},"buyer_company":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Buyer Company"},"buyer_role":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Buyer Role"},"agent_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Agent Name"},"agent_goal":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Agent Goal"},"amount_usd":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Amount Usd"},"buyer_email":{"type":"string","title":"Buyer Email"},"api_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Api Key"}},"type":"object","required":["buyer_email"],"title":"X402CheckoutRequest","description":"Body for POST /api/checkout/x402 (agent flow; no session required)."}},"securitySchemes":{"HTTPBearer":{"type":"http","description":"BotMarket API key: prefix `bot_market_ak_` with USD balance. If you have an active OEC subscription, you can instead send your OEC API key (32 lowercase hex characters, no prefix) in the same Bearer field — that includes 1,000 BotMarket query requests per day at no extra charge. View or copy your OEC API key at https://oec.world/en/account.","scheme":"bearer"}}},"tags":[{"name":"catalog","description":"Browse and search the dataset catalog."},{"name":"datasets","description":"Dataset detail, schema, filter members, sample rows, and paid queries."},{"name":"payments","description":"Stripe checkout and order status polling."},{"name":"ap2","description":"AP2 mandate-based agent payments."},{"name":"x402","description":"HTTP-native stablecoin payments for AI agents."},{"name":"account","description":"API key balance and order lookup."}]}