OpenAPI Specification
The DerivFabric REST API ships a complete, machine-readable OpenAPI document. It is the contract, served as a static file alongside this documentation.
Where the spec is
/api/openapi.yaml
Fetch it from this documentation site — the path is relative to wherever these pages are served, so it works on your deployment without knowing its hostname:
# From the host serving these docs.
curl -O https://<your-docs-host>/api/openapi.yaml
Set that host once and the commands below all reuse it:
export DERIVFABRIC_DOCS_URL=https://<your-docs-host>
It is also rendered interactively at /swagger, with
try-it-out enabled, pointed at this same document.
Identity
| OpenAPI version | 3.1.0 |
| Title | DerivFabric API |
| API version | 0.1.0 |
| Licence | MIT |
| Operations | 140 |
The servers: block declares local development targets. Point a generated
client at your own deployment's base URL — DerivFabric is deployed per
customer, so the spec's entries are conveniences, not the product's address.
Every response is wrapped
This is the single most important thing to know before generating a client.
Each operation's documented response schema describes the payload, not the bytes on the wire. The wire response is always the envelope:
{
"success": true,
"data": { },
"meta": { "manifest": { } },
"correlation_id": "019fd7c6-3b1a-7c4e-9f2d-8e5a1b0c4d7e",
"correlationId": "019fd7c6-3b1a-7c4e-9f2d-8e5a1b0c4d7e",
"timestamp": "2026-08-20T09:00:00Z"
}
dataholds the schema the operation documents. It is absent on failure.metais present only when an operation attaches provenance. A priced number carries its run manifest undermeta.manifest.- On failure,
successisfalse,datais absent, anderrorholds{ code, message }. The code is stable and machine-readable; the message is for a human and may change. success, the correlation id andtimestampare always present.
The shape is stated machine-readably as the ApiEnvelope schema in
components/schemas, with the failure half as ApiError. Individual
operations deliberately do not $ref it — 140 hand-written wrappers would be
140 places for the convention to drift — so a generated client needs the
envelope applied once, at the transport layer, rather than per method.
The correlation id has two spellings
The server emits the correlation id under both correlation_id and
correlationId, carrying the same value in the same response. Either is safe
to read.
The spec documents the camelCase name as the contract, and that is the one to prefer in new integrations. The snake_case name is emitted alongside it because the server shipped that spelling first and live integrations read it. Both are serialized from a single field, so they cannot disagree.
Quote either one in a support request — they identify the same call.
Two things the envelope is not
-
/api/v1/validation/reportreturns a document, not an envelope. It renders Markdown, HTML or JSON according to itsformatquery parameter, and the rendered body is the response. Errors on that endpoint still arrive as envelopes, so error handling is unchanged. -
202 Acceptedis a success. Job submission returns 202 withdatapopulated andsuccesstrue. A client that treats any status at or above 300 as a failure without readingsuccesswill break on job submission.
Authentication
The spec declares one security scheme:
ApiKeyAuth:
type: apiKey
in: header
name: X-API-Key
Security is declared globally rather than repeated per path, so a newly added endpoint is authenticated by default.
Exactly one operation opts out: GET /health, which sets security: [].
It is a liveness probe, and a load balancer should not need a tenant key.
/metrics is not an exception — it shares the Health tag but inherits the
global requirement, because a public metrics endpoint would publish request
volume, error rates and pricer usage to anyone who can reach the API.
Keys carry scopes — price, calibrate, portfolio, xva, jobs,
governance, validate and admin. admin satisfies any scope requirement;
there is no wildcard. Two authorization failures are reported distinctly
because they need different remedies: a missing scope (DF-AUTH-004) is fixed
by issuing a key that carries it, an insufficient tier (DF-AUTH-005) by
changing plan.
Tags
All 140 operations carry exactly one tag from this list.
| Tag | Operations | Covers |
|---|---|---|
| Health | 2 | Liveness and build identity. |
| Pricing | 1 | The generic engine entry point; names the pricer explicitly. |
| Vanilla | 5 | European and binary options. |
| American | 1 | Early-exercisable options, on the numerical engine. |
| Convertible | 1 | Convertible bonds. |
| Structured Products | 2 | Notes and autocallables built from a payoff description. |
| Contract DSL | 4 | Contracts written in the algebra rather than chosen from a catalogue. |
| Portfolio | 8 | Stateless calculation over a portfolio supplied in the request. |
| Portfolios | 6 | Portfolios held by the tenant, and the positions in them. |
| Risk | 8 | Value at risk, stress and sensitivity analysis. |
| XVA | 3 | Valuation adjustments — CVA, DVA, FVA. |
| Hedging | 1 | Hedge construction and optimisation. |
| Calibration | 3 | Fitting model parameters to market quotes. |
| Market Data | 25 | Curves, surfaces, snapshots, reference instruments and connectors. |
| Counterparties | 19 | Counterparties, netting sets, collateral terms and credit data. |
| Trades | 5 | Trade capture and lifecycle. |
| Products | 16 | Product families, templates, versions and conventions. |
| Governance | 10 | Capabilities, entitlements, approvals and the audit trail. |
| Validation | 3 | Model validation runs and their reports. |
| Jobs | 3 | Asynchronous work; submission returns 202 with a job id. |
| Artifacts | 4 | Files a tenant has stored against its work. |
| Studio | 10 | Endpoints backing the Studio client specifically. |
Portfolio calculates over a portfolio supplied inline in the request; Portfolios manages the stored kind.
A representative operation
POST /api/v1/price — operation id priceOption, tagged Vanilla.
{
"spot": 100,
"strike": 100,
"rate": 0.05,
"dividend": 0.0,
"volatility": 0.20,
"time": 1.0,
"optionType": "call"
}
spot, strike, rate, volatility and time are required. dividend is
a continuous dividend yield defaulting to 0; optionType is call or
put, defaulting to call; time is in years and rate is continuously
compounded.
The documented 200 schema is PriceResponse — price, spot, strike,
optionType. Remember the envelope: that schema is what arrives inside
data, and a priced number attaches its run manifest under meta.manifest.
Model parameters
Nine pricers need model parameters — SABR wants its α, β, ρ and ν, Hull-White
its mean reversion, Dupire a local volatility surface. Every other capability
takes what it needs from the instrument and the market snapshot, and rejects a
non-empty params rather than ignoring it.
The params field on POST /api/v1/engine/price is a oneOf over nine
schemas, selected by pricerId. Each names its pricer, so a generated client
gets the field names typed rather than a bare object:
| Schema | Pricer |
|---|---|
BinomialParams | binomial_tree |
HestonFftParams | equity_vanilla_heston_fft |
DupireParams | equity_local_vol_dupire |
SabrHaganParams | equity_vanilla_sabr_hagan |
HullWhiteAnalyticParams | rates_bond_option_hull_white |
RoughBergomiParams | equity_rough_bergomi_mc |
RoughHestonParams | equity_rough_heston_mc |
JarrowYildirimParams | inflation_yoy_jy |
Lg2fParams | rates_swaption_lg2f |
These objects carry no defaults, so an unrecognised field name is a 400 rather
than a silently substituted value. BinomialParams is the exception: omit
params entirely and it uses 200 Cox-Ross-Rubinstein steps.
A CI gate compares each schema's properties against the struct the engine deserialises into, in both directions — a documented field the engine does not accept fails the build, and so does an engine field the spec omits.
Using the spec
Generate a client
Every generator below reads the spec straight from the URL.
npx @openapitools/openapi-generator-cli generate \
-i $DERIVFABRIC_DOCS_URL/api/openapi.yaml \
-g typescript-fetch \
-o ./derivfabric-client
go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@latest \
-generate types,client \
-package derivfabric \
-o derivfabric.gen.go \
$DERIVFABRIC_DOCS_URL/api/openapi.yaml
npx openapi-typescript $DERIVFABRIC_DOCS_URL/api/openapi.yaml -o derivfabric.d.ts
Whichever you choose, wrap the generated calls in one thin layer that unwraps
data, surfaces error and records the correlation id — the generated
response types describe the payload, not the envelope.
Import into a client tool
Postman — Import → Link, paste your docs host's /api/openapi.yaml.
The 140 operations arrive grouped by tag. Add a collection-level X-API-Key
header so every request inherits it.
Insomnia — Create → Import From → URL, same address.
View it
Already hosted at /swagger. To render it yourself:
npx @redocly/cli preview-docs $DERIVFABRIC_DOCS_URL/api/openapi.yaml
npx @redocly/cli lint $DERIVFABRIC_DOCS_URL/api/openapi.yaml
The spec is CI-gated
The document is hand-maintained, so automated gates hold it to the running service on every change. What they do and do not cover matters more than the reassurance:
Enforced — the endpoint list matches the router. A build-blocking test compares every public REST path in the spec against the paths the service registers, in both directions: an endpoint that is live but undocumented fails, and one documented but not served fails. A small list of deliberate exclusions is itself checked for staleness, so an exemption cannot outlive the route it was written for.
Enforced — the envelope stays uniform. A second suite checks that
ApiEnvelope and ApiError exist, that the envelope's documented properties
match the fields the server serializes, that the required fields are exactly
the three always present, that no operation documents the wrapper in place of
its payload, that the tag vocabulary is closed, that every $ref resolves,
and that every success response declares a media type.
Enforced — the document is valid. The spec runs through a full OpenAPI validator in CI, not merely a YAML parse.
Reported, not enforced — breaking changes. Every pull request is diffed against the base branch and anything affecting an existing client is surfaced for a reviewer. It does not block: a breaking change is sometimes the correct change. The gate guarantees nobody makes one by accident.
What is not checked. Field-level agreement between a documented schema and the server's own types. The path gates catch an endpoint appearing or vanishing; they say nothing about a renamed field. So a passing build means no endpoint is missing or invented and the envelope convention holds — it does not mean every field is right.