Dalinea API
v1.0.0 ExternalUnified API for the Dalinea platform. All endpoints require a valid JWT bearer token. Tenant isolation is enforced via the x-tenant-id header extracted from the token.
Getting Started
Welcome to the Dalinea API. This guide covers the basics of making requests and understanding responses.
Base URL
All API requests are made to:
https://api.kloopify.com
Request Format
The API accepts JSON request bodies and returns JSON responses. Set the following headers on every request:
Content-Type: application/json
Authorization: Bearer <your-token>
Response Format
Successful responses return a 2xx status code with a JSON body. Error responses include a message describing the issue:
{
"statusCode": 400,
"message": "Validation failed",
"error": "Bad Request"
}
Pagination
List endpoints support pagination via offset and limit query parameters:
| Parameter | Default | Description |
|---|---|---|
offset |
0 | Number of records to skip |
limit |
100 | Number of records to return (max 100) |
Rate Limiting
API requests are rate-limited per account. If you exceed the limit, you'll receive a 429 Too Many Requests response. Back off and retry after the duration indicated in the Retry-After header.
Authentication
The Dalinea API uses JWT Bearer tokens for authentication. Every request must include a valid token in the Authorization header.
Obtaining a Token
Tokens are issued by our identity provider. Authenticate with your credentials to receive an access token:
POST https://auth.kloopify.com/oauth/token
Content-Type: application/json
{
"client_id": "<your-client-id>",
"client_secret": "<your-client-secret>",
"audience": "https://api.kloopify.com",
"grant_type": "client_credentials"
}
The response includes an access_token and its expiry:
{
"access_token": "eyJhbGciOiJSUzI1NiIs...",
"token_type": "Bearer",
"expires_in": 86400
}
Using the Token
Include the token in the Authorization header of every API request:
Authorization: Bearer eyJhbGciOiJSUzI1NiIs...
Token Expiry
Tokens expire after the duration specified in expires_in (in seconds). When a token expires, the API returns 401 Unauthorized. Request a new token and retry.
Scopes
Access is controlled by scopes embedded in the token. If your token lacks the required scope for an endpoint, the API returns 403 Forbidden.
Running a Cost Analysis
This guide walks through submitting a cost analysis job, tracking its progress, and retrieving the results.
Overview
A cost analysis is an asynchronous operation. You submit a request describing a product and its manufacturer, the system processes it in the background, and you poll for the result. Once complete, the result contains IDs you can use to fetch the full cost analysis, bill of materials, product, and manufacturer records.
Step 1: Submit the Job
Create a cost analysis by posting to the pipeline endpoint:
POST /pipeline/cost-analysis
Content-Type: application/json
Authorization: Bearer <your-token>
{
"productName": "EcoBottle 500ml",
"manufacturerName": "GreenPack Industries",
"countryOfOrigin": "DE",
"productContext": "Reusable water bottle made from recycled stainless steel",
"pricesPaid": [
{ "price": 1250, "currency": "USD", "date": "2025-01-15" }
]
}
The only required fields are productName and manufacturerName. Providing additional context improves the accuracy of the analysis:
| Field | Type | Description |
|---|---|---|
productName |
string | Required. Name of the product |
manufacturerName |
string | Required. Name of the manufacturer |
supplierNames |
string[] | Supplier name(s) |
productWebsite |
string | URL for the product page |
manufacturerWebsite |
string | URL for the manufacturer |
productContext |
string | Free-text description of the product |
manufacturerContext |
string | Free-text description of the manufacturer |
supplierContext |
string | Free-text description of the supplier(s) |
purchaserContext |
string | Context about the purchaser |
countryOfOrigin |
string | ISO country code (defaults to US) |
pricesPaid |
object[] | Historical prices — each with price (number, required), currency (string, required), and date (string, optional) |
The response is 201 Created with a job object:
{
"id": "a1b2c3d4-5678-90ab-cdef-1234567890ab",
"type": "cost-analysis",
"status": "pending",
"step": null,
"result": null,
"started": null,
"completed": null
}
Save the id — you'll use it to check on the job.
Step 2: Poll for Completion
Check the status of your job by its ID:
GET /pipeline/cost-analysis/{id}
Authorization: Bearer <your-token>
The status field progresses through these values:
| Status | Meaning |
|---|---|
pending |
Job is queued |
in_progress |
Job is actively processing |
completed |
Job finished successfully |
failed |
Job encountered an error |
Poll every 5–10 seconds until status is completed or failed. The step field provides a human-readable description of what the system is currently working on.
When the job completes, the response includes a result object with IDs for all generated records:
{
"id": "a1b2c3d4-5678-90ab-cdef-1234567890ab",
"type": "cost-analysis",
"status": "completed",
"step": "done",
"result": {
"costAnalysisId": "ca-uuid-here",
"bomId": "bom-uuid-here",
"productId": "product-uuid-here",
"manufacturerId": "manufacturer-uuid-here"
},
"started": "2025-06-01T12:00:00.000Z",
"completed": "2025-06-01T12:01:30.000Z"
}
If the job fails, errorMessage describes what went wrong.
Step 3: Retrieve the Results
Use the IDs from the result to fetch the generated records.
Cost Analysis
GET /cost-analysis/{costAnalysisId}
Authorization: Bearer <your-token>
Returns the cost analysis record including the shouldCostAmount and shouldCostStdErr (both in minor currency units, e.g. cents), the currency, and the analysisDate.
Bill of Materials
GET /bom/{bomId}
Authorization: Bearer <your-token>
Returns the bill of materials with a components list. Each component includes its name, type, cost, quantity, unitType, and countryOfOrigin.
To retrieve the full component details separately:
GET /bom/{bomId}/components
Authorization: Bearer <your-token>
Product and Manufacturer
The productId and manufacturerId can be used to retrieve the product and manufacturer (company) records:
GET /product/{productId}
GET /company/{manufacturerId}
Error Handling
- 404 Not Found — The job or record ID does not exist.
- 401 Unauthorized — Token is missing or expired. See the Authentication guide.
status: "failed"— The job did not complete. CheckerrorMessageon the job for details and resubmit if appropriate.
Bill of Materials
Retrieve bills of materials and their component breakdowns.
/bom/{id}
Get bom by ID
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| id | path | string<uuid> | required | |
| related | query | string[] | optional | Include related entities. Omit for all, "false" for none, or specify field names (repeatable, supports dot notation) |
Responses
| Field | Type | Description |
|---|---|---|
| data | BomDto | |
| id* | string | Unique identifier for the bill of materials record |
| versionLabel* | string | Per-lineage version label (MAJOR.MINOR), e.g., `v1.0`. MAJOR bumps on structural change (new AI generation, scenario fork, scenario promotion); MINOR bumps on revision (DLN-151). Assigned by the orchestrator at write time based on the most-recent prior BOM in the same `(productId, scenarioId)` lineage. |
| sourceType* | string | How this BOM came to exist. `ai_generation` is the initial BOM produced by the AI Step 3 Create-path (DLN-135). `ai_revision` is a diff applied by DLN-151. `import` is loaded from an external source. `human` is manually created. `scenario_fork` branches off an actual BOM into a scenario lineage (DLN-159). `scenario_promotion` is a scenario BOM promoted into actual lineage (DLN-280). The vocabulary is system-owned and small, so an enum constraint is appropriate (contrast `BOM_COMPONENT.type`, which is relaxed to allow orthogonal flag semantics). enum: ai_generation, ai_revision, import, human, scenario_fork, scenario_promotion |
| scenarioId | string | Lineage discriminator. NULL signals the actual lineage; a non-NULL UUID identifies a scenario lineage. The Scenario entity is introduced by DLN-159; until then this is a plain UUID column (`scenario_id`) with no FK constraint. DLN-135 always writes NULL. |
| promotedFromBomId | string | When `sourceType = scenario_promotion`, the scenario BOM that was promoted into actual lineage. NULL otherwise. Plain UUID column (`promoted_from_bom_id`) with no FK constraint — same convention as `priorBomId` and the legacy `parentBomId`. Populated by DLN-280. |
| generationDate* | string | Date and time when the BOM was generated |
| status | string | Status of the BOM generation process (e.g., "pending", "completed", "failed") enum: pending, completed, failed |
| components | BomComponentDto[] | List of components and their costs that make up the product - accepts array of full objects, id strings, or id numbers |
| id* | string | Unique identifier for the BOM component |
| priorBomComponentId | string | Optional predecessor BOM_COMPONENT row in the same temporal lineage. Set by revision flows (DLN-151) when this component evolved from a prior version. NULL for components on a newly generated BOM. Stored as a plain UUID column (`prior_bom_component_id`) with no FK constraint — same convention as `productId` / the existing `parentBomId` on BOM. Lineage integrity is enforced at the application layer. |
| bom | any | The parent BOM - accepts full object, id string, or id number |
| name* | string | Name of the component in the bill of materials |
| type* | string | Materiality classification for the component. One of: `sub-assembly` (has a populated `product` object and multi-entry `materials[]`), `direct-material` (raw input consumed into the finished product; no `product` object), `indirect-material` (packaging, consumable, or waste; paired with exactly one of `isPackaging` / `isConsumable` / `isWaste` set to true). Type and the `isPackaging`/`isConsumable`/`isWaste`/`isByproduct` flags are orthogonal axes: type answers materiality, flags answer cost treatment. DLN-286: enum-enforced at schema + DTO. The cost-analysis job normalizes the legacy value (`raw material`) before write on both create and revision paths; existing rows with non-canonical values stay readable (the DB CHECK add is warn-only via cruddy_constraint_warnings) but must be normalized before update. enum: sub-assembly, direct-material, indirect-material |
| classification | string | DLN-286 (FR-R1): refresh classification — how the Data Refresh prices this node and (Phase 2) whether it recurses. Derived by the cost-analysis job from `type` + `makeVsBuy` and persisted: direct/indirect-material → `commodity`; sub-assembly + MAKE → `manufactured-sub-assembly`; sub-assembly + BUY/UNKNOWN/absent → `bought-sub-assembly` (conservative default — UNKNOWN never opts a node into recursion). A stored value is never overwritten by re-derivation. enum: commodity, manufactured-sub-assembly, bought-sub-assembly |
| catalogEntityId | string | FK to CATALOG_COMMODITY.id or CATALOG_SUB_ASSEMBLY.id (see catalogEntityType). Plain uuid, not a validated schema relation — deferred-FK convention (matches rateSnapshotId on COST_ANALYSIS_COMPONENT_DRIVER): the two catalog tables are a discriminated union, so no single relation target applies. Set by the refresh pipeline (DLN-289) on first successful identity-match; reused on subsequent refreshes so a component never re-resolves identity every run. |
| catalogEntityType | string | Which catalog table catalogEntityId points into, when set. enum: catalog-commodity, catalog-sub-assembly |
| cost* | number | Cost of the component in minor currency units (e.g., cents) |
| quantity* | number | Quantity of the component used in the product |
| unitType* | string | Unit of measurement for the component (e.g., piece, kilogram, liter) |
| estimatedGramsPerUnit | number | Estimated grams of this component per unit. |
| estimatedCostPerUnit | number | Estimated cost in minor currency units (e.g., cents) of this component per unit. |
| estimatedCostPerUnitStdErr | number | Approximation of the standard error of the estimated cost in minor currency units (e.g., cents) of this component per unit. |
| referenceCostPerUnit | number | DLN-377: universal list / spot / OEM reference price per unit, in minor currency units (cents) — the undiscounted commodity price BOM creation produces. The auditable baseline; never overwritten by downstream adjustments. |
| supplierCostPerUnit | number | DLN-377: the price this manufacturer/supplier actually faces per unit, in minor currency units (cents). Equals referenceCostPerUnit until a supplier-specific pricing mechanism computes it (factor-1 default). |
| supplierDiscountFactor | number | Scale-based discount factor applied to referenceCostPerUnit to produce supplierCostPerUnit (0 < factor <= 1; 1 = no discount). Computed by the supplier purchasing-power step from the buyer's annual commodity / category spend through a capped, saturating curve. Null when no discount has been computed. |
| supplierDiscountBasis | string | Spend basis behind the factor: commodity_scale for raw materials (buyer's spend on the commodity itself), supplier_leverage for bought whole units (buyer's spend on the part category; lower ceiling — only margin and conversion are negotiable). enum: commodity_scale, supplier_leverage |
| supplierDiscountSource | string | Provenance of the financials scale signal the factor was derived from, from filed statements down to structural proxies. enum: edgar_financials, reported_financials, ai_estimate, employees_proxy, supplier_tier, naics_default |
| supplierDiscountConfidence | string | Confidence in the discount, combining the scale-signal quality and the commodity-share source (AI-estimated shares cap at medium). enum: high, medium, low |
| countryOfOrigin | string | Country where the component is most likely manufactured (two digit ISO country code, e.g., US, CN). |
| makeVsBuy | string | Whether the product's manufacturer makes this component in-house (`MAKE`) or buys it from an upstream supplier (`BUY`). `UNKNOWN` when it cannot be determined — do not guess. Classification only: this is an explicit, auditable input signal and drives no cost adjustment here. The implicit default mapping is sub-assembly→`BUY`, direct-material→`MAKE`; orthogonal to `type`. enum: MAKE, BUY, UNKNOWN |
| buyDetails | any | Upstream-sourcing detail for `BUY` components. Omit for `MAKE`/`UNKNOWN`. The supplier here is who the part is purchased from, which is distinct from the sub-assembly `product.manufacturer` (who made it) even when they coincide. |
| beaCode | string | BEA IO commodity code identifying what this component is, as a commodity — the lookup key into the BEA×NAICS composition matrix (bea_composition dataset). Chosen from the controlled bea_commodities vocabulary at BOM generation and enforced against it before persistence: a code outside the vocabulary is nulled with beaUnmappedReason set. Null means unmapped; downstream composition lookups fall back to estimates. Sub-assemblies carry the commodity category of the purchased article, not their dominant raw material. |
| beaConfidence | string | Model-reported confidence in the beaCode mapping. Null when the component is unmapped. enum: high, medium, low |
| beaUnmappedReason | string | Why beaCode is null — either the model found no vocabulary entry that covers the component, or a proposed code was rejected as outside the vocabulary. Null when beaCode is set. |
| isPackaging | boolean | Indicates if the component is packaging material used to contain, protect, or present the finished product (e.g., cartons, labels, shrink wrap). Packaging contributes to Indirect Materials with a positive cost. |
| isWaste | boolean | Indicates if the component is scrap or non-valuable residue generated during production that must be disposed of. Waste has its own cost category (positive price and cost). If a byproduct would require payment to dispose of, classify it as waste, not a byproduct. |
| isConsumable | boolean | Indicates if the component is an indirect process consumable used during manufacturing that does not end up in the final product (e.g., sterilization agents, cleaning solvents, process gases, water). Consumables contribute to Indirect Materials with a positive cost. |
| isByproduct | boolean | Indicates if the component is a valuable co-product of the manufacturing process that generates revenue or offsets cost (e.g., a chemical intermediate sold to another industry). Byproducts carry a positive price but a negative cost representing the credit received. They subtract from Direct Materials. If the component instead requires payment to dispose of, classify it as isWaste, not isByproduct. |
| sources | string[] | List of URIs to sources or references for the component information. This can be spec sheets, manufacturer websites, datasheets, etc. |
| confidence | any | Detailed confidence information about various aspects of the component data |
| justification | string | Explanation of the reasoning behind all of the mappings made in this component (e.g., sources, justification for assumptions, confidence, etc.). Keep this to less than 5000 characters. Can also include other considerations about this product. |
| materials | RawMaterialEntryDto[] | Estimated raw materials that make up this component. In the case that this component is just a single @raw-material-entry, this is just the one raw material itself in the array. In the case of a sub-assembly, this is the list of @raw-material-entries that make up the sub-assembly. - accepts array of full objects, id strings, or id numbers |
| productId | string | Optional reference to PRODUCT when this component represents a known sub-product. Cross-service reference — Cruddy does not emit a FK constraint (DLN-168 forbids cross-service FKs). Populated by recursive sub-product resolution (DLN-154); NULL otherwise. |
| product | any | Information about the @product if the component is a sub-assembly. If the component is a raw material, this can be omitted. If the product is a sub-assembly, but the manufacturer of the sub-assembly is unknown or the sub-assembly is a commodity, you can leave the manufacturer as GENERIC. |
| refQtyValue | number | Reference quantity of output product this BOM represents. Examples: 1 for finished goods (paired with `refQtyUnit: "piece"`); 1, 100, 1000 for chemicals/commodities (paired with `refQtyUnit: "kilogram"` or similar). Per-component `cost`/`quantity` values are calibrated against this reference batch. |
| refQtyUnit | string | Unit of measurement for `refQtyValue` (e.g., `kilogram`, `piece`, `liter`). |
| assumptions | string[] | Critical assumptions about process, material grade, formulation, yield, or other factors that influenced the BOM composition and component costs. Examples: assumed reaction route, catalyst choice, solvent grade, food-grade vs industrial-grade materials, assembly method, raw material form factor. |
| processParams | any | Manufacturing process classification for cost modeling. Used to apply yield, compliance, and setup adjustments in cost analysis. |
| productId | string | ID of the product this BOM was generated for. Enables direct querying of all BOMs for a given product. |
| priorBomId | string | Predecessor BOM in the same `(productId, scenarioId)` lineage. NULL on the first BOM in a lineage; set on every successor (generation, revision, scenario fork, scenario promotion). Establishes per-lineage chaining. Plain UUID column (`prior_bom_id`) with no FK constraint — same convention as the legacy `parentBomId` field this replaces. |
| revisionDiff | object | The structured diff that was applied to the parent BOM to produce this revision. Stored for auditability and lineage tracking. Contains operations (modify/add/remove), updatedAssumptions, and a summary of changes. Stored as opaque JSON. |
| meta | object |
Company
Look up company profiles and related information.
/company/{id}
Get company by ID
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| id | path | string<uuid> | required | |
| related | query | string[] | optional | Include related entities. Omit for all, "false" for none, or specify field names (repeatable, supports dot notation) |
Responses
| Field | Type | Description |
|---|---|---|
| data | CompanyDto | |
| id | string | Unique identifier for the company record |
| name* | string | Legal or commonly known name of the company |
| nameNormalized | string | Deterministic normalization of `name` used for per-tenant deduplication (lowercase + trim + collapse-whitespace + strip-punctuation + strip common corporate suffixes + Unicode NFKC). Service-computed on write; not client-supplied. Indexed per-tenant by a partial unique index installed at service bootstrap. See DLN-133. |
| accountId | string | FK to the account that owns this company record. When null, the company is considered a public/shared record. |
| legalStructure | string | Legal entity type (e.g., LLC, Inc, GmbH, Pty Ltd) |
| identifiers | object | Official business registration identifiers as key-value pairs. Keys are identifier types (e.g., ein, vat, duns, crn) and values are the corresponding registration numbers. |
| country | string | Country of incorporation (ISO 3166-1 alpha-2 code, e.g., US, CA, GB, DE) |
| naicsIndustries | string[] | Two-digit NAICS sector codes describing the company's primary industries |
| naics | string[] | Six-digit NAICS codes describing the company's specific lines of business |
| founded | string | Date the company was founded or incorporated |
| domains | string[] | Company domain names (e.g., google.com, abc.xyz) |
| website | string | Primary corporate website URL |
| status | string | Current operational status of the company enum: active, dissolved, merged, acquired |
| headquarters | any | Primary headquarters address - accepts full object, id string, or id number |
| employees | number | Approximate total number of employees |
| aliases | string[] | Alternative or former names the company is known by (e.g., trade names, DBAs, previous names) |
| logos | LogosDto[] | Company logos, past and present, with usage dates |
| logo* | string | URI to the logo image file (full GCS path) |
| status | string | Whether this logo is currently in use enum: active, inactive |
| description | string | Label or context for this logo (e.g., primary, icon, wordmark) |
| start_date | string | Date this logo started being used |
| end_date | string | Date this logo stopped being used, if inactive |
| socials | SocialsDto[] | Social media profiles associated with the company |
| type* | string | Social media platform (e.g., linkedin, twitter, facebook) |
| url | string | Full URL to the company's profile on this platform |
| username | string | Company's username or handle on this platform |
| addresses | AddressesDto[] | Additional company locations beyond the headquarters (e.g., offices, branches, factories) |
| type* | string | Location type (e.g., office, branch, factory, warehouse) |
| address* | any | Physical address of this location - accepts full object, id string, or id number |
| ticker | string | Stock ticker symbol for a publicly-traded company (e.g., AAPL, BRK.A). Used to resolve the company's SEC CIK for EDGAR financial-statement lookups. |
| cik | string | SEC Central Index Key, 10-digit zero-padded. Populated on first successful EDGAR resolution for a US public filer. |
| financials | CompanyFinancialsDto[] | Annual financial snapshots (revenue, COGS, SGA components) for this company, one per fiscal year. Sourced from EDGAR filings or operator entry. See DLN-73. - accepts array of full objects, id strings, or id numbers |
| id | string | Unique identifier for the financials record |
| company | any | The parent company this snapshot describes - accepts full object, id string, or id number |
| fiscalYear* | number | Fiscal year covered by this snapshot |
| periodStart* | string | Start date of the reporting period (e.g., 2024-01-01) |
| periodEnd* | string | End date of the reporting period. Used by the cross-taxonomy validity guard to reject stale observations where values lag revenue's period by more than ~1 year. |
| statementType* | string | Filing type the snapshot was extracted from, or "manual" when entered by an operator. enum: 10-K, 20-F, manual |
| currency* | string | ISO 4217 currency code (e.g., USD, JPY) for all numeric amounts in this row. Values are stored as-reported in this currency. |
| revenue* | number | Annual revenue, as reported in the filing, in units of `currency`. |
| cogs* | number | Annual cost of goods sold, as reported in the filing, in units of `currency`. |
| salesAndMarketing | number | Sales & Marketing expense component of "our SGA" (sum of S&M + G&A + R&D, deliberately excluding non-operational items). Nullable when the filer does not break it out. |
| generalAndAdministrative | number | General & Administrative expense component of "our SGA". Nullable when the filer does not break it out. |
| researchAndDevelopment | number | Research & Development expense component of "our SGA". Nullable when the filer does not break it out. |
| filingDate | string | SEC filing/accepted date of the underlying 10-K or 20-F. Drives the 300-day EDGAR refresh check. Null for manual rows. |
| accessionNumber | string | EDGAR accession number (e.g., 0000008670-24-000011) that sourced this row, for audit and per-run traceability. Null for manual rows. |
| retrievedAt | string | Timestamp at which this row was written (EDGAR fetch or manual entry). |
| lastCheckedAt | string | Last time EDGAR was probed for this row. Combined with a 30-day negative-cache window to prevent thrashing when filingDate has passed the 300-day fresh window but no newer filing exists. |
| source* | string | Provenance of this row. Only "edgar" and "manual" rows are persisted. LLM fallback responses are never persisted (returned directly to caller with source="llm" in the response envelope). enum: edgar, manual |
| enteredBy | string | Operator who entered this row. Required when source="manual"; null for "edgar". |
| reason | string | Operator-supplied justification for a manual entry (e.g., "EDGAR extraction failed; numbers from investor presentation"). Required when source="manual". |
| commodityDiscounts | CompanyCommodityDiscountDto[] | Cached supplier purchasing-power discount factors for this company, one per (commodityCategory, fiscalYear). Written by the cost-analysis supplier-power step; a reusable derived value, recomputed when the underlying financials change. - accepts array of full objects, id strings, or id numbers |
| id | string | Unique identifier for the cached factor row |
| company | any | The company whose purchasing power the factor describes - accepts full object, id string, or id number |
| commodityCategory* | string | Commodity the factor applies to — the BEA IO commodity code carried on the discounted BOM components (the composition-matrix lookup key). |
| fiscalYear* | number | Fiscal year of the financials the factor was derived from. |
| factor* | number | Discount factor (0 < factor <= 1; 1 = no discount) applied to a reference price to produce the supplier-facing price. |
| basis* | string | Spend basis the factor was computed on. enum: commodity_scale, supplier_leverage |
| source* | string | Provenance of the financials scale signal. enum: edgar_financials, reported_financials, ai_estimate, employees_proxy, supplier_tier, naics_default |
| confidence* | string | Confidence in the factor. enum: high, medium, low |
| spendUsd | number | The annual spend estimate (USD) that produced the factor, kept for auditability of the curve input. |
| computedAt | string | When the factor was last computed. |
| metadata | object | Additional metadata about the company as key-value pairs |
| meta | object |
Product
Look up product profiles and related information.
/product/{id}
Get product by ID
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| id | path | string<uuid> | required | |
| related | query | string[] | optional | Include related entities. Omit for all, "false" for none, or specify field names (repeatable, supports dot notation) |
Responses
| Field | Type | Description |
|---|---|---|
| data | ProductDto1 | |
| id* | string | Unique identifier for the product |
| name* | string | Name of the product |
| description | string | Detailed description of the product |
| retailPrice | number | Approximate, current price of the product, in minor currency units (e.g., cents) |
| retailPriceCurrency | string | Currency code for the retail price (e.g., USD, EUR) |
| unitType | string | Unit of measurement for the @product (e.g., piece, kilogram, liter) enum: piece, kilogram, gram, liter, milliliter, meter, foot, square meter, square foot, cubic meter, gallon, pound, ounce, ton, sheet, roll, barrel, board foot |
| status | string | Lifecycle status of the product enum: in development, active, end-of-life |
| commoditized | boolean | Indicates if the product is classified as a commodity - very little differentiation between competitors |
| rawMaterial | boolean | Indicates if the product is considered a raw material used in manufacturing or production (e.g., steel, plastic, lumber) |
| parentProductId | string | FK to the parent @product, if applicable |
| categoryId | string | FK to the @product-category that classifies the product |
| countryOfOrigin | string | Country where the product is manufactured (ISO 3166 alpha-2 code, e.g., US, CN) |
| weightGrams | number | Product weight in grams |
| leadTimeDays | number | Typical lead time in days |
| minimumOrderQuantity | number | Minimum order quantity |
| metadata | object | Additional account-specific metadata about the product |
| identifiers | any | Various identifiers associated with the product |
| urls | any | Various URLs associated with the product |
| meta | object |
Pipeline
Submit asynchronous analysis jobs such as cost-analysis pipelines.
/pipeline/cost-analysis
Submit a cost analysis pipeline request
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| x-firebase-uid | header | string | optional | Gateway-set Firebase UID of the calling user (Langfuse user attribution). Server-injected — clients never supply it; the gateway strips inbound copies. |
Request Body
| Field | Type | Description |
|---|---|---|
| id | string | Unique identifier for the pipeline request. |
| caVersion | string | The version of cost analysis generation process to use. |
| bomVersion | string | The version of bill of materials to use. |
| productName | string | Name of the product. Required for a normal run; for an iteration (previousAnalysisId set) it is derived from the prior run, so it may be omitted (DLN-197/ADR 0073). A new_analysis run (feedbackId without previousAnalysisId, DLN-196) is a normal run, so it must supply this. |
| manufacturerName | string | Name of the manufacturer. Required for a normal run; for an iteration (previousAnalysisId set) it is derived from the prior run, so it may be omitted (DLN-197/ADR 0073). A new_analysis run (feedbackId without previousAnalysisId, DLN-196) must supply this. |
| productId | string | ID of an existing product entity. When provided along with manufacturerId, skips AI company/product resolution and uses the existing entities. |
| manufacturerId | string | ID of an existing manufacturer entity. When provided along with productId, skips AI company/product resolution and uses the existing entities. |
| supplierNames | string[] | Supplier name(s). Each entry is resolved via a sequential AI company-resolution query, so the list is capped at 10. |
| supplierIds | string[] | IDs of existing supplier entities. When provided, skips AI resolution for supplierNames and links these existing suppliers directly. |
| productWebsite | string | Website of the product. |
| manufacturerWebsite | string | Website of the manufacturer. |
| productContext | string | Context about the product. |
| manufacturerContext | string | Context about the manufacturer. |
| supplierContext | string | Context about the supplier(s). |
| purchaserContext | string | Context about the purchaser. |
| countryOfOrigin | string | ISO 3166-1 alpha-2 country code for the product's country of origin. pattern: ^[A-Z]{2}$ |
| importCountry | string | ISO 3166-1 alpha-2 country code where the product is imported to. pattern: ^[A-Z]{2}$default: "US" |
| annualVolume | number | Expected annual purchase volume of the finished product. |
| annualVolumeUnit | string | Unit for annualVolume (e.g., kg, liter, unit). |
| unitType | string | Base unit of measurement for the product (e.g., kilogram, piece, liter). Overrides AI inference when provided. enum: piece, kilogram, gram, liter, milliliter, meter, foot, square meter, square foot, cubic meter, gallon, pound, ounce, ton, sheet, roll, barrel, board foot |
| countryOfOriginText | string | Raw, unnormalized country-of-origin text from a bulk import (e.g. 'China', 'P.R.C.'). Unlike countryOfOrigin, it is NOT validated to alpha-2; Product Resolution normalizes it. Used only by the import path — the form/API should send the strict countryOfOrigin. |
| unitTypeText | string | Raw, unnormalized unit-of-measure text from a bulk import (e.g. 'kg', 'tonne'). Unlike unitType, it is NOT validated to the closed enum; Product Resolution normalizes it. Used only by the import path — the form/API should send the strict unitType. |
| quantity | number | Quantity of the product for this cost analysis (e.g., 2 for 2 tons, 1000 for 1000 units). Decimals supported. Defaults to 1 if not specified. |
| pricesPaid | PricesPaidItemDto[] | Historical prices paid. |
| date | string | Date when the price was paid. |
| price* | number | Price paid in minor currency units (e.g., cents). |
| currency* | string | Currency code (e.g., USD, EUR). |
| enableBomJudge | boolean | If true, run the BOM Judge step (Step 3a) to validate and correct BOM component costs against retail prices and logical consistency. When false, BOM costs are used as-is from the BOM generation step. default: true |
| enableTier1Adjustments | boolean | If true, apply Tier 1 process parameter adjustments (compliance overhead and batch setup amortization) derived from the BOM process parameters. When false, the ASM industry averages are used without process-level adjustments. default: true |
| enableSupplierPower | boolean | If true (default), apply the supplier purchasing-power step: components are priced at the supplier-facing cost (reference price x a capped, scale-based discount factor). Set false to keep every component at the universal reference price. default: true |
| supplierScaleTier | string | Optional explicit supplier scale tier, used as the purchasing-power signal when no financials are available (fallback of last resort before no-discount). enum: enterprise, mid, small |
| enableProcessAssessment | boolean | If true, run a process assessment step that generates Tier 2 adjustments. |
| costAdjustments | CostAdjustmentItemDto[] | Explicit named adjustments to apply to cost-analysis components. |
| name* | string | Human-readable label for this adjustment. |
| category* | string | Cost category type to target. enum: direct_materials, indirect_materials, labor, overhead |
| type | string | How to apply the adjustment. enum: multiplicative, additivedefault: "multiplicative" |
| factor | number | Multiplicative factor (e.g., 1.1 for a 10% increase). |
| amount | number | Additive amount in minor currency units (cents). |
| enableQa | boolean | If true, run an AI-powered QA evaluation step after cost analysis. |
| enableAiTariffResolution | boolean | If true, run an AI-powered Tariff Resolution step (Step 3d) to determine the effective import tariff rate, replacing the static HTSUS dataset lookup. Supports non-US import countries when enabled. default: false |
| annualRevenue | number | DEPRECATED (DLN-73): Manufacturer annual revenue. Prefer POST /company/{id}/financials with source=manual. Hard-overrides the EDGAR auto-fetch for this run. |
| annualCogs | number | DEPRECATED (DLN-73): Manufacturer annual cost of goods sold. Prefer POST /company/{id}/financials with source=manual. |
| annualSga | number | DEPRECATED (DLN-73): Manufacturer annual SG&A expenses. Prefer POST /company/{id}/financials with source=manual. |
| enableMonteCarlo | boolean | If true, run Monte Carlo simulation to compute costMin/costMax. Bounds derive from the MC P10/P90 but are widened where needed so the deterministic cost always lies within [costMin, costMax]; a widened side is a containment bound, not a strict percentile. |
| analysisConfig | string | Named analysis configuration preset (e.g., "basic"). |
| existingBomId | string | ID of an existing bill of materials to reuse. When provided, the pipeline skips BOM generation and uses this BOM for downstream steps. If bomContext is also provided, the BOM is revised rather than reused as-is. |
| bomContext | string | Free-text instructions for revising an existing BOM. Only used when existingBomId is also provided. Describes what should change from the previous BOM (e.g., "change support legs from 2 to 4 pieces"). |
| previousAnalysisId | string | DLN-197/ADR 0073: the cost analysis being iterated on (with-rerun). This field — together with feedbackId — is the iteration discriminator: when both are set, the orchestrator resolves the prior run via its computeInputs.sourceJobId, reuses its entities + BOM, and revises the BOM from the feedback corrections (so productName/manufacturerName are derived and may be omitted). Omit it for a normal or new_analysis run. |
| feedbackId | string | DLN-197/ADR 0073: the analysis-feedback record this run fulfils. With previousAnalysisId it drives an iteration rerun (the orchestrator reads its normalizedCorrections as the single source of truth for the BOM revision). Without previousAnalysisId it marks a new_analysis run (DLN-196) for audit: the orchestrator stamps this feedback record’s resultAnalysisId with the new CostAnalysis it creates. |
| includeBomPackaging | boolean | Include packaging components in the BOM. When false, the AI is instructed to omit packaging from the BOM and packaging costs use ASM industry averages. default: true |
| includeBomWaste | boolean | Include waste components in the BOM. When false, the AI is instructed to omit waste from the BOM and waste removal costs use ASM industry averages. default: true |
| includeBomConsumables | boolean | Include consumable components in the BOM. When false, the AI is instructed to omit consumables from the BOM and consumable costs use ASM industry averages. default: true |
| includeBomByproducts | boolean | Include valuable byproduct/co-product components in the BOM. When false, the AI is instructed to omit byproducts and no cost credit is applied to Direct Materials. default: true |
| importId | string<uuid> | Parent Import when this run is one row of a file import uuid |
| rowIndex | number | Zero-based row index in the source import file min: 0 |
| rowData | object | Raw parsed source row (import provenance) |
Responses
| Field | Type | Description |
|---|---|---|
| data | JobDto | |
| id | string | Unique identifier for the job |
| parentJobId | string | FK to a parent job when this job is a sub-task of a pipeline job |
| importId | string | FK to the parent Import when this job is one row of a file import |
| rowIndex | number | Zero-based row index within the source import file (set for import rows) |
| type* | string | Job type identifier (e.g., bom_generation, cost_analysis) |
| status* | string | Current execution status of the job enum: pending, in_progress, completed, failed, skipped |
| payload | object | Input data for the job (structure depends on job type) |
| result | object | Output data from the job (structure depends on job type) |
| step | string | Current step label for progress tracking (e.g., fetching_data, analyzing) |
| started | string | Timestamp when the job started executing |
| completed | string | Timestamp when the job completed successfully |
| errored | string | Timestamp when the job encountered an error, if applicable |
| errorMessage | string | Error message describing what went wrong, if applicable |
| meta | object |
/pipeline/cost-analysis/{id}
Get a cost analysis or bom-refresh job by ID
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| id | path | string<uuid> | required |
Responses
| Field | Type | Description |
|---|---|---|
| data | CostAnalysisJobDto | |
| id | string | Unique identifier for the job |
| parentJobId | string | FK to a parent job when this job is a sub-task of a pipeline job |
| importId | string | FK to the parent Import when this job is one row of a file import |
| rowIndex | number | Zero-based row index within the source import file (set for import rows) |
| type* | string | Job type identifier (e.g., bom_generation, cost_analysis) |
| status* | string | Current execution status of the job enum: pending, in_progress, completed, failed, skipped |
| payload | object | Input data for the job (structure depends on job type) |
| step | string | Current step label for progress tracking (e.g., fetching_data, analyzing) |
| started | string | Timestamp when the job started executing |
| completed | string | Timestamp when the job completed successfully |
| errored | string | Timestamp when the job encountered an error, if applicable |
| errorMessage | string | Error message describing what went wrong, if applicable |
| result | any | Result shape depends on the job type: cost_analysis jobs return this cost-analysis result; bom_refresh jobs return per-outcome refresh counts (update / ignore / flag-for-review / total) instead. |
| meta | object |
Cost Analysis
Retrieve completed cost-analysis results and component-level details.
/cost-analysis/{id}/feedback
List feedback submitted on a cost analysis (DLN-311)
Returns the feedback submissions for the analysis, newest-first, tenant-scoped. An analysis with no feedback yet returns an empty list. Responds 404 only when the cost analysis is unknown or belongs to another tenant.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| id | path | string<uuid> | required | |
| limit | query | number | optional | |
| offset | query | number | optional | |
| count | query | boolean | optional | Include totalCount of unbounded results in response meta |
Responses
| Field | Type | Description |
|---|---|---|
| data | AnalysisFeedbackDto[] | |
| id* | string | Unique identifier for the analysis-feedback record |
| costAnalysis* | any | The cost analysis this feedback is for (the ticket's analysisId). Validated relation — accepts the related object or its id string (@ValidateRelatedOrId). - accepts full object, id string, or id number |
| submittedById* | string | User who submitted the feedback |
| submittedByName | string | Display name of the submitter, captured at submission time |
| submittedAt* | string | When the feedback was submitted |
| origin | string | Whether the iteration was submitted by a Dalinea-internal or an external (customer) user. Derived server-side at submit from the gateway-set x-user-type header (never the request body). Internal-origin iterations are excluded from the rerun count/cap and hidden from customer-facing history (DLN-334). Absent on rows predating DLN-334 → treated as external. enum: internal, external |
| changeType* | string | Kind of change the feedback requests enum: new_analysis, iteration_no_rerun, iteration_with_rerun |
| feedbackStatus* | string | Review lifecycle status enum: auto_approved, submitted, under_review, approved, rejected |
| corrections | any | The user-submitted correction payload. Bundled rather than flattened: the individual values are reported on, not filtered. The concrete grammar of the free-form sub-objects is owned by the submit flow (DLN-194). |
| normalizedCorrections | any | The admin-normalized counterpart of `corrections`, produced during review (DLN-195). Same field set, plus `changeType` when the admin reclassifies the request. |
| reviewedById | string | Admin who reviewed the feedback |
| reviewedByName | string | reviewedByName |
| reviewedAt | string | reviewedAt |
| adminNotes | string | Free-text admin notes on the review decision |
| bomValidationOverrides | string[] | BOM validation rules the admin chose to override for this iteration. Each item identifies a rule and the override decision; shape owned by the admin review flow (DLN-195). |
| resultAnalysisId | string | Nullable pointer to the resulting cost analysis (the new v1 for new_analysis, or the new version for iterations). Stored as a plain uuid (deferred-FK) — a second validated relation to cost-analysis is deferred to avoid multi-relation disambiguation; AC requires only the submitted analysis FK to be validated. |
| evaluationMessage | string | System/admin message describing the evaluation outcome |
| meta | object | |
| totalCount | integer | Unbounded result count. Only present when ?count=true is passed. |
/cost-analysis/{id}/feedback
Submit category-manager feedback on a cost analysis (DLN-194)
For external submitters, the first submission claims the feedback-owner lock (403 for a different user). DLN-334: internal (Dalinea) submitters are exempt — they neither claim the lock nor are blocked by an existing owner (no 403), and their iterations do not count toward or hit the 3-round rerun cap. iteration_with_rerun and new_analysis enter the admin review queue (202, status → pending_review); iteration_with_rerun is rejected with 422 once the chain has consumed 3 rerun rounds (external only). iteration_no_rerun recomputes synchronously (no AI) and resolves immediately (200) with the auto-approved feedback pointing at the newly persisted version via resultAnalysisId.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| id | path | string<uuid> | required | |
| x-app-user-id | header | string | required | |
| x-user-type | header | string | optional | Gateway-set INTERNAL/EXTERNAL user type (DLN-334). Server-injected — clients never supply it; the gateway strips inbound copies. Absent → treated as external. |
Request Body
| Field | Type | Description |
|---|---|---|
| changeType* | string | Kind of change requested. iteration_no_rerun resolves immediately; iteration_with_rerun and new_analysis enter the admin review queue. enum: new_analysis, iteration_no_rerun, iteration_with_rerun |
| submittedByName | string | Submitter display name, captured for the review queue. Non-authoritative — the identity used for the ownership lock comes from x-app-user-id. |
| corrections | any | The user-submitted correction payload (per the analysis-feedback grammar). |
Responses
| Field | Type | Description |
|---|---|---|
| data | AnalysisFeedbackDto | |
| id* | string | Unique identifier for the analysis-feedback record |
| costAnalysis* | any | The cost analysis this feedback is for (the ticket's analysisId). Validated relation — accepts the related object or its id string (@ValidateRelatedOrId). - accepts full object, id string, or id number |
| submittedById* | string | User who submitted the feedback |
| submittedByName | string | Display name of the submitter, captured at submission time |
| submittedAt* | string | When the feedback was submitted |
| origin | string | Whether the iteration was submitted by a Dalinea-internal or an external (customer) user. Derived server-side at submit from the gateway-set x-user-type header (never the request body). Internal-origin iterations are excluded from the rerun count/cap and hidden from customer-facing history (DLN-334). Absent on rows predating DLN-334 → treated as external. enum: internal, external |
| changeType* | string | Kind of change the feedback requests enum: new_analysis, iteration_no_rerun, iteration_with_rerun |
| feedbackStatus* | string | Review lifecycle status enum: auto_approved, submitted, under_review, approved, rejected |
| corrections | any | The user-submitted correction payload. Bundled rather than flattened: the individual values are reported on, not filtered. The concrete grammar of the free-form sub-objects is owned by the submit flow (DLN-194). |
| normalizedCorrections | any | The admin-normalized counterpart of `corrections`, produced during review (DLN-195). Same field set, plus `changeType` when the admin reclassifies the request. |
| reviewedById | string | Admin who reviewed the feedback |
| reviewedByName | string | reviewedByName |
| reviewedAt | string | reviewedAt |
| adminNotes | string | Free-text admin notes on the review decision |
| bomValidationOverrides | string[] | BOM validation rules the admin chose to override for this iteration. Each item identifies a rule and the override decision; shape owned by the admin review flow (DLN-195). |
| resultAnalysisId | string | Nullable pointer to the resulting cost analysis (the new v1 for new_analysis, or the new version for iterations). Stored as a plain uuid (deferred-FK) — a second validated relation to cost-analysis is deferred to avoid multi-relation disambiguation; AC requires only the submitted analysis FK to be validated. |
| evaluationMessage | string | System/admin message describing the evaluation outcome |
| meta | object |
/cost-analysis/portfolio/summary
Portfolio Overview savings-potential summary
Aggregates the latest completed cost analysis per product into Likely/Possible/Unlikely/Unknown savings buckets (counts, percentages, summed savings potential in minor currency units) plus the top-N savings opportunities. V1: single-currency assumption, tenant-wide, cached briefly in memory.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| topLimit | query | integer | optional | Rows in topProducts (default 5) |
| recentLimit | query | integer | optional | Rows in recentAnalyses (default 5) |
Responses
| Field | Type | Description |
|---|---|---|
| data | PortfolioSummaryDto | |
| currency* | string | Single currency observed across analyzed products (V1 single-currency assumption) |
| totalProducts* | number | Products with >=1 completed cost analysis — the percentage denominator |
| buckets* | PortfolioBucketsDto | |
| likely* | PortfolioBucketStatDto | |
| possible* | PortfolioBucketStatDto | |
| unlikely* | PortfolioBucketStatDto | |
| unknown* | any | Products whose latest analysis has no savings opportunity or no usable should-cost |
| topProducts* | PortfolioTopProductDto[] | |
| productId* | string<uuid> | Product the opportunity is for uuid |
| costAnalysisId* | string<uuid> | Latest completed cost analysis id uuid |
| savingsOpportunityId* | string<uuid> | Savings opportunity id uuid |
| shouldCostAmount* | number | Should-cost in minor currency units |
| savingsAmount* | number | Savings amount (reference price - should-cost) in minor units |
| savingsPct* | number | Savings as a fraction of should-cost (0..1) |
| bucket* | string | Bucket this product falls into enum: likely, possible, unlikely, unknown |
| currency* | string | Currency code |
| recentAnalyses* | PortfolioRecentAnalysisDto[] | |
| productId* | string<uuid> | Product the analysis is for uuid |
| costAnalysisId* | string<uuid> | Cost analysis id uuid |
| analysisDate* | string | When the analysis was performed (ISO 8601) |
| shouldCostAmount* | number | Should-cost in minor currency units |
| savingsAmount* | number | Savings amount in minor units; null when the analysis has no opportunity |
| savingsPct* | number | Savings as a fraction of should-cost (0..1); null when no opportunity or no usable should-cost |
| currency* | string | Currency code |
| generatedAt* | string | When the summary was computed (ISO 8601) |
| meta | object |
/cost-analysis/by-product/{productId}
Get the most recent completed cost analysis for a product
Returns the latest completed cost analysis as a single merged object (run-level record + rollup buckets as components). Monetary values are in minor currency units. Responds 202 with job status when no completed analysis exists but a pipeline run is pending or in progress (the in-progress check is product-level and not constrained by filterScope). Responds 404 when neither exists, including when the pipeline service is unreachable.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| productId | path | string<uuid> | required | |
| filterScope | query | string | optional | Comma-separated dimension:value filters constraining which completed analyses qualify. Supported dimensions: countryOfOrigin, importCountry. Example: countryOfOrigin:CN,importCountry:US |
Responses
| Field | Type | Description |
|---|---|---|
| data | CostAnalysisResultDto1 | |
| id* | string<uuid> | Cost analysis id uuid |
| status* | string | Status of the cost analysis enum: analysis_done |
| analysisDate* | string | When the analysis was performed (ISO 8601) |
| productId* | string<uuid> | Product the analysis belongs to uuid |
| currency | string | Currency code for all monetary values (e.g., USD) |
| bomId | string<uuid> | Bill of materials the analysis was computed from uuid |
| countryOfOrigin | string | ISO country code of origin |
| importCountry | string | ISO country code of import destination |
| shouldCostAmount | number | Theoretical production cost in minor currency units |
| shouldCostStdErr | number | Standard error of the should-cost estimate in minor currency units |
| qaVerdict | object | QA Evaluation verdict (DLN-158). Null when QA was not enabled for this analysis. |
| adjustments | AdjustmentsDto[] | Adjustments applied beyond the industry-average baseline |
| type* | string | Identifier for the kind of adjustment applied enum: manufacturer_financials, yield_adjustment, compliance_overhead, setup_amortization, named_adjustment, tariff, indirect_tariff, volume_discount, supplier_purchasing_power |
| source* | string | Origin of this adjustment enum: user_provided, ai_estimate, analyst_judgment, system, edgar_auto, operator_entry |
| label | string | Human-readable description of what was adjusted |
| metadata | object | Adjustment-specific qualitative context (no dollar amounts). For type="manufacturer_financials": may include - cogsRatioAdjusted (boolean) - profitMarginOverridden (boolean) - fiscalYear (integer): the FY the financials describe - companyFinancialsId (uuid): the specific company_financials row that fed this run, enabling audit even after the cache rolls to a newer filing - financialsSource ("edgar" | "manual" | "llm" | "dto"): where the financials came from for this run - sgaCompleteness ({found:[...], missing:[...]}): which SGA components were present vs missing from the source filing - operatingMarginSource ("edgar_sga" | "asm_industry_average"): whether annual SGA was available or the ASM industry average was used for the operating-margin component - llmCitations ([{field, url, note}]): present only when financialsSource == "llm" For type="tariff" (direct product-level import tariff): may include - importCountry (string) - countryOfOrigin (string) - ratePercent (number) For type="indirect_tariff" (tariffs on foreign-sourced BOM components): may include - components (object): per-component breakdown of the indirect tariff impact |
| components* | CostComponentDto[] | Cost breakdown by rollup bucket |
| id* | string<uuid> | Unique identifier of the bucket row uuid |
| name* | string | Name of the cost component (e.g., "Direct Materials") |
| currency* | string | Currency code (e.g., USD) |
| cost* | number | Cost amount in minor currency units (e.g., cents) |
| costMin* | number | Minimum estimated cost in minor currency units |
| costMax* | number | Maximum estimated cost in minor currency units |
| meta | object |
| Field | Type | Description |
|---|---|---|
| data | CostAnalysisInProgressDto | |
| jobId* | string<uuid> | Pipeline job id to poll via GET /pipeline/cost-analysis/:id uuid |
| status* | string | Job status enum: pending, in_progress |
| step | string | Current pipeline step label |
| meta | object |
/cost-analysis/{id}/versions
Get the full version history of a cost analysis
Returns every version in the analysis chain in chronological order (oldest first). Accepts ANY version id in the chain — it walks both backward (prior versions) and forward (later iterations) from the given id. Each entry is a summary; full data stays on GET /cost-analysis/:id. Responds 404 when the id is unknown or belongs to another tenant.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| id | path | string<uuid> | required |
Responses
| Field | Type | Description |
|---|---|---|
| data | CostAnalysisVersionDto[] | |
| id* | string<uuid> | Cost analysis id for this version uuid |
| versionLabel* | string | Human-readable label for this version |
| changeType* | string | Iterations changeType of the feedback that produced this version; null for the root (no driving feedback) |
| status* | string | Lifecycle status of this version |
| feedbackOwnerId* | string<uuid> | User who owns the feedback loop for this version uuid |
| feedbackOwnerName* | string | Display name of the feedback owner |
| changeSummary* | string | Short summary of what changed in this version |
| feedbackSummary* | string | Short summary of the feedback that drove this version |
| createdAt* | string | When this version was created (ISO 8601) |
| hasBomValidationOverrides* | boolean | True when the driving feedback carries confirmed BOM validation overrides |
| meta | object | |
| totalCount | integer | Unbounded result count. Only present when ?count=true is passed. |
/cost-analysis/{id}
Get cost-analysis by ID
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| id | path | string<uuid> | required | |
| related | query | string[] | optional | Include related entities. Omit for all, "false" for none, or specify field names (repeatable, supports dot notation) |
Responses
| Field | Type | Description |
|---|---|---|
| data | CostAnalysisDto | |
| id* | string | Unique identifier for the cost analysis record |
| status* | string | Status of the cost analysis lifecycle. analysis_done = an AI pipeline run finished (the former "completed"); pending_review / pending_feedback / iteration are the human-in-the-loop iterations states (DLN-190). enum: pending, analysis_done, pending_review, pending_feedback, iteration, failed |
| analysisDate* | string | Date and time when the cost analysis was performed |
| productId | string | FK to the @product for which the cost analysis is performed |
| currency | string | Currency code for the cost analysis (e.g., USD, EUR) |
| bomId | string | FK to the bill of materials used as the basis for this cost analysis |
| countryOfOrigin | string | The country of origin for the product. This may impact the cost analysis due to factors like tariffs, shipping costs, and local market conditions. |
| importCountry | string | The country into which the product is imported. Used for tariff rate lookups. Defaults to US if not provided. |
| shouldCostAmount | number | Theoretical cost to produce the product, in minor currency units (e.g., cents) |
| shouldCostStdErr | number | Approximation of the standard error of the should-cost estimate, in minor currency units (e.g., cents) |
| scenarioContext | string | Named rate scenario this analysis ran under. Nullable. |
| analysisBasis | string | Basis of the analysis (e.g. 'should_cost'). |
| priorCostAnalysisId | string | Self-FK to the previous CA in a temporal lineage. Nullable (DLN-152 writes). |
| changeType | string | Classification of why this CA exists: BOM_REVISION for a new/updated bill of materials, RATE_REFRESH for a rate-only re-run. DLN-152/153 write this field. enum: BOM_REVISION, RATE_REFRESH |
| versionLabel | string | Human-readable label for this CA version. |
| rerunRoundCount | number | Denormalized count of with-rerun iteration rounds consumed on this chain. Defaults to 0; the feedback flow (DLN-194) increments it and enforces the round limit, rather than walking the chain on every check. |
| isInternalIteration | boolean | True when this CA version was produced by a Dalinea-internal iteration (DLN-334). Denormalized from the producing analysis-feedback's origin so the version-chain query can hide internal versions from external callers without re-deriving origin per row. Internal versions are excluded from the rerun count/cap. Defaults to false (rows predating DLN-334 and non-iteration analyses are external/customer-facing). Set only by the submit service / the orchestrator; immutable thereafter so a later PUT can't unhide/hide a version. |
| feedbackOwnerId | string | User who owns the feedback loop for this analysis (first-submitter lock). Nullable until claimed. |
| feedbackOwnerName | string | Display name of the feedback owner, captured at claim time. Nullable. |
| changeSummary | string | Short human-readable summary of what changed in this version. Nullable. |
| feedbackSummary | string | Short human-readable summary of the feedback that drove this version. Nullable. |
| qaVerdict | object | QA evaluation outcome. Nullable (DLN-158 writes; DLN-138 leaves null). |
| computeInputs | any | Snapshot of the run-time engine inputs NOT otherwise reconstructable from this analysis — raw financials scalars, the derived margins actually passed, and the option flags — plus the resolved tariff scalars for robust replay. Written by the orchestrator at the cost-analysis compute step (DLN-269). Makes the analysis self-describing so a recompute (iteration no-rerun, DLN-194) or audit can faithfully replay the run. Nullable on rows produced before this field existed. See ADR 0071. |
| userTariffOverride | any | A user-pinned HTS code and/or direct tariff rate that must survive AI pipeline reruns (DLN-202). Set from an iteration_no_rerun feedback submission and copied forward to every new version in the chain. The tariff-resolution step (orchestrator Step 3d) and the recompute engine read it as a CONSTRAINT before resolving: a pinned tariffRatePct is authoritative (used instead of dataset/AI resolution), while a pinned htsCode only overrides which code is looked up (the rate is still resolved). The resulting direct tariff adjustment is emitted with source=user_provided so GET /cost-analysis/:id distinguishes it from AI-estimated values. Nullable when the user has not pinned anything. |
| buckets | CostAnalysisBucketDto[] | Rollup buckets (Direct Materials, Salaries, Import Tariff, …) derived from component results. - accepts array of full objects, id strings, or id numbers |
| id* | string | Unique identifier for the cost analysis bucket record |
| name* | string | Name of the cost component (e.g., "direct materials", "production wages", etc.) |
| category* | string | Coarse classification (e.g. 'materials', 'labor', 'overhead', 'tariff', 'profit'). |
| costAnalysis* | any | The parent cost analysis - accepts full object, id string, or id number |
| currency* | string | Currency code for the cost analysis (e.g., USD, EUR) |
| cost* | number | Cost amount for this component in minor currency units (e.g., cents) |
| costMin* | number | Minimum estimated cost for this component in minor currency units (e.g., cents) |
| costMax* | number | Maximum estimated cost for this component in minor currency units (e.g., cents) |
| supportingData | object | Additional supporting data for this cost component as key-value pairs (e.g., dataset references, assumptions, calculation notes) |
| componentResults | CostAnalysisComponentResultDto[] | Per-BOM-component cost results (baselineCost, finalCost, stdErr). - accepts array of full objects, id strings, or id numbers |
| id* | string | Unique identifier for the component result |
| costAnalysis* | any | The parent cost analysis - accepts full object, id string, or id number |
| bomComponentId* | string | FK to BOM_COMPONENT.id. Stored as a plain uuid (no $ref) because the BOM lives in a separate standalone service — same convention as COST_ANALYSIS.productId and COST_ANALYSIS.bomId. |
| currency* | string | Currency code (e.g. USD, EUR) |
| baselineCost* | number | Pre-adjustment cost for this component, in minor currency units (cents). |
| finalCost* | number | Post-adjustment cost for this component, in minor currency units (cents). |
| stdErr | number | Approximate standard error of finalCost, in cents. Nullable (populated when Monte Carlo ran). |
| costMin | number | Lower bound (≈P10) of finalCost in minor currency units (cents). Nullable — populated only when Monte Carlo ran (same condition as stdErr). |
| costMax | number | Upper bound (≈P90) of finalCost in minor currency units (cents). Nullable — populated only when Monte Carlo ran (same condition as stdErr). |
| rateSnapshots | CostAnalysisRateSnapshotDto[] | Frozen rate snapshots (tariff, labor, energy, localization) used in this analysis - accepts array of full objects, id strings, or id numbers |
| id* | string | Unique identifier for the rate snapshot |
| costAnalysis | any | The parent cost analysis - accepts full object, id string, or id number |
| rateType* | string | Kind of rate captured enum: tariff, labor, energy, localization, manufacturer_financials |
| layer | string | base MFN rate, or a surcharge layered on top (e.g. Section 301) enum: base, surcharge |
| source* | string | Authoritative source of the rate. USER = a user-pinned tariff (DLN-202): the pin is a recorded rate fact, emitted as a base-layer snapshot so the analysis stays reproducible (ADR 0047) and the pin is queryable. enum: USITC HTS, WITS, AI, INTERNAL, EDGAR, USER |
| sourceTable | string | Dataset table the rate was read from (e.g. usitc_hts_10digit, wits_tariff_rates) |
| sourceVersionId | string | Source dataset version stamp (e.g. "2026HTSRev8" for USITC, "2023" for WITS) |
| lookupKey* | string | The HTS/HS6 code looked up |
| value* | number | Rate as a decimal fraction (e.g. 0.075 for 7.5%) |
| unit* | string | Unit of the value. "percent" = ad-valorem percent expressed as a decimal fraction (e.g. 0.075 for 7.5%). "ratio" = dimensionless multiplier (e.g. 1.25 = +25%, 0.80 = -20%). enum: percent, ratio |
| currency | string | Currency for specific (per-unit) rates; omitted/null for ad-valorem (optional) |
| effectiveDate | string | Effective date of the rate (YYYY-MM-DD) |
| appliesToComponentName | string | BOM component this snapshot applies to (for indirect tariffs); omitted/null for the direct/product-level tariff (optional). DLN-138 maps this to the component FK at persist time. |
| componentDrivers | CostAnalysisComponentDriverDto[] | Driver-level cost attributions (tariff, labor, energy, localization, overhead, etc.) for this analysis - accepts array of full objects, id strings, or id numbers |
| id* | string | Unique identifier for the component driver |
| costAnalysis | any | The parent cost analysis - accepts full object, id string, or id number |
| driver* | string | The driver type this row attributes cost to enum: tariff, labor, energy, commodity, localization, freight, overhead, volume_discount, process_adjustment, supplier_purchasing_power |
| amount* | number | Cost impact of this driver, in minor currency units (cents). Positive means the driver increased cost; negative means it decreased it. |
| stdErr | number | Approximate standard error of `amount`, in minor currency units (cents). |
| source* | string | How `amount` was derived enum: rate_snapshot, manual_adjustment, model |
| rateSnapshotId | string | FK to COST_ANALYSIS_RATE_SNAPSHOT.id when the driver was derived from an ingested rate. Stored as a plain uuid (no $ref) following the deferred-FK convention. Nullable (overhead drivers have source=manual_adjustment with no snapshot; synthesized tariff drivers use source=model with no snapshot). |
| appliesToComponentName | string | BOM component this driver applies to, when component-specific. Absent = driver applies at the cost-analysis / product level (v1 default for labor / energy / localization / overhead). DLN-138 maps to the component FK at persist time when present. |
| metadata | object | Driver-specific qualitative context (e.g. localization sub-factor breakdown). |
| referencePrices | CostAnalysisReferencePriceDto[] | Reference prices (historical/benchmark) compared against should-cost for this analysis (DLN-189). - accepts array of full objects, id strings, or id numbers |
| id* | string | Unique identifier for the reference price |
| costAnalysis | any | The parent cost analysis this reference price was used for - accepts full object, id string, or id number |
| price* | number | Reference price in minor currency units (e.g., cents) |
| currency* | string | ISO 4217 currency code (e.g., USD, EUR) |
| pricedDate | string | Date the price was paid or observed (YYYY-MM-DD); optional |
| source* | string | How this reference price was obtained enum: user_provided, ai_estimate |
| sourceReferencePriceId | string | When this row was carried over (cloned) from a prior cost analysis in the same product lineage, the id of the reference-price row it was cloned from. Stored as a plain uuid (no $ref) following the deferred-FK convention. Null for freshly-provided or estimated references. |
| savingsOpportunities | SavingsOpportunityDto[] | Savings opportunities derived from this analysis (DLN-247). At most one per run. - accepts array of full objects, id strings, or id numbers |
| id* | string | Unique identifier for the savings opportunity |
| costAnalysis | any | The cost analysis that identified this opportunity - accepts full object, id string, or id number |
| productId* | string | Product the opportunity is for. Plain uuid (no $ref) following the deferred-FK convention (product lives in another service). |
| amount* | number | Savings amount in minor currency units (cents): reference price minus should-cost. Positive = savings; may be zero or negative when the should-cost is at or above the reference price. |
| currency* | string | ISO 4217 currency code (matches the cost analysis run currency) |
| periodScope* | string | Basis the amount is expressed on enum: per_unit, annual, total |
| status* | string | Lifecycle status; opportunities are created "open" enum: open, closed |
| identifiedDate* | string | Date the opportunity was identified (the cost analysis date, YYYY-MM-DD) |
| comparisonBasis* | string | What the savings is measured against enum: prices_paid, prior_analysis, external_benchmark, target_cost |
| comparisonReferenceId* | string | Id of the COST_ANALYSIS_REFERENCE_PRICE row this opportunity was computed against. Plain string (no $ref) per the ERD's non-polymorphic-FK convention. |
| assigneeUserId | string | User the opportunity is assigned to (deferred-FK to the user service). Not populated by the pipeline; set by a later workflow. |
| targetCloseDate | string | Target date to act on the opportunity. Populated by a later workflow. |
| notes | string | Free-text notes. Populated by a later workflow. |
| adjustments | AdjustmentsDto[] | Adjustments applied to the cost model beyond the industry-average ASM baseline. Records which factors shaped the analysis without capturing exact numeric deltas. |
| type* | string | Identifier for the kind of adjustment applied enum: manufacturer_financials, yield_adjustment, compliance_overhead, setup_amortization, named_adjustment, tariff, indirect_tariff, volume_discount, supplier_purchasing_power |
| source* | string | Origin of this adjustment enum: user_provided, ai_estimate, analyst_judgment, system, edgar_auto, operator_entry |
| label | string | Human-readable description of what was adjusted |
| metadata | object | Adjustment-specific qualitative context (no dollar amounts). For type="manufacturer_financials": may include - cogsRatioAdjusted (boolean) - profitMarginOverridden (boolean) - fiscalYear (integer): the FY the financials describe - companyFinancialsId (uuid): the specific company_financials row that fed this run, enabling audit even after the cache rolls to a newer filing - financialsSource ("edgar" | "manual" | "llm" | "dto"): where the financials came from for this run - sgaCompleteness ({found:[...], missing:[...]}): which SGA components were present vs missing from the source filing - operatingMarginSource ("edgar_sga" | "asm_industry_average"): whether annual SGA was available or the ASM industry average was used for the operating-margin component - llmCitations ([{field, url, note}]): present only when financialsSource == "llm" For type="tariff" (direct product-level import tariff): may include - importCountry (string) - countryOfOrigin (string) - ratePercent (number) For type="indirect_tariff" (tariffs on foreign-sourced BOM components): may include - components (object): per-component breakdown of the indirect tariff impact |
| meta | object |
User
User identity and profile records. Each user maps 1:1 to a Firebase Auth account.
/users/{id}
Get user by ID (scoped to caller membership)
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| id | path | string<uuid> | required |
Responses
| Field | Type | Description |
|---|---|---|
| data | UserDto | |
| id* | string | Unique identifier for the user |
| firebaseUid | string | Firebase Auth UID — links this record to the user's GCIP auth account. Unique across all non-null values. Server-set: for INTERNAL users, User.AfterCreate calls tenant.createUser() and writes the returned uid back to this row; for EXTERNAL (invited) users the uid is bound at first SSO sign-in via resolve-invite (DLN-266) and starts as null. Any value supplied on POST is rejected. Immutable after creation. Uniqueness on non-null values is enforced by a partial unique index (not a Cruddy-managed constraint); see scripts/dln-266-firebase-uid-partial-index.sql. |
| email* | string | User's email address. Unique across all users. |
| firstName* | string | User's first name |
| lastName* | string | User's last name |
| displayName* | string | Display name shown in the UI (may differ from firstName + lastName) |
| image | string | GCS filename for the user's profile picture |
| title | string | Job title or role at the user's organization |
| phone | string | Contact phone number |
| bio | string | Short biography or about text |
| userType* | string | Whether this user is a Dalinea employee (INTERNAL) or a client user (EXTERNAL). Immutable after creation. enum: INTERNAL, EXTERNAL |
| status* | string | Lifecycle status of the user account enum: ACTIVE, INACTIVE, SUSPENDED, DELETED |
| language* | string | Preferred language (ISO 639-1 two-character code, e.g. "en") |
| lastLogin | string | Timestamp of the user's most recent login |
| firebaseTenantId | string | GCIP tenant ID for the organization this user authenticates under. Present for tenant-scoped users (EXTERNAL, DALINEA_ANALYST); absent for platform-scoped INTERNAL users (DALINEA_ADMIN) who authenticate at the project level. Determines which GCIP tenant createUser targets. |
| meta | object |
/users/{id}
Update user (scoped to caller membership)
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| id | path | string<uuid> | required |
Request Body
| Field | Type | Description |
|---|---|---|
| id* | string | Unique identifier for the user |
| firebaseUid | string | Firebase Auth UID — links this record to the user's GCIP auth account. Unique across all non-null values. Server-set: for INTERNAL users, User.AfterCreate calls tenant.createUser() and writes the returned uid back to this row; for EXTERNAL (invited) users the uid is bound at first SSO sign-in via resolve-invite (DLN-266) and starts as null. Any value supplied on POST is rejected. Immutable after creation. Uniqueness on non-null values is enforced by a partial unique index (not a Cruddy-managed constraint); see scripts/dln-266-firebase-uid-partial-index.sql. |
| email* | string | User's email address. Unique across all users. |
| firstName* | string | User's first name |
| lastName* | string | User's last name |
| displayName* | string | Display name shown in the UI (may differ from firstName + lastName) |
| image | string | GCS filename for the user's profile picture |
| title | string | Job title or role at the user's organization |
| phone | string | Contact phone number |
| bio | string | Short biography or about text |
| userType* | string | Whether this user is a Dalinea employee (INTERNAL) or a client user (EXTERNAL). Immutable after creation. enum: INTERNAL, EXTERNAL |
| status* | string | Lifecycle status of the user account enum: ACTIVE, INACTIVE, SUSPENDED, DELETED |
| language* | string | Preferred language (ISO 639-1 two-character code, e.g. "en") |
| lastLogin | string | Timestamp of the user's most recent login |
| firebaseTenantId | string | GCIP tenant ID for the organization this user authenticates under. Present for tenant-scoped users (EXTERNAL, DALINEA_ANALYST); absent for platform-scoped INTERNAL users (DALINEA_ADMIN) who authenticate at the project level. Determines which GCIP tenant createUser targets. |
Responses
| Field | Type | Description |
|---|---|---|
| data | UserDto | |
| id* | string | Unique identifier for the user |
| firebaseUid | string | Firebase Auth UID — links this record to the user's GCIP auth account. Unique across all non-null values. Server-set: for INTERNAL users, User.AfterCreate calls tenant.createUser() and writes the returned uid back to this row; for EXTERNAL (invited) users the uid is bound at first SSO sign-in via resolve-invite (DLN-266) and starts as null. Any value supplied on POST is rejected. Immutable after creation. Uniqueness on non-null values is enforced by a partial unique index (not a Cruddy-managed constraint); see scripts/dln-266-firebase-uid-partial-index.sql. |
| email* | string | User's email address. Unique across all users. |
| firstName* | string | User's first name |
| lastName* | string | User's last name |
| displayName* | string | Display name shown in the UI (may differ from firstName + lastName) |
| image | string | GCS filename for the user's profile picture |
| title | string | Job title or role at the user's organization |
| phone | string | Contact phone number |
| bio | string | Short biography or about text |
| userType* | string | Whether this user is a Dalinea employee (INTERNAL) or a client user (EXTERNAL). Immutable after creation. enum: INTERNAL, EXTERNAL |
| status* | string | Lifecycle status of the user account enum: ACTIVE, INACTIVE, SUSPENDED, DELETED |
| language* | string | Preferred language (ISO 639-1 two-character code, e.g. "en") |
| lastLogin | string | Timestamp of the user's most recent login |
| firebaseTenantId | string | GCIP tenant ID for the organization this user authenticates under. Present for tenant-scoped users (EXTERNAL, DALINEA_ANALYST); absent for platform-scoped INTERNAL users (DALINEA_ADMIN) who authenticate at the project level. Determines which GCIP tenant createUser targets. |
| meta | object |
Organization
Tenant organizations. Each owns a GCIP tenant and one or more email domains used for sign-in discovery.
/organizations/{id}
Get organization by ID (scoped to caller membership)
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| id | path | string<uuid> | required |
Responses
| Field | Type | Description |
|---|---|---|
| data | OrganizationDto | |
| id* | string | Unique identifier for the organization |
| name* | string | Display name of the organization |
| status* | string | Lifecycle status of the organization enum: ACTIVE, ARCHIVED, SUSPENDED |
| legalEntityName | string | Full legal entity name (may differ from display name) |
| taxId | string | Tax identification number (EIN, VAT, etc.) |
| crmId | string | CRM system identifier for this organization |
| companyId | string | FK to the @company record linked to this organization |
| defaultCurrency | string | Default ISO 4217 currency code (e.g. USD, EUR) |
| fiscalYearStart* | number | Month in which the fiscal year starts (1 = January, 12 = December) |
| dateFormat* | string | Preferred date display format for this organization enum: MM/DD/YYYY, DD/MM/YYYY, YYYY-MM-DD |
| defaultTimeZone* | string | Default time zone identifier for this organization (e.g. America/New_York, America/Chicago, Europe/Berlin, Asia/Tokyo) |
| domains* | string[] | Email domains associated with this organization (e.g. ["acme.com", "acme-legacy.com"]). Used for tenant discovery. Must be unique across all organizations. |
| firebaseTenantId | string | Google Cloud Identity Platform (GCIP) tenant ID for this organization. Auto-generated by GCIP (not a UUID). Set after org creation by the Firebase Admin SDK event listener. Required for EXTERNAL user authentication. |
| meta | object |
/organizations
List organization documents
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| firebaseTenantId | query | string[] | optional | Filter by a set of values (repeatable param) |
| defaultTimeZone | query | string[] | optional | Filter by a set of values (repeatable param) |
| dateFormat | query | string[] | optional | Filter by a set of values (repeatable param) |
| fiscalYearStart | query | string[] | optional | Filter by a set of values (repeatable param) |
| defaultCurrency | query | string[] | optional | Filter by a set of values (repeatable param) |
| companyId | query | string[] | optional | Filter by a set of values (repeatable param) |
| crmId | query | string[] | optional | Filter by a set of values (repeatable param) |
| taxId | query | string[] | optional | Filter by a set of values (repeatable param) |
| legalEntityName | query | string[] | optional | Filter by a set of values (repeatable param) |
| status | query | string[] | optional | Filter by a set of values (repeatable param) |
| name | query | string[] | optional | Filter by a set of values (repeatable param) |
| id | query | string[] | optional | Filter by a set of values (repeatable param) |
| firebaseTenantId[contains] | query | string | optional | Case-insensitive substring match |
| defaultTimeZone[contains] | query | string | optional | Case-insensitive substring match |
| dateFormat[contains] | query | string | optional | Case-insensitive substring match |
| defaultCurrency[contains] | query | string | optional | Case-insensitive substring match |
| crmId[contains] | query | string | optional | Case-insensitive substring match |
| taxId[contains] | query | string | optional | Case-insensitive substring match |
| legalEntityName[contains] | query | string | optional | Case-insensitive substring match |
| status[contains] | query | string | optional | Case-insensitive substring match |
| name[contains] | query | string | optional | Case-insensitive substring match |
| count | query | boolean | optional | Include totalCount of unbounded results in response meta |
| related | query | string[] | optional | Include related entities. Omit for all, "false" for none, or specify field names (repeatable, supports dot notation) |
| sortOrder | query | string | optional | Sort direction (default: asc) |
| sortBy | query | string | optional | Field name to sort by |
| offset | query | number | optional | |
| limit | query | number | optional |
Responses
| Field | Type | Description |
|---|---|---|
| data | OrganizationDto[] | |
| id* | string | Unique identifier for the organization |
| name* | string | Display name of the organization |
| status* | string | Lifecycle status of the organization enum: ACTIVE, ARCHIVED, SUSPENDED |
| legalEntityName | string | Full legal entity name (may differ from display name) |
| taxId | string | Tax identification number (EIN, VAT, etc.) |
| crmId | string | CRM system identifier for this organization |
| companyId | string | FK to the @company record linked to this organization |
| defaultCurrency | string | Default ISO 4217 currency code (e.g. USD, EUR) |
| fiscalYearStart* | number | Month in which the fiscal year starts (1 = January, 12 = December) |
| dateFormat* | string | Preferred date display format for this organization enum: MM/DD/YYYY, DD/MM/YYYY, YYYY-MM-DD |
| defaultTimeZone* | string | Default time zone identifier for this organization (e.g. America/New_York, America/Chicago, Europe/Berlin, Asia/Tokyo) |
| domains* | string[] | Email domains associated with this organization (e.g. ["acme.com", "acme-legacy.com"]). Used for tenant discovery. Must be unique across all organizations. |
| firebaseTenantId | string | Google Cloud Identity Platform (GCIP) tenant ID for this organization. Auto-generated by GCIP (not a UUID). Set after org creation by the Firebase Admin SDK event listener. Required for EXTERNAL user authentication. |
| meta | object | |
| totalCount | integer | Unbounded result count. Only present when ?count=true is passed. |
Feature Flags
Feature flag configuration and resolution.
/feature-flags/defaults
Get system-wide default feature flag values
Responses
Imports
Upload files for sharing or to feed into batch workflows like cost analysis.
/imports/upload-url
Get a signed PUT URL for uploading an import file.
Validates the asserted MIME type against the registry for the given importType. Returns a fileLocation the client must echo back to POST /imports once the upload is complete.
Request Body
| Field | Type | Description |
|---|---|---|
| originalFilename* | string | Original filename (used as the leaf of the object path). |
| mimeType* | string | Client-asserted MIME type. Validated against the cost-analysis allowlist. |
| sizeBytes* | number | Client-asserted file size in bytes. Rejected if FMS limit exceeded. |
Responses
| Field | Type | Description |
|---|---|---|
| data | ImportUploadUrlResponseDto | |
| uploadUrl* | string | |
| fileLocation* | string | GCS path of the form {bucket}/{tenantId}/{uuid}/{filename}. |
| expiresAt* | string | |
| contentType* | string | MIME type the PUT must declare (echoed as Content-Type). |
| requiredHeaders* | object | Headers the client MUST send verbatim on the PUT for the V4 signature to validate. Always includes content-type; includes x-goog-content-length-range when a size cap is set. Send exactly these — omitting one yields a 403 SignatureDoesNotMatch. |
| meta | object |
/imports/preview
Preview the columns + first few rows of an uploaded file.
For workflow imports the UI uses this to build column mappings. Streams the file through FMS, parses up to maxRows rows, and returns them.
Request Body
| Field | Type | Description |
|---|---|---|
| fileLocation* | string | fileLocation returned from upload-url, of the form {bucket}/{tenantId}/{uuid}/{filename}. |
| maxRows | number | Max sample rows to return. Default 5, max 50. |
Responses
| Field | Type | Description |
|---|---|---|
| data | PreviewResponseDto | |
| columns* | string[] | |
| sampleRows* | object[] | |
| totalRowsEstimate | number | Best-effort total-rows count, when the parser can compute it. |
| meta | object |
/imports
List import documents
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| failedRowCount | query | string[] | optional | Filter by a set of values (repeatable param) |
| processedRowCount | query | string[] | optional | Filter by a set of values (repeatable param) |
| totalRowCount | query | string[] | optional | Filter by a set of values (repeatable param) |
| errorMessage | query | string[] | optional | Filter by a set of values (repeatable param) |
| approvedAt | query | string[] | optional | Filter by a set of values (repeatable param) |
| approvedByUserId | query | string[] | optional | Filter by a set of values (repeatable param) |
| uploadedByUserId | query | string[] | optional | Filter by a set of values (repeatable param) |
| status | query | string[] | optional | Filter by a set of values (repeatable param) |
| type | query | string[] | optional | Filter by a set of values (repeatable param) |
| sizeBytes | query | string[] | optional | Filter by a set of values (repeatable param) |
| mimeType | query | string[] | optional | Filter by a set of values (repeatable param) |
| originalFilename | query | string[] | optional | Filter by a set of values (repeatable param) |
| fileLocation | query | string[] | optional | Filter by a set of values (repeatable param) |
| description | query | string[] | optional | Filter by a set of values (repeatable param) |
| name | query | string[] | optional | Filter by a set of values (repeatable param) |
| id | query | string[] | optional | Filter by a set of values (repeatable param) |
| errorMessage[contains] | query | string | optional | Case-insensitive substring match |
| approvedByUserId[contains] | query | string | optional | Case-insensitive substring match |
| uploadedByUserId[contains] | query | string | optional | Case-insensitive substring match |
| status[contains] | query | string | optional | Case-insensitive substring match |
| type[contains] | query | string | optional | Case-insensitive substring match |
| mimeType[contains] | query | string | optional | Case-insensitive substring match |
| originalFilename[contains] | query | string | optional | Case-insensitive substring match |
| fileLocation[contains] | query | string | optional | Case-insensitive substring match |
| description[contains] | query | string | optional | Case-insensitive substring match |
| name[contains] | query | string | optional | Case-insensitive substring match |
| count | query | boolean | optional | Include totalCount of unbounded results in response meta |
| related | query | string[] | optional | Include related entities. Omit for all, "false" for none, or specify field names (repeatable, supports dot notation) |
| sortOrder | query | string | optional | Sort direction (default: asc) |
| sortBy | query | string | optional | Field name to sort by |
| offset | query | number | optional | |
| limit | query | number | optional |
Responses
| Field | Type | Description |
|---|---|---|
| data | ImportDto[] | |
| id | string | Unique identifier for the import |
| name* | string | User-supplied display name for the import |
| description | string | Optional user-supplied description |
| fileLocation* | string | GCS path of the form "{bucket}/{tenantId}/{uuid}/{filename}" |
| originalFilename* | string | Filename as supplied by the user at upload time |
| mimeType* | string | Actual MIME type reported by GCS at create time |
| sizeBytes* | number | Actual size in bytes reported by GCS at create time |
| type* | string | Import type (single supported type today; registry returns when a second lands). enum: COST_ANALYSIS_IMPORT |
| status* | string | Import lifecycle status enum: PENDING_CONFIG, PENDING_APPROVAL, PROCESSING, COMPLETED, PARTIALLY_COMPLETED, FAILED, REJECTED |
| uploadedByUserId* | string | ID of the user that uploaded this import (from the request's auth context) |
| approvedByUserId | string | ID of the internal admin that approved this import (set on approval) |
| approvedAt | string | Timestamp the import was approved |
| config | object | Type-specific configuration. Validated by the service layer per type. |
| errorMessage | string | Error message if the import failed during processing |
| totalRowCount | number | Total rows the processor identified in the file |
| processedRowCount | number | Number of rows the processor has finished (successfully or otherwise) |
| failedRowCount | number | Number of rows that failed processing |
| meta | object | |
| totalCount | integer | Unbounded result count. Only present when ?count=true is passed. |
/imports
Create an Import record from an uploaded file.
Request Body
| Field | Type | Description |
|---|---|---|
| name* | string | |
| description | string | |
| fileLocation* | string | fileLocation returned from POST /imports/upload-url. |
| originalFilename* | string | |
| config | object | Cost-analysis configuration. Validated against CostAnalysisImportConfig. |
Responses
| Field | Type | Description |
|---|---|---|
| data | ImportDto | |
| id | string | Unique identifier for the import |
| name* | string | User-supplied display name for the import |
| description | string | Optional user-supplied description |
| fileLocation* | string | GCS path of the form "{bucket}/{tenantId}/{uuid}/{filename}" |
| originalFilename* | string | Filename as supplied by the user at upload time |
| mimeType* | string | Actual MIME type reported by GCS at create time |
| sizeBytes* | number | Actual size in bytes reported by GCS at create time |
| type* | string | Import type (single supported type today; registry returns when a second lands). enum: COST_ANALYSIS_IMPORT |
| status* | string | Import lifecycle status enum: PENDING_CONFIG, PENDING_APPROVAL, PROCESSING, COMPLETED, PARTIALLY_COMPLETED, FAILED, REJECTED |
| uploadedByUserId* | string | ID of the user that uploaded this import (from the request's auth context) |
| approvedByUserId | string | ID of the internal admin that approved this import (set on approval) |
| approvedAt | string | Timestamp the import was approved |
| config | object | Type-specific configuration. Validated by the service layer per type. |
| errorMessage | string | Error message if the import failed during processing |
| totalRowCount | number | Total rows the processor identified in the file |
| processedRowCount | number | Number of rows the processor has finished (successfully or otherwise) |
| failedRowCount | number | Number of rows that failed processing |
| meta | object |
/imports/{id}
Get import by ID
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| id | path | string<uuid> | required | |
| related | query | string[] | optional | Include related entities. Omit for all, "false" for none, or specify field names (repeatable, supports dot notation) |
Responses
| Field | Type | Description |
|---|---|---|
| data | ImportDto | |
| id | string | Unique identifier for the import |
| name* | string | User-supplied display name for the import |
| description | string | Optional user-supplied description |
| fileLocation* | string | GCS path of the form "{bucket}/{tenantId}/{uuid}/{filename}" |
| originalFilename* | string | Filename as supplied by the user at upload time |
| mimeType* | string | Actual MIME type reported by GCS at create time |
| sizeBytes* | number | Actual size in bytes reported by GCS at create time |
| type* | string | Import type (single supported type today; registry returns when a second lands). enum: COST_ANALYSIS_IMPORT |
| status* | string | Import lifecycle status enum: PENDING_CONFIG, PENDING_APPROVAL, PROCESSING, COMPLETED, PARTIALLY_COMPLETED, FAILED, REJECTED |
| uploadedByUserId* | string | ID of the user that uploaded this import (from the request's auth context) |
| approvedByUserId | string | ID of the internal admin that approved this import (set on approval) |
| approvedAt | string | Timestamp the import was approved |
| config | object | Type-specific configuration. Validated by the service layer per type. |
| errorMessage | string | Error message if the import failed during processing |
| totalRowCount | number | Total rows the processor identified in the file |
| processedRowCount | number | Number of rows the processor has finished (successfully or otherwise) |
| failedRowCount | number | Number of rows that failed processing |
| meta | object |
/imports/{id}
Partial-update name/description/config. Recomputes status from config.
Allowed only while the import is PENDING_CONFIG or PENDING_APPROVAL. Setting config recomputes status: valid → PENDING_APPROVAL, invalid → PENDING_CONFIG.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| id | path | string<uuid> | required |
Request Body
| Field | Type | Description |
|---|---|---|
| name | string | |
| description | string | |
| config | object | Replaces the previous config. The resulting status is recomputed from validity. |
Responses
| Field | Type | Description |
|---|---|---|
| data | ImportDto | |
| id | string | Unique identifier for the import |
| name* | string | User-supplied display name for the import |
| description | string | Optional user-supplied description |
| fileLocation* | string | GCS path of the form "{bucket}/{tenantId}/{uuid}/{filename}" |
| originalFilename* | string | Filename as supplied by the user at upload time |
| mimeType* | string | Actual MIME type reported by GCS at create time |
| sizeBytes* | number | Actual size in bytes reported by GCS at create time |
| type* | string | Import type (single supported type today; registry returns when a second lands). enum: COST_ANALYSIS_IMPORT |
| status* | string | Import lifecycle status enum: PENDING_CONFIG, PENDING_APPROVAL, PROCESSING, COMPLETED, PARTIALLY_COMPLETED, FAILED, REJECTED |
| uploadedByUserId* | string | ID of the user that uploaded this import (from the request's auth context) |
| approvedByUserId | string | ID of the internal admin that approved this import (set on approval) |
| approvedAt | string | Timestamp the import was approved |
| config | object | Type-specific configuration. Validated by the service layer per type. |
| errorMessage | string | Error message if the import failed during processing |
| totalRowCount | number | Total rows the processor identified in the file |
| processedRowCount | number | Number of rows the processor has finished (successfully or otherwise) |
| failedRowCount | number | Number of rows that failed processing |
| meta | object |
/imports/{id}
Delete an Import and its GCS object. Rejected while PROCESSING.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| id | path | string<uuid> | required | |
| hard | query | string | required |
Responses
/imports/{id}/jobs
List child pipeline job rows for an import with their own status (paginated).
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| id | path | string<uuid> | required | |
| pageSize | query | number | optional | Default 50, max 200 |
| page | query | number | optional | Default 1 |
Responses
| Field | Type | Description |
|---|---|---|
| data* | ImportJobItemDto[] | |
| importJobId* | string | |
| pipelineJobId* | string | |
| rowIndex* | number | |
| rowData* | object | |
| submissionError | string | |
| pipelineStatus* | string | Live status from the Pipeline Service. |
| pipelineStep | string | |
| meta* | ImportJobsResponseMetaDto | |
| totalCount* | number | |
| aggregate* | ImportJobsAggregateDto | |
| total* | number | |
| completed* | number | |
| failed* | number | |
| inProgress* | number |
/imports/{id}/errors
List row-level errors for an import (paginated). Empty list when none.
Returns the failed job rows recorded during processing (rows with status "failed" and an error message). These cover both pre-submission and execution failures; live pipeline execution status is on GET /imports/:id/jobs.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| id | path | string<uuid> | required | |
| pageSize | query | number | optional | Default 50, max 200 |
| page | query | number | optional | Default 1 |
Responses
| Field | Type | Description |
|---|---|---|
| data* | ImportRowErrorDto[] | |
| rowIndex* | number | |
| rowData* | object | |
| errorMessage* | string | Why the row failed during processing. |
| meta* | ImportErrorsResponseMetaDto | |
| totalCount* | number |
/imports/{id}/download-url
Sign a download URL for the import file. Tenant-scoped.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| id | path | string<uuid> | required |
Responses
| Field | Type | Description |
|---|---|---|
| data | ImportDownloadUrlResponseDto | |
| downloadUrl* | string | |
| expiresAt* | string | |
| meta | object |