---
title: "Editing quantification across a plate (one control, many wells)"
method: POST
path: "/editing_plate_quantify"
tags: ["Alignment & variants"]
---

# Editing quantification across a plate (one control, many wells)

`POST /editing_plate_quantify`

## Request

- Base URL: `https://seqbench.com/api/v1`
- URL: `https://seqbench.com/api/v1/editing_plate_quantify`
- Auth: none required

Quantify a whole plate of edited samples against ONE untreated control trace and return a single sortable table — the plate-scale form of sanger_indel_spectrum, base_edit_quant and sanger_knockin_quant, chosen with `mode`. Each sample gives one row keyed by its id, carrying the headline number for that mode (edited fraction / editing at the target base / intended knock-in percentage), the fit-quality numbers behind it (R², or the background n and noise floor for base mode), and fitAdequate — the single-sample tool's own gate verdict on that row, so the plate cannot drift from the per-well answer. Failure is isolated per well: a sample whose read is short, mismatched or unfittable becomes a failed ROW with its error message and the other 95 still come back, while an error about the control trace, the mode or the work ceilings throws, because it is wrong for every row. Duplicate sample ids are suffixed (against the whole plate, so the suffix never lands on another well's name) rather than merged. Arguments are strict: an argument belonging to another mode, an unknown argument, an out-of-range limit, and an `offset` override (which is a property of one pair of reads, not of a plate) are all rejected rather than ignored or clamped, because at plate scale a substituted setting rewrites every row identically and nothing in the table looks odd. Returns the rows in input order, a tally, and a CSV. Comparing two wells' percentages is only meaningful when both rows are fitAdequate, which is why the plate summary is computed over those rows alone.

## Request body

