V1 API Changelog
Track changes, additions, and deprecations to the V1 API.2026-06-16
Documentation: accuracy reset across the API reference
The API reference was audited end-to-end against the live route surface and corrected so every documented endpoint, schema, status code, and permission matches what the API does today. No runtime behaviour changed — these are documentation corrections only.- Removed phantom endpoint groups. Three capability groups that had never shipped as endpoints (
resolve-address/ Address Tools, Event Financials, and quote send) were removed from the spec; they were never callable. - Corrected every endpoint’s schema, examples, status codes, and permissions to match the implementation, including the bare (un-prefixed) permission strings that the authorization guard actually checks:
insured:update/insured:deletefor the Exposure update/delete,policy:updatefor the policy cancel/endorse/reinstate transactions, andpolicy:deletefor transaction delete. Create/read operations keep theircompany.-prefixed permissions. The Event configuration endpoint requirescompany.event:export. - Raw
Authorizationheader. External API authentication takes your API key as the rawAuthorizationheader value with no scheme prefix — notBearerand notApiKey, and neverX-API-Key. See Generating API Keys. - Narrative pages reconciled. The overview, roadmap, getting-started, object-primitives, and data-models pages were corrected: Submissions, Persons/Organizations, Notes, Tasks, and Company Files are documented as available today (not “planned”); the unified entity envelope (
fieldModelV1Datawith epoch-secondcreatedAt/updatedAt, no top-levelcompanyId) and its{ items, hasMore, totalCount }/ zero-basedpageNumberlist shape are documented accurately; and broken internal links were repaired.
2026-06-11
Added: per-placement organize — move/categorize a shared file under one entity
folderId and category are per-placement attributes, so the owner-less PATCH /files/{fileId} cannot address them once a file is shared (its 409 Conflict below). The new placement update lifts that limitation:
PATCH /api/v1/external/companies/{companyId}/files/{fileId}/placements/{placementId}— update ONE placement’sfolderId(a folder of the placement’s owner, ornullfor the owner’s top level) and/orcategory(free-text ≤255 chars, ornullto clear). Absent fields are untouched; at least one must be present. Returns200 { placementId, fileId, entityType, entityId, folderId, category }; the file’s other placements are never affected. Placement ids come fromGET /files/{fileId}/placementsor the share response. Requirescompany.file:update.- The
409 Conflictbody returned byPATCH /files/{fileId}forfolderId/categoryon a shared file now points at the placement endpoint:File has multiple placements: {fileId}. Update one placement instead: PATCH /files/{fileId}/placements/{placementId} (enumerate them with GET /files/{fileId}/placements). Single-placement files are unaffected — either endpoint works there.
Added: file placements — share one file across entities
A file can now be placed on more than one entity at a time. Sharing adds a placement — never a copy: the bytes are stored once and every placement sees the same current version and history. Folder location andcategory are per placement; displayName stays on the file. Sharing is same-company only.
GET /api/v1/external/companies/{companyId}/files/{fileId}/placements— list everywhere a file appears ([{ placementId, entityType, entityId, entityDisplayName, folderId, category, createdAt }]). Requirescompany.file:read.POST /api/v1/external/companies/{companyId}/files/{fileId}/placements— share the file to another owner (entityType,entityId?, optionalfolderIdof the target owner). Returns201 { placementId, fileId, entityType, entityId, folderId }; a duplicate share to the same owner is409 Conflict. Requirescompany.file:create.DELETE /api/v1/external/companies/{companyId}/files/{fileId}/placements/{placementId}— remove the file from ONE owner. While other placements remain, the file and its content are untouched; removing the last placement deletes the file and reclaims storage (fileDeleted: true). Requirescompany.file:delete.- The file responses now carry placement information: list items gained
placementIdandplacementCount;GET /files/{fileId}gainedplacementCount, and its owner fields (entityType/entityId/folderId/category) now describe the file’s primary (oldest) placement. PATCH /files/{fileId}on a shared file can only changedisplayName; an owner-lessfolderId/categoryupdate is ambiguous across placements and returns409 Conflict. Single-placement files behave exactly as before.DELETE /files/{fileId}removes the file everywhere (all placements) — unchanged for single-placement files; use the placements endpoint for per-entity removal.
2026-06-10
Added: file categories
Files can now carry a free-textcategory label (max 255 characters). There is no configured category list — any non-blank string is a valid category.
PATCH /api/v1/external/companies/{companyId}/files/{fileId}accepts an optionalcategoryfield alongsidedisplayName/folderId: a string sets the label, an explicitnullclears it, and an absent field leaves it untouched.- The file responses (
GET /files/{fileId}metadata and theGET /fileslist items) already includecategory(nullwhen unset).
Breaking: Company Files API rebuilt on signed URLs
The Company Files API was rebuilt end-to-end. File bytes no longer travel through the API — uploads and downloads now go straight to cloud storage via short-lived signed URLs, and every request/response shape changed. There is no compatibility mode for the old contract. See the Company Files overview for the new workflow.- Upload is now a two-phase handshake.
POST /api/v1/external/companies/{companyId}/filesno longer acceptsmultipart/form-data; it takes a JSON upload intent (entityType,entityId?,folderId?,fileName,contentType,byteSize) and returns201 { fileId, versionId, uploadUrl }. PUT the bytes touploadUrl(pinned to the declared content type and byte size, 15-minute expiry), thenPOST /files/{fileId}/finalizewith theversionIdto make the file visible. - Files and folders are now owner-scoped. Every file/folder belongs to a configured entity (
entityType+entityId) or the company level (entityType: "company"). The folder endpoints keep their five paths but now require the owner on create/tree and return new shapes;GET /foldersreturns the owner’s whole tree as{ folders: [{ id, parentFolderId, name }] }(no pagination), andGET /folders/{folderId}returns{ folder, folders, files, totalCount }instead of the mixedcontentType-discriminated item list. GET /files/{fileId}returns the new metadata shape —displayName/fileName/contentType/byteSize/status/folderId/category/createdAt/updatedAt/uploadedAt/uploadedByreplace the legacyname/mimeType/entityName/userDatefields.PATCH /files/{fileId}renames withdisplayName(wasname) and/or moves withfolderId; it returns{ id }(was the full file).PATCH /folders/{folderId}keepsname/parentFolderIdbut returns{ id }; reparenting is cycle-checked.DELETE /folders/{folderId}now reports the cascade:{ id, deleted, deletedFolders, deletedFiles }.
Removed: binary download and multipart upload
GET /api/v1/external/companies/{companyId}/files/{fileId}/content(binary stream) is removed — use the newGET /files/{fileId}/download-url, which returns{ url, expiresAt, fileName, contentType, byteSize }(requires the newcompany.file:downloadpermission), and fetch the bytes from the signedurl.- The
multipart/form-dataupload body is removed — see the upload handshake above.
Added: list files
GET /api/v1/external/companies/{companyId}/files— list an owner’s files (entityType,entityId?, optionalfolderIdplacement filter, 1-basedpage/pageSize). Previously files were only discoverable through folder contents. Requirescompany.file:read.POST /api/v1/external/companies/{companyId}/files/{fileId}/finalizeandGET /api/v1/external/companies/{companyId}/files/{fileId}/download-url— the new halves of the signed-URL upload/download workflow.
2026-06-07
Removed: QuoteBindError object primitive
The Object: QuoteBindError object primitive (and its Fmv1QuoteBindError OpenAPI schema) has been removed. It was never produced at runtime — no endpoint ever returned or accepted a quoteBindErrors value — so this removal is not expected to affect any integration. The four remaining object primitives (Address, CoverageLimit, Currency, Date) are unchanged. See the Object Primitives reference.
2026-06-01
Added: Notes endpoints
Notes can now be managed via the external API. Notes are simple text records attached to a top-level Field Model V1 entity (Event, Exposure, Quote, Submission, Person, Organization, Policy). The parent entity type travels as the entityType query parameter on every verb; permission is gated by the parent entity (read for GET, update for write).
GET /api/v1/external/companies/{companyId}/notes— List notes for a parent entity (1-basedpage/pageSize)POST /api/v1/external/companies/{companyId}/notes— Create a note (returns{ id }, HTTP 201)GET /api/v1/external/companies/{companyId}/notes/{noteId}— Get a notePATCH /api/v1/external/companies/{companyId}/notes/{noteId}— Update a note’s bodyDELETE /api/v1/external/companies/{companyId}/notes/{noteId}— Soft-delete a note
New: Tasks API
Added 5 endpoints for managing company tasks at/api/v1/external/companies/{companyId}/tasks:
GET /tasks— List tasks (paginated, filter bystatus,assigneeId,entityType,entityId). Requirescompany.task:read.POST /tasks— Create a task. Returns{ id }. Requirescompany.task:create.GET /tasks/{taskId}— Get a single task. Requirescompany.task:read.PATCH /tasks/{taskId}— Partial update (only changed fields; unknown fields rejected). Requirescompany.task:update.DELETE /tasks/{taskId}— Soft delete. Returns{ id, deleted: true }. Requirescompany.task:delete.
name, description, status (Not Complete / Complete), ISO 8601 deadline, optional linked entity snapshot ({ type, id, name }), and assignees (company user IDs — non-members are rejected with 400). See the Tasks overview.
Breaking: Full-term policy transaction reshape
The segmented Policy Transaction API moved to the full-term (“Model-B”) design. Affectsnew-business, endorse, cancel, reinstate, and renew.
- Term bounds come solely from
fullTermPolicyInfo.policyStartDate/policyEndDateare read fromfieldModelV1Data.policy.fullTermPolicyInfoon NEW_BUSINESS / RENEW — the top-levelpolicyStartDate/policyEndDate(and RENEW’s top-levelpreviousPolicyId/newPolicyStartDate/newPolicyEndDate) parameters are removed.previousPolicyIdnow lives infullTermPolicyInfo. fullTermPolicyBillingrenamed tofullTermPolicyBillingInfoin every request, response, and bordereau column path.policyStatusis a segment-scoped policy field with lowercase values"active"/"cancelled"— no longer insidefullTermPolicyInfo.- ENDORSE now has five channels:
deltasXORfullTermDeltas(the latter restricted topolicy.fullTermPolicyInfo, no dates), plus additivefullTermPolicyBillingInfo,fullTermPolicyRatingResult, andcrossSegmentRatingOutputs. List elements are addressed by predicate —exposures[id = '…']. - CANCEL / REINSTATE take the date plus optional whole-object
fullTermPolicyBillingInfo/fullTermPolicyRatingResult. CANCEL flips per-segmentpolicyStatusto"cancelled"and records a singlecancellationEffectiveOnDate(uniform across the term); REINSTATE flipspolicyStatusback to"active"and clearscancellationEffectiveOnDate(no reinstatement date field). A reinstate that would leave a coverage gap is rejected — that scenario is a new policy term.policyEarlyTerminationDateis removed. - Rating output split into
fullTermPolicyRatingResult(policy-root, hoisted) andcrossSegmentRatingOutputs(element-level, inline). Responses hoistfullTermPolicyInfo,fullTermPolicyBillingInfo, andfullTermPolicyRatingResult.
2026-05-15
New: Company Files API (folders + files)
Added 10 endpoints for managing company-level folders and files: Folders:POST, GET, GET /{folderId}, PATCH /{folderId}, DELETE /{folderId} under /api/v1/external/companies/{companyId}/folders
Files: POST (multipart upload), GET /{fileId}, GET /{fileId}/content (binary download), PATCH /{fileId}, DELETE /{fileId} under /api/v1/external/companies/{companyId}/files
Key capabilities:
- Create nested folder hierarchies with
parentFolderId - Upload files via
multipart/form-data, optionally placing them in a folder - Stream binary file content with correct
Content-TypeandContent-Dispositionheaders - Rename and move files/folders (including moving to root by setting parent to
null) - Recursive soft-delete of folders (deletes all contents)
company.file:{action} permissions. See the Company Files overview for details.
These are company-level file endpoints only. Entity-scoped file endpoints (attached to exposures, policies, events) are planned for a future release.
2026-05-01
Event→Policy relationship migrated to eventPolicy Join field (additive)
Event responses now surface the associated policy in two places: the existing
top-level policyId and the new eventPolicy key inside fieldModelV1Data.
Both reflect the same value — policyId stays at the top level for backwards
compatibility, while eventPolicy is the underlying Join: Policy field
where the value is stored.
What changed:
GET /api/v1/external/companies/{companyId}/eventsand/events/{eventId}responses includeeventPolicyinsidefieldModelV1Dataalongside the pre-existing top-levelpolicyId. No fields were removed.POSTandPUTevent endpoints continue to acceptpolicyIdas a top-level request param. The server maps it tofieldModelV1Data.eventPolicyinternally; clients that already submitpolicyIdneed no changes.policyIdis no longer stored on a dedicatedevents.policy_idcolumn on the FMV1 read/write paths — it now lives infieldModelV1Data.eventPolicy, consistent with howeventInsuredswas migrated previously. The external API contract is unchanged for existing integrators.
eventPolicy and
continue using policyId, or migrate to reading the value from
fieldModelV1Data.eventPolicy to align with the rest of the field model.
Address.zipCode must be a JSON string (breaking)
Address object-primitive writes that send zipCode as a JSON number are now rejected with 400 and problemCode: "InvalidAddressZipCode". Previously, numeric ZIPs were accepted by the API but silently lost their leading zeros — 02140 parses as 2140, corrupting the stored address.
Affected endpoints: every FMV1 create/update endpoint that can carry an Address value (top-level field or nested inside a custom object), including all exposure, event, quote, policy-transaction, and custom-object writes.
What to send: quote ZIP codes in your payload — "zipCode": "02140", never "zipCode": 02140. The Address sub-field reference and the Fmv1Address OpenAPI schema both call this out explicitly.
Why this is most likely to bite:
- Spreadsheets (Excel / Google Sheets) auto-coerce ZIP-shaped cells to numbers — export as text or wrap in
=TEXT(...)before serializing. - OpenAPI clients / codegen that infer the
zipCodeJSON type from a sample value rather than the schema (which has always beentype: string). - LLM-generated requests that “helpfully” unquote numeric-looking strings.
2026-04-29
Documentation: Object Primitives
- New Object Primitives reference page documenting the five FMV1 built-in object shapes (
Address,CoverageLimit,Currency,Date,QuoteBindError) — sub-field tables, JSON examples, the strict-completeness rule, and List cardinality. - OpenAPI spec now exports reusable
Fmv1Address,Fmv1CoverageLimit,Fmv1Currency,Fmv1Date, andFmv1QuoteBindErrorschemas undercomponents.schemasfor client-codegen consumers. Schemas mark every sub-field asrequired.
2026-04-28
Strict object-primitive sub-field validation (breaking)
When a request body for an FMV1 create/update endpoint includes an object-primitive value (Address, CoverageLimit, Currency, Date, QuoteBindError), every declared sub-field must now be present and non-empty. Affected endpoints:
POST/PATCH /api/v1/external/companies/{companyId}/exposuresand/exposures/{id}POST/PATCH /api/v1/external/companies/{companyId}/eventsand/events/{id}POST/PATCH /api/v1/external/companies/{companyId}/quotesand/quotes/{id}- All segmented policy transaction endpoints (
new-business,endorse,renew) POST/PATCH /api/v1/external/companies/{companyId}/custom-objects/{objectType}and/{objectId}
- A
null,undefined, or empty-string ("") sub-field on a present object-primitive value now returns400withField '<parentField>' is missing required sub-field '<refId>'. Previously, partial object primitives were silently accepted and surfaced as confusing rating errors downstream. The most common case isAddresswithoutcounty— ensure upstream data includes a county before submitting. - Numeric
0(e.g.Currency.value: 0) and Booleanfalseare still valid — the rule only treatsnull/undefined/""as missing. - Whitespace-only strings (e.g.
" ") are NOT treated as missing by this validator. A consumer sendingcounty: " "will pass this check; downstream rating may still reject it. Trim/normalize sub-field strings client-side before submitting. - Custom-object sub-fields keep their existing
requiredConditionrules unchanged. - Omitting the parent object-primitive field entirely is unchanged — the strict rule only fires when the parent value is provided.
