Worldwide shipping $10 flat | Save 10% with code 10OFF at checkout

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

Base URL

https://getzoral.com/api/store

Endpoints

OperationEndpointPurpose
listProductsGET /api/store/productsCatalog with prices and stock
getProductGET /api/store/products/{id}One product
listReviewsGET /api/store/reviewsVerified reviews + average rating
listRegionsGET /api/store/regionsRegions (currency / pricing)
listCollectionsGET /api/store/collectionsCollections
createCheckoutSessionPOST /checkout_sessionsAgentic Commerce Protocol session

MCP

Two Streamable HTTP servers, protocol 2025-06-18, both zero-auth:

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.

Contact

[email protected]