Skip to content

Lavender API

Your Greeks are only as good as your model. The Lavender native API gives you a second, independently computed set — dividend-aware, early-exercise-aware, with calibrated forward prices — that you can run as your primary source or alongside an existing provider. It's the richest way to access Gateway's Greeks: extended Greeks through third order, quality metadata, per-expiry chain data, and term structure support, in a clean, flat response format.

Whether you're starting fresh or migrating, this is the canonical protocol. The vendor compatibility layers let you swap a vendor's host with a one-line change and adopt the Lavender API at your own pace.

Want to verify these numbers yourself?

Every Greek returned by this endpoint is reproducible from first principles — see Verify the Greeks for the Black-76 derivation and a drop-in Python/R/Excel reference implementation.

Try It in Your Browser

Once Gateway is running, paste this into any browser:

http://localhost:2112/l1/greeks?root=SPY&center=atf&format=html

The at-the-forward call and put for every SPY expiry, rendered as an HTML table. Change the symbol or drop the center=atf filter to widen the view. No API key, no code, no setup.

Sample Response

The values shown below are illustrative -- a snapshot from the moment this page was written. A live request returns whatever the market is doing right now, so und_price, the Greeks, and theo will be different. The shape and field set are stable.

GET /l1/greeks?root=SPY&right=call&min_strike=570&max_strike=570&min_exp=2026-12-18&max_exp=2026-12-18&format=json
[
  {
    "underlying": "SPY",
    "root": "SPY",
    "expiry": "2026-12-18",
    "strike": 570,
    "right": "call",
    "osym": "SPY   261218C00570000",
    "und_price": 632.16,
    "delta": 0.7335,
    "gamma": 0.0022,
    "vega": 1.7270,
    "theta": -0.1147,
    "decay": -0.1495,
    "rho": 2.6532,
    "theo": 95.94,
    "vol": 0.2659,
    "greeks": "core",
    "ts": "2026-05-12T13:04:02.595"
  }
]

The core field group (default) includes delta, gamma, vega, theta, rho, plus Lavender-specific fields: decay (next-trading-day P&L), theo (model price), and vol (calibrated implied volatility). Add greeks=all for extended Greeks through third order.

Endpoint

GET /l1/greeks

Primary endpoint. No authentication required. Runs on localhost:2112.

Returns per-contract Greeks for all options on an underlying, with optional filtering, field selection, and term structure modes.

A slimmer companion endpoint, /l1/chains, returns just the per-expiry chain metadata (forward, rates, dividends, borrow, settlement) with one row per (root, expiry). Use it when you need term-structure inputs but not strikes.

Output Formats

Every request accepts a format parameter:

Format Value Content-Type Notes
JSON format=json application/json Array of objects. Default.
CSV format=csv text/csv Header row + data rows. Ideal for pandas / R.
NDJSON format=ndjson application/x-ndjson One JSON object per line. Good for streaming.
HTML format=html text/html Rendered table. Paste the URL in a browser.

Browser-first onboarding

Append ?format=html (or &format=html) to any request to see the output as a rendered table — no code needed. Great for quick inspection, spot-checking Greeks, or sharing a link with a colleague.

Identity Fields

Every response row includes identity fields that describe which contract the row belongs to.

Every response row includes both structural fields and the OSI symbol:

Field Example Description
underlying SPY Underlying symbol
root SPY Option root
expiry 2026-06-19 Expiration date
strike 550 Strike price
right call call or put
osym SPY 260619C00550000 Standard OSI contract symbol (21 chars, space-padded root)

Field Groups

Control which fields appear in the response with the greeks parameter. Default is core. Use greeks=all for everything, or combine groups with commas (e.g., greeks=core,chain).

Every response row carries two metadata columns appended after the real data: greeks (echo of which field groups are active) and ts (the wall-clock reprice timestamp). ts is always rightmost — pinned in a known position regardless of which field groups you select — so a client can pick it off without knowing which Greeks columns came back. See Response metadata in the field reference for details.

Which group do I need?

