---
title: "Estimate experiment cost"
method: POST
path: "/api/v1/experiments/cost-estimate"
tags: ["experiments"]
---

# Estimate experiment cost

`POST /api/v1/experiments/cost-estimate`

## Request

- Base URL: `https://devs.adaptyvbio.com`
- URL: `https://devs.adaptyvbio.com/api/v1/experiments/cost-estimate`
- Auth: HTTP bearer

Calculates the estimated cost for an experiment without creating it.
Useful for previewing costs before submission.

# Request Body

Accepts an `experiment_spec` matching the creation endpoint format:

```json
{
  "experiment_spec": {
    "experiment_type": "screening",
    "method": "bli",
    "target_id": "019a03da-b87f-7e15-8b02-cef171c9871d",
    "sequences": {
      "seq1": "MKTL...",
      "seq2": "EVQL..."
    },
    "n_replicates": 3
  }
}
```

# Response

Returns a detailed cost breakdown including:
- `pricing_version`: The pricing rules applied (e.g., "v1_2026-01-20")
- `assay`: Per-experiment-type costs with base and replicate pricing
- `materials`: Target material costs (for binding experiments)
- `total_cents`: Sum of all costs in USD cents

# Complete Estimate Response

When the target has self-service pricing:
```json
{
  "breakdown": {
    "pricing_version": "v1_2026-01-20",
    "assay": { "name": "screening", "base_cents": 14900, "replicate_addon_cents": 5800, "subtotal_cents": 103500 },
    "materials": { "target": { "name": "Human PD-L1", "target_catalog_id": "019a03da-b87f-7e15-8b02-cef171c9871d" }, "price_per_sequence_cents": 500, "subtotal_cents": 2500 },
    "total_cents": 106000
  },
  "incomplete": null,
  "warnings": []
}
```

# Incomplete Estimate Response

When the target lacks self-service pricing (e.g., custom proteins), you'll
receive an incomplete estimate with assay costs but `materials_unavailable`:
```json
{
  "breakdown": null,
  "incomplete": {
    "pricing_version": "v1_2026-01-20",
    "assay": { "name": "screening", "base_cents": 14900, "replicate_addon_cents": 5800, "subtotal_cents": 103500 },
    "materials_unavailable": {
      "target": { "name": "This target", "target_catalog_id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee" },
      "reason": "This target is not yet onboarded to self-service pricing. You'll receive a quote with full price information."
    }
  },
  "warnings": []
}
```

Use `GET /targets?selfservice_only=true` to list targets with complete pricing.

# Notes

- **All prices exclude VAT**; taxes calculated at invoicing based on jurisdiction
- Requires authentication with experiment read permission
- Does not create an experiment
- Pricing is based on the current date (not a future experiment date)
- Targets without self-service pricing return incomplete estimates (not errors)
- Experiments created before pricing v1 (2026-01-20) cannot be estimated

## Request body

- CostEstimateRequest: Request payload for cost estimation. Contains the same experiment specification fields as creation, but does not require a name or project association. # Example ```json { "experiment_spec": { "experiment_type": "screening", "method": "bli", "target_id": "019a03da-b87f-7e15-8b02-cef171c9871d", "sequences": { "seq1": "EVQLVESGGGLVQPGGSLRLSCAASGFTFS...", "seq2": "MKTLVLLALLVGAALA..." }, "n_replicates": 3 } } ```
  - `experiment_spec` ExperimentSpec, required: Request body for creating an experiment (`POST /experiments`). Required fields differ by experiment type. The matrix below is the authoritative contract; submissions that violate it are rejected with a 400 listing every problem at once. * `required` — must be set. * `rejected` — must not be set for this type. * `optional` / `≥1` / ranges — accepted as stated; the noted default applies when omitted. | Field | Affinity | Screening | Thermostability | Fluorescence | Expression | EpitopeBinning | EnzymeActivity | |-------------------------------|------------|-----------|-----------------|--------------|------------|---------------------------|----------------| | `experiment_type` | required | required | required | required | required | required | required | | `method` (`bli` \| `spr`) | required | required | rejected | rejected | rejected | rejected | rejected | | `target_id` (UUID) | required | required | rejected | rejected | rejected | required | rejected | | `sequences` | ≥1 | ≥1 | ≥1 | ≥1 | ≥1 | multiple of 4, range 4–28 | ≥1 | | `n_replicates` | optional | optional | optional | optional | optional | rejected | optional | | `antigen_concentrations` | default `[1000.0, 316.2, 100.0, 31.6, 0.0]` nM | — | — | — | — | — | — | | `parameters` (free-form JSON) | optional | optional | optional | optional | optional | optional | optional | # Example ```json { "experiment_type": "screening", "method": "bli", "target_id": "019a03da-b87f-7e15-8b02-cef171c9871d", "sequences": { "mAb1": "EVQLVESGGGLVQPGGSLRLSCAASGFTFS...", "control": {"aa_string": "MKTLVLLALLV...", "control": true} }, "n_replicates": 3 } ```
    - `antigen_concentrations` number[], nullable: Antigen concentrations to test (in nanoMolar)
    - `experiment_type` 'affinity' | 'screening' | 'thermostability' | 'fluorescence' | 'expression' | 'epitope_binning' | 'enzyme_activity', required: Experiment type determining the assay workflow.
    - `method` 'bli' | 'spr': The measurement method (BLI or SPR). Required for affinity and screening; must be omitted for all other types.
    - `n_replicates` integer, nullable: Number of technical replicates (minimum 1, recommended 3+)
    - `parameters` object, nullable: Advanced experiment-specific settings. Most experiments leave this null. When provided, the object round-trips through the experiment detail with one addition: the read path merges the `experiment_type` discriminator into it, so a submitted `{"note":"x"}` reads back as `{"experiment_type":"...","note":"x"}`. A user-supplied `experiment_type` key is preserved as-is — the discriminator is only inserted when absent.
    - `sequences` object: Sequences keyed by a human readable name. Accepts either simple amino acid strings or rich objects with control flags and metadata.
    - `target_id` string, uuid, nullable: UUID of the target antigen from the catalog, required when creating binding experiments (affinity, screening, epitope binning); only catalog targets can be specified. On the experiment read response the resolved target is returned as `target` (see `target.target_catalog_id`).

