Skip to main content
Object primitives are the five built-in object shapes that FMV1 fields can be typed as. Unlike custom objects (which you define in your configuration), object primitives have a fixed structure across every company and are recognized natively by the rating engine and snapshots. You will encounter object primitives whenever a field’s fieldType in your configuration is one of:
  • Object: Address
  • Object: AddressV2
  • Object: Currency
  • Object: Date
  • Object: StringOrNumber
Address and AddressV2 are two different shapes, and both are live. AddressV2 is the successor to Address; it renames and re-nests the sub-fields, so a payload written for one is not valid for the other. Companies are migrated field by field, so a single company can have some address fields on each.Which shape a field uses is decided by that field’s configured type, not by the endpoint. Read the field’s fieldType (or typeInfo.kind) from GET /api/v1/companies/{companyId}/entities/{entityType}/configuration rather than assuming — Object: Address means the flat shape, Object: AddressV2 means the nested one.
NumberLimit is not an object primitive — it is a custom object. A common point of confusion: coverage limits in the default tenant configuration are modelled as a NumberLimit custom object ({ numberLimitName, numberLimitAmount }), with Coverage.coverageLimits typed as a list of them. Its keys and requiredness come from the tenant configuration, not from the framework, so it is documented as a custom-object example (see the Fmv1NumberLimit schema), not on this page. There is no built-in CoverageLimit primitive.

Required-completeness rule

If an object-primitive field is provided in a create/update payload, its required sub-fields (listed per primitive below) must each be present and non-empty. A missing required sub-field is rejected with HTTP 400 and a problem code naming the offending sub-field:
Requiredness is per-primitive, not blanket. Each primitive marks some sub-fields required and leaves others optional (an inactive StringOrNumber slot, a Date without a timezone, a partial Address). The required set is listed in each primitive’s section below — only those sub-fields fire the rule. The rule only fires when the parent field is provided. Omitting the field entirely is unchanged — object-primitive fields can still be optional at the field-definition level. What counts as missing: null, undefined, or empty string (""). Numeric 0 and Boolean false are valid values. Whitespace-only strings (e.g. " ") currently slip past this validator — trim sub-field strings client-side before submitting. Custom objects keep their own rules. Sub-fields of a custom object (including NumberLimit) follow each sub-field’s own requiredCondition from your configuration; only object primitives’ required sub-fields are strict-by-default. This rule applies to every FMV1 external write endpoint:
  • POST exposures, events, quotes
  • All segmented policy transactions (new-business, endorse, renew)
  • POST custom objects (including an object-primitive sub-field nested inside a custom object)

Address

Structured postal address as a single flat set of components. Used wherever a property, mailing, or risk location appears in your field model. This is the legacy address primitive — see AddressV2 for its successor. Address stays fully supported for every field still typed Object: Address. Required sub-fields: none. A partial address (e.g. street + city, no county) is valid — Address sub-fields are all optional, so the required-completeness rule never fires for Address. (Whether an address must exist at all is governed by the embedding field’s own required condition.)
zipCode must be a JSON string, never a number. JSON numbers cannot represent leading zeros — 02140 parses as 2140, silently corrupting the ZIP. The API rejects numeric zipCode values with 400:
This is the most common failure when payloads are generated from spreadsheets, OpenAPI codegen with the wrong type, or LLMs that “helpfully” unquote numeric-looking strings — always quote ZIP codes in your payload.

AddressV2

The successor to Address. A postal address modelled as an authoritative entered address plus an optional geocode computed from it. AddressV2 is not a superset of Address — the sub-fields are renamed and re-nested. A payload written for Address is not a valid AddressV2, and vice versa. Check the field’s configured type before writing it; see the warning at the top of this page. Read one half or the other, never a blend. enteredAddress is what a person typed or confirmed, and is the half to render as the address. geocode carries provider output only — county, coordinates, precision. There is deliberately no county in enteredAddress and no street text in geocode. Required sub-fields: none at the top level; all three are optional, as is every sub-field of enteredAddress. The one requiredness rule sits inside geocode: if you send a geocode object at all, status and source must both be present and non-empty.

enteredAddress

There is no county here. County is provider output and lives on geocode.

geocode

Never typed or edited by a user. null when no geocode has been recorded. granularity, most precise first:

Writing an AddressV2 field

Send enteredAddress. The platform geocodes server-side on save and fills geocode for you:
Reading the same field back returns the geocode alongside it:
Four behaviours worth knowing before you write one:
  • Geocoding never gates the write. A provider miss or outage is recorded as an "unmatched" or "failed" geocode, not a 4xx or 5xx on your save.
  • You can supply your own geocode. Send it with source: "provided" and it is stored as given, with no provider lookup. A geocode sent with any other source is discarded and replaced by the platform’s own result.
  • An unchanged entered address keeps its geocode verbatim. address2 is excluded from the components the geocode is computed from, so adding a suite number to an already-matched address does not re-geocode it or lose its match.
  • Only top-level AddressV2 fields are geocoded on save. An AddressV2 value nested inside a custom object is stored as you send it.
zipCode must be a JSON string, never a number — same reason as on Address. JSON numbers cannot represent leading zeros, so 02140 parses as 2140 and silently corrupts the ZIP. On AddressV2 the path is enteredAddress.zipCode, and a numeric value is rejected with 400 as an ordinary shape violation:

Currency

A monetary value with its currency code. Required sub-fields: value. code is optional.

Date

A calendar date with an optional timezone, stored in the canonical DMY form. Required sub-fields (DMY shape): day, month, year. timezone is optional — persisted dates may lack one. The API accepts two input shapes for a generic Date field:
You may also submit the ISO envelope form — the API canonicalizes it to the DMY form before storage. In this shape timezone is required (it has no DMY fields to fall back on):
Both shapes are accepted on every FMV1 write path — entity CRUD (exposures, events, quotes, custom objects) and policy transactions alike (#2503). Responses always use the DMY form. The policy term dates are no exception: the root policyStartDate / policyEndDate on policy transactions are ordinary Date fields and take either shape. (They additionally still accept a full ISO 8601 string carrying a UTC offset — e.g. "2026-03-15T00:00:00-05:00" — as backward compatibility for existing clients.) See the policy transaction endpoints.

StringOrNumber

A discriminated value that is either a string or a number, chosen per-row. The two typed slots are mutually exclusive — the inactive one is null. Required sub-fields: kind. The text / number slots are optional (the inactive slot is null).

Cardinality

Any of these object primitives can appear as a single value or as a list, depending on how the field is configured. List-cardinality fields enforce the same per-primitive required-completeness rule per array element — each item must satisfy its primitive’s required sub-fields.

  • V1 API Changelog — the strict-validation rule was rolled out on 2026-04-28 and corrected to per-primitive requiredness on 2026-06-26.