Most traders need core — delta, gamma, vega, theta, rho, and the model price. This is the default. Add extra if you trade vol (vanna, volga, charm, veta) or want bid/ask IV. Add exotic for third-order Greeks (speed, zomma, color, ultima) — rarely needed outside market-making. Add chain for per-expiry data (forward price, rates, dividends, settlement type).

core — Essential per-strike Greeks

Field Description
und_price Current underlying price
delta \(\partial V / \partial S\) — per $1 spot move
gamma \(\partial^2 V / \partial S^2\) — per $1 spot move
vega \(\partial V / \partial \sigma\) — per 1% vol move
theta \(\partial V / \partial t\) — per calendar day
decay Expected price change to same time on next trading day
rho \(\partial V / \partial r\) — per 1% rate move
theo Model theoretical value
vol Surface-fitted implied volatility (decimal: 0.25 = 25%)

extra — Cross-Greeks and vol data

Field Description
vanna \(\partial^2 V / \partial S\,\partial \sigma\) — delta sensitivity to vol
volga \(\partial^2 V / \partial \sigma^2\) — vega sensitivity to vol (also known as vomma)
charm \(\partial^2 V / \partial S\,\partial t\) — delta decay over time (annualized)
veta \(\partial^2 V / \partial \sigma\,\partial t\) — vega decay over time (annualized)
bid_vol Implied volatility at bid price
ask_vol Implied volatility at ask price
prev_vol Prior session's implied volatility
confidence Vol surface quality metric

exotic — Niche and third-order Greeks

Field Description
speed \(\partial^3 V / \partial S^3\) — gamma sensitivity to spot
zomma \(\partial^3 V / \partial S^2\,\partial \sigma\) — gamma sensitivity to vol
color \(\partial^3 V / \partial S^2\,\partial t\) — gamma decay over time (annualized)
ultima \(\partial^3 V / \partial \sigma^3\) — volga sensitivity to vol
vera \(\partial^2 V / \partial \sigma\,\partial r\) — cross-sensitivity of vol and rates
lambda \(\Delta \times S \,/\, V\) — leverage ratio (% option move per % spot move). Also known as omega (\(\Omega\)).
epsilon \(\partial V / \partial q\) — per 1% dividend yield move

chain — Per-expiry constants

Field Description
forward Calibrated forward price for this expiry
ex_style american or european
settle am or pm settlement
days Fractional calendar days to settlement (e.g., 31.83 means 31 days and ~20 hours). Accounts for AM vs PM settlement.
t Variance-weighted time to expiry (years). Use for σ√t in Black-76 d1/d2.
t_disc Calendar time to expiry (years). Use for discounting: DF = exp(−r × t_disc).
rate Risk-free rate (annualized, continuously compounded)
borrow Implied stock borrow rate (annualized, continuously compounded)
divs Cumulative dividends to expiry (dollars)

Query Parameters

Parameter Type Default Description
underlying string All roots for an underlying (e.g., SPX returns both SPX and SPXW). Use this for typical queries.
root string A specific option root (e.g., SPXW for just SPX weeklies). Use when you need to filter to one root within a multi-root underlying. One of underlying or root is required. Alias: symbol.
format string json json, csv, ndjson, or html
exp date or * * Exact expiration, comma-separated list, or * for all. Accepts yyyy-MM-dd, yyyyMMdd, or yyMMdd.
right string both call, put, or both. Alias: type.
strike decimal Exact strike match. Comma-separated for multi-strike (e.g., strike=570,580,590).
min_strike decimal Strike floor
max_strike decimal Strike ceiling
min_exp date Expiration floor
max_exp date Expiration ceiling
dte int Days-to-expiry (nearest match). For each value, picks the available expiry whose calendar distance to today + N is smallest. Comma-separated for multi-DTE (e.g., dte=7,30,60). Per-root: with multi-root queries, each root contributes its own nearest expiry.
min_dte int Minimum days to settlement
max_dte int Maximum days to settlement
min_delta decimal Lower bound on signed delta (−1 to 1). Calls are positive, puts are negative. Use min_delta=0.3&max_delta=0.6 for ITM-ish calls, min_delta=-0.6&max_delta=-0.3 for ITM-ish puts.
max_delta decimal Upper bound on signed delta (−1 to 1).
moneyness string itm, otm, or atm. See moneyness section below.
greeks string core Comma-separated list of field groups (core, extra, exotic, chain, all) and/or individual field names. See "Field selection" below.
center string atm (at-the-money) or atf (at-the-forward) — anchors per expiry
strike_count int 1 Number of closest strikes to center, per expiry
sort string Sort key, ascending. One of: delta, call_delta, gamma, vega, theta, vol, strike, expiry. Overrides the default sort order.
sortdesc string Same as sort but descending
limit int Cap the number of returned rows. Applied after sorting.
osym string Request specific contracts by OSI symbol (comma-separated). Accepts padded (AAPL 260321C00400000) or compact (AAPL260321C00400000) forms. When set, root/underlying are optional.

