The three buckets
Per client, sliding hour, HTTP 429 with {"error": "rate_limited"} when exhausted. A client is the caller’s address and client signature, or the OAuth client when a bearer is sent. The machine-readable copy is rate-limits.yaml.
| Bucket | Limit | Covers | When exhausted |
|---|---|---|---|
| Quote | 80 an hour | POST /quote; MCP get_parcel_quote; the A2A skill; POST /agent/checkout-session, create_checkout_link and the A2A skill when they price live (no valid quote_id) | 429 rate_limited |
| Checkout status | 60 an hour | GET /agent/checkout-session/{{session_id}}; MCP get_checkout_status; the A2A skill | 429 rate_limited |
| OAuth token | 20 an hour | POST /oauth/token | 429 slow_down |
quote_id in create_checkout_link spends nothing from the quote bucket, so quote once and hand off from that quote.What spends nothing
track_parcel and get_price_index over MCP spend no quote allowance. GET /status and the discovery documents (/openapi.json, everything under /.well-known/) are public and cacheable for an hour.
What a 429 looks like
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
{"error": "rate_limited",
"message": "Too many Smart Quote API requests from this client. Try again later."}
No rate-limit or Retry-After headers are sent today. Buckets are sliding one-hour windows: after a 429, wait and retry later rather than immediately. Switching from REST to MCP does not add capacity; the buckets are shared.
A bucket of your own
A client that needs more than the public allowance holds OAuth 2.0 client_credentials, issued by hand: write to info@smklog.com as auth.md describes, exchange the credentials at POST https://quote-api.smklog.com/oauth/token (scope quote), and send the opaque bearer on POST /quote. The token lives one hour and buys a dedicated hourly quote bucket at the size agreed at registration. Discovery: authorization-server metadata.