Documentation menu · routing-policy

Routing policy

A policy decides which offers may serve a call and how they're ranked. It can be set four ways, and the four are merged so that they only ever tighten.

The four ways

1. Key policy

Set in the dashboard when creating or editing a key. Applies to every request made with that key.

2. Policy path

Prefix the API path with /p/{policy}, tokens joined with +. Works for /v1/… and /anthropic/….

example
http://localhost:8787/p/min60+zdr+eu+verified/v1
TokenMeaning
min{N}Minimum discount vs list price, in percent — e.g. min60
zdrZero-data-retention offers only
teeAttested TEE offers only (coming soon — no offer qualifies yet)
eu / us / apacRegion
verified / probedMinimum verification tier
fastObjective latency
cheapObjective price
reliableObjective reliability
valueObjective value
maskMask secrets and PII before forwarding
cacheUse your opt-in response cache
hedge{ms}Hedge if no first token within ms — e.g. hedge800
max{usd}Maximum output price in $ per 1M — e.g. max0.5

An unknown token returns 400 invalid_request.

3. Headers

headers
X-Thin-Min-Discount: 60
X-Thin-Objective: latency
X-Thin-Region: eu
X-Thin-ZDR: on
X-Thin-Verification: verified
X-Thin-Mask: on
X-Thin-Cache: on
X-Thin-Hedge-Ms: 800
X-Thin-Max-Output-Price: 0.5

4. Body field

A thin object in the request body. It is stripped before the request is forwarded.

json
"thin": {
  "objective": "price | latency | reliability | value",
  "price_tolerance_pct": 10,
  "min_discount": 60,
  "max_input_price_micro": 300000,
  "max_output_price_micro": 900000,
  "verification": "probed | verified | attested",
  "zdr": true,
  "tee": false,
  "regions": ["eu"],
  "sellers": ["s_7f3a"],
  "sellers_blocked": ["s_19cc"],
  "max_latency_ms": 2000,
  "hedge_after_ms": 800,
  "mask": true,
  "cache": true,
  "cache_ttl_s": 3600,
  "rescue": true,
  "max_attempts": 3
}

Defaults and precedence

  • Defaults: objective price, verification verified, rescue true, max_attempts 3, price tolerance 0 for price and 25% for the other objectives.
  • The default tier applies only when no source names one, so a request may opt into probed offers. Once any source (for example your key) sets a tier, the strictest named tier wins.
  • Floors take the strictest value (highest min_discount, lowest max price, highest tier).
  • Requirements add up: any source asking for ZDR, TEE or masking turns it on.
  • Allow-lists intersect; block-lists union. A request can narrow a key's policy, never widen it.

Objectives

  • price — cheapest eligible offer first.
  • latency — fastest time-to-first-token within the price tolerance band.
  • reliability — highest recent success rate within the band.
  • value — price weighed against verification score and success rate.

price_tolerance_pct sets how far above the cheapest eligible price an offer may be and still be ranked by a non-price objective.

Seeing the decision

POST /v1/route/preview takes a chat request and returns the merged policy, the eligible offers in rank order and every rejected offer with its reason. Nothing is sent upstream and nothing is charged.

Rejection reasons

ReasonMeaning
unhealthyOffer is failing health checks
pausedSeller paused the offer
verification_below_policyOffer's tier is below your required tier
not_zdrYou required ZDR
not_teeYou required TEE
region_excludedOffer region not in your regions
seller_excludedNot in your sellers allow-list
seller_blockedIn your sellers_blocked list
below_min_discountDiscount vs list below your floor
above_max_pricePrice above your max input/output price
latency_above_maxp50 time-to-first-token above max_latency_ms
daily_cap_reachedSeller's daily cap is used up
at_capacitySeller's max concurrency reached
outside_scheduleOutside the seller's selling windows
context_too_smallRequest won't fit the offer's context

When nothing qualifies

If offers exist but your policy excludes them all, the call fails with no_eligible_offers and the error includes the rejected list. If no one sells the model, it's no_offers_for_model.

Per-key guardrails

  • Budgets: budget_daily_micro and budget_monthly_micro; exceeding one returns budget_exceeded.
  • Model map: glob patterns mapping incoming model names to exchange models.
  • Anomaly guard: if a key's spend over the last 10 minutes exceeds the larger of $5 and 10× its trailing 24-hour 10-minute average, the key is frozen (key_frozen) and you're notified. Unfreeze it in the dashboard.