Parameter details

  • underlying and root accept comma-separated lists (e.g., underlying=SPX,NDX or root=SPX,SPXW).
  • underlying expands to all roots for each underlying — underlying=SPX returns both SPX and SPXW options.
  • root returns only the exact root(s) specified.
  • center must be atm or atf — unrecognized values return 400.
  • sort/sortdesc override the default underlying → expiry → strike ordering. call_delta normalizes put delta to 1 + delta so calls and puts sort on the same scale.
  • Unknown parameters return a 400 error with a descriptive message. This catches typos like ?righ=call.
  • All numeric values are rounded to 6 decimal places.

Field selection (greeks=)

Mix group names and individual field names freely. Output column order is fixed (coreextraexoticchain) regardless of the order tokens appear in the request.

Example Returns
greeks=core All core fields (default)
greeks=delta,vega Only those two
greeks=core,vanna,volga Core plus those two extras
greeks=all Every field across all groups
greeks=core,chain Core fields plus chain pricing inputs

Unknown field names return a 400 error (e.g., Unknown field 'vomma' in greeks=) — this catches typos and reminds you of canonical names. Identity fields (underlying, root, expiry, strike, right, osym, greeks) are always included.

Moneyness (moneyness=)

Value Definition
itm Strikes where the option has intrinsic value relative to the forward. Calls: K ≤ F. Puts: K ≥ F. The single ATM strike falls into itm.
otm The other side. Calls: K > F. Puts: K < F.
atm The single strike closest to the forward, returned per (root, expiry) pair. With right=both (the default) you get both the call and the put at that strike — so two rows per (root, expiry). With right=call or right=put you get one row per (root, expiry).

itm and otm partition the chain at the forward. atm is independent and always returns exactly one strike per (root, expiry) — even on multi-underlying or multi-root queries.

Sort Order

Results are sorted deterministically:

  1. Underlying — in the order specified by the caller
  2. Expiration — ascending
  3. Settlement — AM before PM
  4. Root — alphabetical
  5. Strike — ascending
  6. Right — call before put

Term Structure

Use center=atm or center=atf to select the N closest strikes to an anchor per expiry. Combined with strike_count=1 (the default) and right=call, this produces one row per expiration — a term structure view.

http://localhost:2112/l1/greeks?root=AAPL&center=atf&right=call&format=html
http://localhost:2112/l1/greeks?root=AAPL&center=atm&right=call&format=html
http://localhost:2112/l1/greeks?root=AAPL&center=atf&strike_count=5&format=html
  • atm anchors to the nearest strike to the current underlying price
  • atf anchors to the nearest strike to the calibrated forward price for each expiry
  • Numeric values (e.g., center=25) anchor to the nearest strike by call delta — see Example Requests

All Greeks are per-share

Multiply by 100 (or the contract multiplier) to get per-contract values. This applies to all endpoints — native and vendor compatibility.

List available expirations

Use center=atm&strike_count=1&right=call to get one row per expiration — a lightweight expiry discovery query:

http://localhost:2112/l1/greeks?root=AAPL&center=atm&strike_count=1&right=call&format=csv

Example Requests

Every example is a complete URL — paste it in a browser or curl it.

http://localhost:2112/l1/greeks?root=AAPL : All AAPL Greeks — core fields, all expirations

http://localhost:2112/l1/greeks?root=AAPL&right=call&max_dte=30 : Just calls, near-term

http://localhost:2112/l1/greeks?root=AAPL&right=call&dte=7,30,90 : Calls at the expiries nearest to 7, 30, and 90 days from today (one expiry per requested DTE)