- object
  - `mode` 'indel' | 'base' | 'knockin', required: Which quantifier to run on every well. "indel" = sanger_indel_spectrum (NHEJ efficiency and the indel spectrum; needs cutPosition; blind to substitutions). "base" = base_edit_quant (CBE/ABE conversion; needs an editor id + protospacer, or an explicit window with from/to; blind to indels). "knockin" = sanger_knockin_quant (a specific intended edit against its byproducts; needs editKind + editPosition). Arguments belonging to another mode are rejected, not ignored.
  - `controlBases` string, required: Base calls of the ONE untreated control read (raw or FASTA).
  - `controlChannels` array[], required: Per-base [A, C, G, T] intensities of the control read, one row per called base, read at that base's peak location (trace arrays are indexed by scan, not by base). Raw peak heights: every intensity must be >= 0, because negatives are clamped to zero during normalization and a baseline-subtracted trace would silently lose its minor peaks and read as unedited.
    - number[]
  - `samples` object[], required: The plate's edited wells, in the order you want them tabulated. Up to 384 samples (96 is the natural plate) and 400,000 trace positions across the whole call, control included — that is already an 8-10 MB request body, so split a plate of untrimmed reads rather than sending one call.
    - `id` string: Well or sample name — this keys the row. A number is tolerated and read as its digits. Duplicates are suffixed ("A01#2", stepping past any name already in use), never merged; an empty or absent id becomes sample_<n>.
    - `bases` string, required: Base calls of this well's read (raw or FASTA).
    - `channels` array[], required: Per-base [A, C, G, T] intensities for this well, same convention as the control, and non-negative for the same reason.
      - number[]
  - `cutPosition` number: indel mode (required): 1-based position of the expected cut, in CONTROL read coordinates. knockin mode (optional): 1-based CONTROL position where UNINTENDED indels start — the nuclease cut or the PE nick; defaults to the edit start.
  - `maxIndel` number: indel and knockin modes: largest indel to fit, in bp — a whole number, 1-20. Out of range is rejected, not clamped.
  - `windowLength` number: indel and knockin modes: bases downstream used for the decomposition — a whole number, 20-300. Out of range is rejected, not clamped.
  - `guard` number: indel mode: bases skipped immediately after the cut, where the trace is least reliable. A whole number >= 0; a negative value is rejected, not clamped to 0.
  - `editor` 'be3' | 'be4max' | 'abe7.10' | 'abe8e': base mode: base editor id (be3, be4max, abe7.10, abe8e) — fixes the converted bases and the activity window in protospacer coordinates. Requires "protospacer". Mutually exclusive with windowStart/windowEnd/from/to.
  - `protospacer` string: base mode: the 20-nt spacer, located in the CONTROL read (either strand; must match exactly once).
  - `windowStart` number: base mode: explicit window start, 1-based in CONTROL coordinates. Requires windowEnd, from and to.
  - `windowEnd` number: base mode: explicit window end, 1-based inclusive. Window length is capped at 40.
  - `from` string: base mode: the base the editor converts, as READ on the control strand.
  - `to` string: base mode: the base it converts to, as READ on the control strand.
  - `targetPosition` number: base mode: 1-based CONTROL position of the intended edit. Give it for a plate. Without it each well's headline is its OWN most-edited significant position, so two rows can be reporting two different bases and the column is not one measurement.
  - `targetProtospacerPosition` number: base mode: 1-based protospacer position of the intended edit (PAM-distal = 1). Editor mode only.
  - `zThreshold` number: base mode: significance threshold in standard deviations of each well's own background (1-10; out of range is rejected, not clamped). Raising it raises the reported noise floor with it.
  - `editKind` 'substitution' | 'insertion' | 'deletion' | 'replacement': knockin mode (required): shape of the intended edit. "substitution" replaces bases one for one; "insertion" adds novel bases and replaces none; "deletion" removes bases and adds none; "replacement" is the general case where the lengths differ.
  - `editPosition` number: knockin mode (required): 1-based CONTROL position of the first base the edit replaces. An insertion replaces nothing, so there it is the base the insert lands immediately BEFORE — one MORE than the VCF/HGVS anchor.
  - `refAllele` string: knockin mode: the control bases the edit replaces (substitution and replacement). Checked against the control read once, before any well is fitted.
  - `altAllele` string: knockin mode: the bases installed in their place.
  - `insertedSeq` string: knockin mode: the novel bases inserted (insertion only).
  - `deletedLength` number: knockin mode: how many bases are deleted (deletion only).

## Response `200`

Tool ran successfully.

- SuccessResponse: Standard success envelope returned by every single-tool call.
  - `ok` unknown, required
  - `tool` string, required: The tool slug that ran.
  - `result` object, required: Tool-specific output object. Its shape depends on the tool — call `GET /{tool}` or see the docs for each tool's fields.
  - `gate` GateResult
    - `pass` boolean, required: True if and only if every hard check passed.
    - `checks` GateCheck[], required
      - `id` string, required
      - `label` string, required
      - `severity` 'hard' | 'soft', required
      - `pass` boolean, required
      - `message` string, required
      - `value` number
      - `threshold` string
    - `notChecked` string[], required: Honest list of what this gate does NOT verify.
  - `provenance` Provenance, required
    - `apiVersion` string, required
    - `tool` union, required: Tool slug, or an array of slugs (one per step) for a workflow.
      - string
      - string[]
    - `generatedAt` string, date-time, required: ISO 8601 timestamp of when the result was generated.

## Other responses

- `400`: Invalid argument or the tool could not run.
- `404`: Unknown tool.
- `429`: Rate limited (metered tools only). Body carries code `rate_limited` and retryable `true`; honor the Retry-After header.
- `503`: A metered tool is momentarily at capacity. The identical request should succeed after Retry-After; body carries code `upstream_unavailable`.

---

[API](https://skmtc.dev/seqbench/apis/seqbench-api.md) · [All operations](https://skmtc.dev/seqbench/apis/seqbench-api/llms.txt) · [OpenAPI document](https://skmtc.dev/seqbench/apis/seqbench-api/revisions/132575216865?raw)
