Skip to main content

Variant EPDs

Variant EPDs are derived from an approved Reference EPD with different product parameters. They enable manufacturers to publish EPDs for product families without repeating the full verification process.

Prerequisites​

Before creating variants, you need:

  1. A Reference EPD in approved or published status. Approving it locked its model, which every variant is compared with (see Model lock).
  2. An approved LCA version in the same project
  3. Constraint definitions on the spec/template (so automated checks can run)

Creating a variant​

POST /api/v2/epds/{reference_epd_id}/variants/
Content-Type: application/json

{
"parameters": {
"strength_class": "C30/37",
"cement_content": 320,
"water_cement_ratio": 0.45
}
}

The parameters object contains the product-specific values that differ from the reference. The variant EPD inherits all other data from the reference.

The variant starts in generated status.

Locked fields are enforced on variant document updates

If the reference EPD declared an authoring_policy.locked_fields list, any subsequent PUT /api/v2/epds/{variant_id}/document/ that diverges from the reference on one of those fields is rejected with a 400 validation_error. The lock list and values come from the reference's approved constraint version. The variant's detail carries them as variant_envelope.locked_field_ids and variant_envelope.locked_values. When a revision of the reference is approved, draft and flagged variants are updated to the new locked values automatically. Submitting a variant whose stored locked values differ from the approved ones is refused. The typical locked fields are methodology-related (LCA software, primary data year, unit of measure, reference standards) — see Locking fields so variants can't change them for how to set the list on the reference.

Variant lifecycle​

A freshly generated variant resolves one of three ways: it passes the auto-approve gate (constraint checks + outlier detection) and lands in auto_approved; an outlier scan flaggeds it for human follow-up (after which a reviewer can approve or reject it); or a reviewer approves it directly to approved. There is no separate "start review" step — submission and review start in the same call.

Automated verification​

When you auto-approve a variant, the system runs constraint validation automatically:

POST /api/v2/epds/{reference_epd_id}/variants/{variant_id}/auto-approve/

What happens during auto-approve​

  1. Constraint validation — all constraints from the spec/template are checked against the variant's parameter values
  2. Error-severity violations block — if any constraint with severity: "error" fails, the auto-approve is rejected with a 400 error listing the violations
  3. Non-blocking violations stored — warnings and info-level violations are recorded on the variant EPD for reviewer visibility
  4. PDF generation triggered — on success, PDF generation is enqueued

Checking constraint violations​

Validate a variant against its constraint rules:

POST /api/v2/epds/{reference_epd_id}/variants/{variant_id}/validate/

Outlier detection​

Unstable endpoints

The flag and outlier-flags endpoints are unstable and may change without notice. They are not covered by the API contract — the supported variant surface is create, list, auto-approve, and validate. They are documented here to explain how outlier flagging behaves on the platform; do not build integrations against them.

Variants can be flagged with outlier information:

POST /api/v2/epds/{reference_epd_id}/variants/{variant_id}/flag/
{
"outlier_flags": [
{
"indicator": "gwp_a1a3",
"expected_value": 350.0,
"actual_value": 520.0,
"deviation_percent": 48.6,
"severity": "warning"
}
]
}

List outlier flags:

GET /api/v2/epds/{reference_epd_id}/variants/{variant_id}/outlier-flags/

Model lock​

A variant is only as trustworthy as the model that produced it. When its reference EPD was approved, the platform locked the reference's model: the EPD tool and its version, the PCR spec version, and the template's constraints and external input fields. Each time a variant is submitted or resubmitted, its current model is compared with that lock and the result is recorded in the variant's submission snapshot:

  • conformant — the variant matches the lock.
  • drift — at least one coordinate differs: the EPD tool, the tool's version, the PCR spec version, the template, or the template's constraints and external inputs.
  • no_lock — the reference has no locked model yet. This applies to references approved before model locks existed, until an operator backfills them. There is nothing to compare against, and nothing blocks.

By default, a drifted variant is flagged, not blocked. The drift is logged, stored in the variant's submission snapshot and reported on the EPD detail's model_lock block, which lists each drifted coordinate as {coordinate, label, locked, actual}. Submitting a drifted variant never takes the auto-approve shortcut; it goes to in_review so a verifier sees it. Background auto-verification skips it too.

Where the variant_model_lock_block feature flag is on for the organization that owns the EPD (it is off by default), drift blocks the variant's submission and resubmission with 400 model_lock_drift. The error's details list the drifted coordinates.

See Submission snapshots and the model lock for what a snapshot records and the exact comparison rules.

Non-prod testing shortcuts​

In non-production environments, use force_status to bypass status and constraint checks:

# Force auto-approve (skips constraints)
POST /api/v2/epds/{epd_id}/variants/{variant_id}/auto-approve/
{"force_status": "auto_approved"}

# Force manual approve (skips status + constraints)
POST /api/v2/epds/{epd_id}/variants/{variant_id}/approve/
{"force_status": "approved"}

# Force reject (skips status check)
POST /api/v2/epds/{epd_id}/variants/{variant_id}/reject/
{"force_status": "rejected"}

The force_status parameter is rejected with a 400 in production. See Verification Testing Shortcuts for the full list of supported endpoints.

Listing variants​

GET /api/v2/epds/{reference_epd_id}/variants/?cursor=&limit=25

Returns a paginated list of all variants for the reference EPD, including their status, parameters, and constraint violation counts.