http://localhost:2112/l1/greeks?root=AAPL&strike=170,175,180&right=call : Specific strikes only

http://localhost:2112/l1/greeks?root=AAPL&moneyness=otm&right=call : Out-of-the-money calls only

http://localhost:2112/l1/greeks?root=AAPL&sortdesc=vega&limit=10 : Top 10 contracts by vega

http://localhost:2112/l1/greeks?root=AAPL&center=atf&right=call : Term structure — one row per expiry at the forward

http://localhost:2112/l1/greeks?root=AAPL&center=25&right=call : 25-delta call skew across the term

http://localhost:2112/l1/greeks?root=AAPL&center=atf&right=call&greeks=chain : Term structure with carry data (forward, rates, divs)

http://localhost:2112/l1/greeks?underlying=SPX : SPX + SPXW options together — underlying= returns every root for that underlying

http://localhost:2112/l1/greeks?root=SPX : Just the PM-settled SPX monthlies — root= is the more specific selector

http://localhost:2112/l1/greeks?root=SPXW : Just the SPX weeklies

http://localhost:2112/l1/greeks?root=SPX,SPXW : Same as underlying=SPX, listed explicitly

http://localhost:2112/l1/greeks?root=AAPL&greeks=all : Every field — core, extra, exotic, chain

http://localhost:2112/l1/greeks?root=AAPL&format=html : Paste in browser — instant Greeks table

Code Examples

import pandas as pd

url = "http://localhost:2112/l1/greeks"
df = pd.read_csv(f"{url}?root=SPY&center=atf&format=csv")

# Near-term ATM calls
near = df[(df["right"] == "call") & (df["delta"].abs() > 0.4) & (df["delta"].abs() < 0.6)]
print(near[["expiry", "strike", "delta", "vega", "theta", "decay", "vol"]])
df <- read.csv(paste0(
  "http://localhost:2112/l1/greeks",
  "?root=SPY&center=atf&format=csv"))

# Filter to near-term calls
calls <- df[df$right == "call" & abs(df$delta) > 0.4, ]
head(calls[, c("expiry", "strike", "delta", "vega", "theta", "decay", "vol")])
using var client = new HttpClient();
var json = await client.GetStringAsync(
    "http://localhost:2112/l1/greeks?root=SPY&center=atf&format=json");

using var doc = JsonDocument.Parse(json);
foreach (var row in doc.RootElement.EnumerateArray().Take(5))
{
    Console.WriteLine($"{row.GetProperty("expiry")} " +
        $"{row.GetProperty("strike")} {row.GetProperty("right")}: " +
        $"delta={row.GetProperty("delta")}");
}
#include <cpr/cpr.h>
#include <nlohmann/json.hpp>
using json = nlohmann::json;

auto r = cpr::Get(cpr::Url{
    "http://localhost:2112/l1/greeks?root=SPY&center=atf&format=json"});
auto data = json::parse(r.text);

for (auto& row : data | std::views::take(5))
    std::cout << row["expiry"] << " " << row["strike"]
              << " delta=" << row["delta"] << "\n";
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder()
    .uri(URI.create(
        "http://localhost:2112/l1/greeks?root=SPY&center=atf&format=json"))
    .build();

var response = client.send(request, HttpResponse.BodyHandlers.ofString());
var array = new JSONArray(response.body());
for (int i = 0; i < Math.min(5, array.length()); i++) {
    var row = array.getJSONObject(i);
    System.out.printf("%s %.0f %s: delta=%.3f%n",
        row.getString("expiry"), row.getDouble("strike"),
        row.getString("right"), row.getDouble("delta"));
}
const resp = await fetch(
  "http://localhost:2112/l1/greeks?root=SPY&center=atf&format=json"
);
const greeks = await resp.json();
greeks.slice(0, 5).forEach(c =>
  console.log(`${c.expiry} ${c.strike} ${c.right}: delta=${c.delta}`)
);
using CSV, DataFrames, HTTP

resp = HTTP.get(
    "http://localhost:2112/l1/greeks?root=SPY&center=atf&format=csv")
