Skip to main content
The FMV1 Configuration API provides JSON-native endpoints for exporting and importing company configuration. This is the programmatic interface to the configuration pipeline. A new company starts from a complete configuration document posted to Import Configuration. For Quote–Policy mappings and JEXL transformations, see Conversion Rules.

Authentication

These endpoints require an API key that holds the configuration permissions. The Admin role holds them; a role without them returns 403.To create an API key with this role, go to Settings > API Keys and select the Admin role when generating the key.

Workflow

The JSON round-trip workflow is:
  1. Export — Pull current config as a structured JSON body
  2. Edit the JSON
  3. Import — Apply the edited JSON body to the database
export → edit → import is a lossless, machine-to-machine round-trip. For a fresh company, POST the complete initial document directly to Import. Rating workflow stages accept only stageType, raterSpec, callOncePerPath, outputPath, and optional inputs. Validation rejects unknown stage properties with the affected stage’s JSON path, so a misspelled property cannot silently discard input selection or output routing.

API Endpoints

The Configuration Management endpoints are listed in the left navigation:
  • Export Configuration (POST /configuration/export) — Return current config as a structured JSON body. The output is the exact shape import accepts, so export → edit → import is a lossless round-trip.
  • Get Configuration Metadata (POST /configuration/metadata) — Return a stable config version token plus last-modified / last-imported timestamps, without the full config body. Use it for cheap staleness checks before pulling the full export payload.
  • Import Configuration (POST /configuration/import) — Apply a structured JSON configuration body to the database.
  • Start Data Validation Run (POST /configuration/data-validation-runs) — Start a background scan that classifies every stored record against a configuration. Send a complete configuration body to scan a candidate, or send no body at all to scan the live configuration. Returns a runId to poll.
  • Get Data Validation Run (GET /configuration/data-validation-runs/{runId}) — Poll a run’s status and its running counts of records scanned, adhering, holding undeclared keys, and breaking.
  • List Data Validation Run Findings (GET /configuration/data-validation-runs/{runId}/findings) — Page through which records would not survive the scanned configuration and why. Paginated (page / pageSize) because a poll must not re-transfer thousands of findings; filter with entityType to build a per-type view.

Field type declarations

Full configuration imports, validation and comparison accept a field’s structured typeInfo without duplicate type or typeArgs properties. The add-field patch change accepts the same declaration, including when adding a custom-object subfield:
For a full configuration field, use entitySelector instead of entity and omit kind: "add-field". Argless types need only their kind, such as "typeInfo": { "kind": "Text" }. Existing type and JSON-string typeArgs inputs remain accepted. When you send both forms, they must describe the same type and arguments; conflicts identify the field in the error. Configuration exports declare each field type once in typeInfo, without type or typeArgs duplicates. Field values and cardinality rules are unchanged.

Checking configuration against stored data

Validate and compare are configuration-only: neither reads a single stored record, which is why both answer instantly regardless of how much data a company holds. They tell you a configuration is well-formed and how it differs from the current one — not whether the records you already have would survive it. Data validation runs answer that second question. A run reads every stored record of every entity type and classifies each one, so the natural order before a risky import is: validate (is the config well-formed?) → compare (what changes?) → a run (which of my records would break?) → import. Four properties are worth knowing before you build against it:
  • A run snapshots its configuration when it starts, so a verdict cannot drift — an import that lands mid-scan does not change what the scan is measuring against.
  • Starts collapse and are capped. Starting a run whose configuration matches one already in flight returns that run’s id with outcome: "duplicate" instead of starting a second scan (pass ?force=true to override). A company may have 3 runs in flight; a 4th distinct configuration is refused with a 429 carrying inFlightRunIds so you can poll those instead.
  • The counts and the detail are separate reads. The poll is fixed-size — status plus four counts — and findings is a separate, paginated endpoint, so polling a run costs the same whether the book is clean or badly broken. Poll until the run is terminal, then page the findings once.
  • A run’s status and findings stay readable for as long as the run exists. Nothing removes a run or its findings on a timer, so a run started months ago still answers in full. A run’s age is never a failure on either by-id read: neither reports a run as too old to read, and a run id that belongs to no run of this company is a 404.

Permissions


Framework-Required Rows

Some configuration rows are required by the framework: the import rejects a configuration that omits them or changes their type, cardinality, or join shape. Most framework-required rows also have a fixed calculated value the import enforces byte-for-byte, but a few are flagged customer-supplied: the row’s presence and shape are enforced, while its JEXL calculated-value expression is yours to author and maintain. The main example is referencedExposures on Quote, Policy, and Submission.

Configuration Categories

The compare endpoint returns change counts for each category: