Zoral for developers and agents
Zoral sells one thing: a 316L medical-grade stainless steel tongue scraper. Everything about it — catalog, live prices, stock, reviews, policies — is available over a public API. No API key, no sign-up, no sales call. You can go from zero to a payable checkout session in two requests.
Quickstart
1. Read the catalog. This needs no credential at all:
curl "https://getzoral.com/api/store/products"2. Build a checkout session your buyer can pay:
curl -X POST "https://getzoral.com/checkout_sessions" \
-H "Content-Type: application/json" \
-H "API-Version: 2026-07-16" \
-d '{ "items": [{ "id": "tongue-scraper", "quantity": 1 }] }'Read totals.total.amount for the amount due, then send the buyer to payment_provider.checkout_url to pay.
API keys and credentials
Reading the catalog and building carts needs no key. That is deliberate: an agent that must register before it can browse will simply leave.
If you want to act under your own client identity, registration is open and self-service (RFC 7591) — no human approval step:
curl -X POST "https://api.getzoral.com/oauth/register" \
-H "Content-Type: application/json" \
-d '{ "client_name": "Your App", "scope": "catalog:read cart:write" }'That returns a client_id and a client_secret (shown once — we store only a scrypt hash). Exchange them for a 1-hour bearer token via the client_credentials grant:
curl -X POST "https://api.getzoral.com/oauth/token" \
-u "CLIENT_ID:CLIENT_SECRET" \
-d "grant_type=client_credentials" -d "scope=catalog:read"Scopes are catalog:read and cart:write. Full walkthrough: /auth.md. Revoke at https://api.getzoral.com/oauth/revoke (RFC 7009).
Testing without side effects
There is no separate sandbox host, because you do not need one. Every read endpoint is side-effect free. Checkout sessions are ordinary carts: creating one, adding items and applying 10OFF charges nothing and reserves nothing — a session only becomes an order when a human completes payment on Stripe. Abandon a session by simply not paying it, or POST /checkout_sessions/{id}/cancel. Nothing you do against this API can move money.
Documentation
- /openapi.json — OpenAPI 3.1 description (machine-readable, function-calling ready)
- /auth.md — OAuth 2.0 walkthrough for agents
- /llms.txt — what Zoral is and when an agent should use it
- /developers/llms.txt — scoped context for this page only
- /pricing.md — machine-readable pricing
- /.well-known/api-catalog — RFC 9727 catalog
- /.well-known/agent-skills/index.json — Agent Skills, with sha256 digests
- /.well-known/agent-card.json — A2A agent card
- github.com/getzoral/agent-resources — AGENTS.md and skills, mirrored
Base URL
https://getzoral.com/api/storeEndpoints
| Operation | Endpoint | Purpose |
|---|---|---|
listProducts | GET /api/store/products | Catalog with prices and stock |
getProduct | GET /api/store/products/{id} | One product |
listReviews | GET /api/store/reviews | Verified reviews + average rating |
listRegions | GET /api/store/regions | Regions (currency / pricing) |
listCollections | GET /api/store/collections | Collections |
createCheckoutSession | POST /checkout_sessions | Agentic Commerce Protocol session |
MCP
Two Streamable HTTP servers, protocol 2025-06-18, both zero-auth:
/mcp— store:search_catalog,get_product,get_reviews,get_shop_policies/mcp/docs— content:search_articles,get_article,list_article_tags,search_faqs
Prices
Prices are region-scoped and returned in major units — 9.99 means $9.99, not 999 cents. Pass region_id (from /api/store/regions) to price against a specific region; otherwise the store default (USD) is used.
Errors
Every error is JSON — never an HTML page — with a stable code and a suggested next step:
{
"error": {
"code": "unknown_endpoint",
"message": "No public read endpoint at /api/store/foo.",
"resolution": "See https://getzoral.com/openapi.json for available operations."
}
}502 and 503 are transient — retry with backoff.
Rate limits
No hard published quota. Responses are cached for 60s; please cache on your side and avoid polling faster than once a minute.
Payment
Zoral does not accept delegated card credentials from an agent. Every checkout session says so explicitly via payment_provider.provider: "human_handoff". Send the buyer to the returned checkout_url; payment is handled by Stripe and Zoral never receives raw card details. This is a design choice, not a gap.