df = CSV.read(IOBuffer(resp.body), DataFrame)

# Near-term ATM calls
filter(r -> r.right == "call" && abs(r.delta) > 0.4, df) |>
    x -> select(x, :expiry, :strike, :delta, :vega, :theta, :decay, :vol) |>
    x -> first(x, 10)

How It Differs from Vendor Compatibility Layers

Lavender API Vendor Compatibility
Field names Lavender native (vol, und_price, decay, …) Vendor-specific (implied_vol, underlying_price, …)
Field selection greeks= groups (core, extra, exotic, chain) Fixed per vendor
Filters Strike/DTE/delta/moneyness + sort/limit + term structure Vendor-specific subset
Term structure center=atm/atf + strike_count Not available
Market data fields Not included — model outputs only Zeroed for wire compatibility
Response shape Flat array of objects Vendor-specific envelope
Greek units Per-1% vega/rho/epsilon, per-calendar-day theta Converted to each vendor's convention

The compatibility layers are for migrating existing code with zero changes. The Lavender API is for new integrations and for accessing the full feature set.

Error Handling

Status Condition Example
200 Success. Empty array [] means no contracts matched your filters — the root exists but no options match. ?root=AAPL&exp=2026-07-04 (holiday, no expiry)
400 Invalid or missing parameters. The response body describes the error. Missing root or underlying, Invalid right, Unknown parameter 'righ'
502 Upstream data unavailable -- the gateway could not fetch Greeks from the data engine. See When you see a 502 below.

Unknown parameters return 400 with the parameter name — this catches typos like ?righ=call before they silently produce wrong results.

When you see a 502

A 502 means Gateway received your request but couldn't deliver a Greeks response. The three common causes:

Cause How long it lasts Signal
Housekeeping-window restart A few seconds, nightly 03:00-04:00 ET (details) Daily cadence; outside that hour Gateway runs without interruption
Upstream feed transient Seconds to a minute Persists across retries within a short window; recovers on its own
Entitlement / subscription check failed Until the subscription state is resolved Gateway console logs the entitlement message (details)

Recommended client behavior:

  • Retry 502s with exponential backoff and jitter -- e.g. 250ms, 500ms, 1s, 2s, capped at 30s, max 5 attempts.
  • Do not retry 4xx responses. They are not transient; the client request is wrong.
  • A 502 that persists for more than ~1 minute outside the nightly 03:00-04:00 ET housekeeping window almost always indicates an entitlement issue -- check Gateway's console output rather than retrying further.

Compat layers (Polygon.io, ThetaData, Alpaca, etc.) emit 502 for the same conditions; the response body matches the upstream vendor's error envelope.

Rate Limits

There are no rate limits. Gateway runs on localhost and serves requests as fast as your machine can handle them. Typical latency is 5–50ms for a single root, 100–200ms for large chains (SPY, SPX).

Coverage

Lavender covers all OPRA-listed US options — equities, ETFs, and index options including SPX, NDX, RUT, VIX, and their weekly variants. Approximately 6,000 underlying names with all listed expirations and strikes.

Data Freshness

Greeks are repriced continuously against the market during market hours (9:30 AM – 4:00 PM ET). Outside market hours, Greeks reflect the last computed values from the prior session.

Excel Integration

Bulk fetch + VLOOKUP

Don't make one HTTP call per cell — Excel will freeze. Instead, use Power Query to import the full chain as a table, then VLOOKUP into it:

  1. Data → From Web → paste http://localhost:2112/l1/greeks?root=AAPL&center=atf&format=csv
  2. Power Query imports all Greeks as a table
  3. Use VLOOKUP or INDEX/MATCH against the table to pull individual values into your spreadsheet
  4. Data → Refresh All to update Greeks

For multiple underlyings, make one query per underlying (not per contract). Each query returns the full chain in ~50ms.


Per-expiry chain metadata: /l1/chains

GET /l1/chains

Returns the per-expiry pricing inputs (underlying price, forward, rate, borrow, dividends, variance time, settlement type) as one row per (root, expiry) — no strikes, no Greeks. Same fields as the chain field group on /l1/greeks, just flattened so you don't have to dedupe across strikes — plus a chain-only num_strikes column (the count of distinct listed strikes for that (root, expiry)).