## Response `200`

Cost estimate calculated

- CostEstimateResponse: Response wrapper for cost estimation endpoint. Contains either a complete breakdown (when all pricing is available) or an incomplete estimate (when target lacks self-service pricing).
  - `breakdown` CostBreakdown: Complete cost breakdown for an experiment. Aggregates assay costs and optional material costs into a total estimate. Used for both cost estimation endpoint responses and dynamic experiment costs. All amounts are in USD cents and **exclude VAT**.
    - `assay` AssayCost, required: Assay cost breakdown for a specific experiment type. # Pricing Formula ```text per_sequence_cost = unit_price + max(0, n_replicates - 1) × replicate_price subtotal = sequence_count × per_sequence_cost ``` The first replicate is included in the base unit price; additional replicates are charged at `replicate_price` each. For experiment types without replicate pricing (e.g., thermostability), `replicate_price_cents` is 0.
      - `experiment_type` string, required: Experiment type (e.g., "screening", "affinity", "thermostability", "fluorescence", "expression")
      - `n_replicates` integer, required: Number of technical replicates
      - `replicate_price_cents` integer, required: Price per additional replicate (beyond first) in USD cents. Zero for experiment types without replicate pricing.
      - `sequence_count` integer, required: Number of sequences in the experiment
      - `subtotal_cents` integer, required: Subtotal for assay costs in USD cents. Calculated as: `sequence_count × (unit_price + max(0, n_replicates - 1) × replicate_price)`
      - `unit_price_cents` integer, required: Base price per sequence in USD cents. Includes the first replicate.
    - `materials` union: Material cost for target antigens, discriminated by pricing model.
      - object: Per-sequence pricing: fixed cost per sequence.
        - `price_per_sequence_cents` integer, required: Price per sequence in USD cents
        - `sequence_count` integer, required: Number of sequences requiring material
        - `subtotal_cents` integer, required: Subtotal: sequence_count * price_per_sequence_cents
        - `target` TargetReference, required: A resolved reference to an experiment's target, as shown in the Foundry Portal. This is the single shape every API response uses to name a target: the experiment spec, result readouts, cost-estimate line items, and the internal minimum-sequence admin config all embed it instead of a bare id string. `name` is always present. `target_catalog_id` is present when the target is a catalog product — fetch its full details from `GET /targets/{target_catalog_id}`; its absence indicates a custom target. `sequence` and `supplier_url` are included when available.
          - `name` string, required: The target's display name, as shown in the Foundry Portal.
          - `sequence` string, nullable: The target's amino-acid sequence, when available.
          - `supplier_url` string, nullable: Link to the target's vendor product page, when available.
          - `target_catalog_id` string, uuid, nullable: Identifier of the matching catalog product, when the target is in the catalog; absent for custom targets. Resolve full details via `GET /targets/{target_catalog_id}`.
        - `type` 'per_sequence', required
      - object: Broken-lot pricing: customer pays for one or more full lots. The greedy allocator picks the cheapest combination of vendor lots that covers the required material. Single-lot orders have one entry; larger orders may combine multiple lot sizes.
        - `lots` LotAllocation[], required: Lot allocations covering the order
          - `lot_price_cents` integer, required: Price of one unit of this lot in USD cents
          - `lot_size_ug` number, double, required: Size of this lot in micrograms
          - `quantity` integer, required: Number of this lot needed
        - `sequence_count` integer, required: Number of sequences in the experiment
        - `subtotal_cents` integer, required: Total material cost in USD cents (sum of lot_price_cents × quantity)
        - `target` TargetReference, required: A resolved reference to an experiment's target, as shown in the Foundry Portal. This is the single shape every API response uses to name a target: the experiment spec, result readouts, cost-estimate line items, and the internal minimum-sequence admin config all embed it instead of a bare id string. `name` is always present. `target_catalog_id` is present when the target is a catalog product — fetch its full details from `GET /targets/{target_catalog_id}`; its absence indicates a custom target. `sequence` and `supplier_url` are included when available.
          - `name` string, required: The target's display name, as shown in the Foundry Portal.
          - `sequence` string, nullable: The target's amino-acid sequence, when available.
          - `supplier_url` string, nullable: Link to the target's vendor product page, when available.
          - `target_catalog_id` string, uuid, nullable: Identifier of the matching catalog product, when the target is in the catalog; absent for custom targets. Resolve full details via `GET /targets/{target_catalog_id}`.
        - `type` 'per_broken_lot', required
    - `pricing_version` string, required
    - `total_cents` integer, required: Total estimated cost in USD cents
  - `incomplete` IncompleteCostEstimate: Partial cost estimate when materials pricing is unavailable. Used in the `incomplete` field of `CostEstimateResponse` when the target is not configured for self-service pricing.
    - `assay` AssayCost, required: Assay cost breakdown for a specific experiment type. # Pricing Formula ```text per_sequence_cost = unit_price + max(0, n_replicates - 1) × replicate_price subtotal = sequence_count × per_sequence_cost ``` The first replicate is included in the base unit price; additional replicates are charged at `replicate_price` each. For experiment types without replicate pricing (e.g., thermostability), `replicate_price_cents` is 0.
      - `experiment_type` string, required: Experiment type (e.g., "screening", "affinity", "thermostability", "fluorescence", "expression")
      - `n_replicates` integer, required: Number of technical replicates
      - `replicate_price_cents` integer, required: Price per additional replicate (beyond first) in USD cents. Zero for experiment types without replicate pricing.
      - `sequence_count` integer, required: Number of sequences in the experiment
      - `subtotal_cents` integer, required: Subtotal for assay costs in USD cents. Calculated as: `sequence_count × (unit_price + max(0, n_replicates - 1) × replicate_price)`
      - `unit_price_cents` integer, required: Base price per sequence in USD cents. Includes the first replicate.
    - `materials_unavailable` MaterialsUnavailable, required: Explains why materials pricing is unavailable for a target. Returned as part of an incomplete cost estimate when the target is not configured for self-service pricing.
      - `reason` string, required: Human-readable explanation for why pricing is unavailable
      - `target` TargetReference, required: A resolved reference to an experiment's target, as shown in the Foundry Portal. This is the single shape every API response uses to name a target: the experiment spec, result readouts, cost-estimate line items, and the internal minimum-sequence admin config all embed it instead of a bare id string. `name` is always present. `target_catalog_id` is present when the target is a catalog product — fetch its full details from `GET /targets/{target_catalog_id}`; its absence indicates a custom target. `sequence` and `supplier_url` are included when available.
        - `name` string, required: The target's display name, as shown in the Foundry Portal.
        - `sequence` string, nullable: The target's amino-acid sequence, when available.
        - `supplier_url` string, nullable: Link to the target's vendor product page, when available.
        - `target_catalog_id` string, uuid, nullable: Identifier of the matching catalog product, when the target is in the catalog; absent for custom targets. Resolve full details via `GET /targets/{target_catalog_id}`.
    - `pricing_version` string, required
    - `total_cents` unknown, required
  - `warnings` string[]: Warnings about the estimate (e.g., unknown target, pricing limitations)

## Other responses

- `400`: Malformed request body, or an invalid experiment specification
- `401`: Invalid or missing authentication token
- `403`: Insufficient permissions
- `415`: Request body was not sent as `application/json`
- `422`: Request body did not match this operation's schema, or pricing is unavailable (unknown target or pre-v1 date). The `error` field distinguishes the two.

---

[API](https://skmtc.dev/adaptyvbio/apis/adaptyv-foundry-api.md) - [All operations](https://skmtc.dev/adaptyvbio/apis/adaptyv-foundry-api/llms.txt) - [OpenAPI document](https://skmtc.dev/adaptyvbio/apis/adaptyv-foundry-api/revisions/5a2228f4bd59?raw)