Use it when you need term-structure inputs — building a forward curve, calibrating a model, or staging discounting factors — without paying for per-contract Greeks you'll throw away.

Parameters

Parameter Type Required Description
root list<string> one of {root, underlying} OCC root(s). Comma-separated for multiple.
underlying list<string> one of {root, underlying} Underlying ticker(s); expands to all matching roots (e.g. underlying=SPX returns SPX and SPXW).
format string no json (default), csv, ndjson, or html.

Output columns

underlying, root, expiry, und_price, forward, ex_style, settle, days, num_strikes, t, t_disc, rate, borrow, divs, ts

Same units and semantics as the chain field group — see the Field Reference. ts is the reprice wall-clock stamp (Response metadata), pinned rightmost.

Examples

GET /l1/chains?root=SPY
GET /l1/chains?root=SPY,QQQ,IWM
GET /l1/chains?underlying=SPX&format=csv

Sample response

[
  {
    "underlying": "SPY",
    "root": "SPY",
    "expiry": "2026-06-19",
    "und_price": 632.16,
    "forward": 631.38,
    "ex_style": "american",
    "settle": "pm",
    "days": 36.0,
    "num_strikes": 287,
    "t": 0.098630,
    "t_disc": 0.098630,
    "rate": 0.0432,
    "borrow": 0.0151,
    "divs": 1.49,
    "ts": "2026-05-12T13:04:02.595"
  }
]

Service liveness: /l1/health

GET /l1/health

A blended view of both layers in one round trip -- the Gateway running on your machine and the Lavender cloud it talks to. Use it as the canonical monitoring / liveness probe: startup readiness, retry-loop sanity, dashboard healthchecks.

Parameters

Parameter Type Required Description
format string no json (default), csv, ndjson, or html.

Output columns

Fields are emitted in the order shown below. time is always last.

Field Type Description
status string Roll-up: "ok" iff both gw_status and lav_status are "ok", otherwise "degraded".
gw_status string Gateway status. Always "ok" when this endpoint returns 200 (a Gateway that can't respond is its own unhealthy signal).
lav_status string Lavender cloud status. "ok", "unreachable", or an error string.
gw_version string Gateway version (e.g. 26.5.13.2).
lav_version string Lavender cloud version. "unknown" when lav_status is not "ok".
gw_uptime string Gateway uptime, e.g. 5h 2m.
lav_uptime string Lavender cloud uptime. "unknown" when lav_status is not "ok".
gw_memory_mb int Gateway memory footprint, MB.
lav_memory_mb int Lavender cloud memory footprint, MB. 0 when lav_status is not "ok".
time string Current ET wall clock, yyyy-MM-dd HH:mm:ss.

Sample response -- healthy

{
  "status": "ok",
  "gw_status": "ok",
  "lav_status": "ok",
  "gw_version": "26.5.13.2",
  "lav_version": "26.5.13.2",
  "gw_uptime": "5h 2m",
  "lav_uptime": "12h 18m",
  "gw_memory_mb": 142,
  "lav_memory_mb": 1837,
  "time": "2026-05-14 10:03:11"
}

Sample response -- degraded (cloud unreachable)

{
  "status": "degraded",
  "gw_status": "ok",
  "lav_status": "unreachable",
  "gw_version": "26.5.13.2",
  "lav_version": "unknown",
  "gw_uptime": "5h 2m",
  "lav_uptime": "unknown",
  "gw_memory_mb": 142,
  "lav_memory_mb": 0,
  "time": "2026-05-14 10:03:11"
}

A 200 with top-level status: "ok" is the green-light contract. A 200 with status: "degraded" means the Gateway is up but something on the Lavender cloud side needs attention -- inspect lav_status for the specific cause. Anything else (connection refused, 5xx) means the Gateway is not currently serving -- typically a brief mid-restart during the nightly 03:00-04:00 ET housekeeping window; retry after a few seconds.


See also

  • Field Reference — every L1 field with units, source, and example values
  • Greek Conventions — sign conventions, units, and the full extended Greeks catalog
  • Verify the Greeks — derive each Greek from first principles and check against the API