---
title: "Knock-in / prime-edit rate from Sanger traces"
method: POST
path: "/sanger_knockin_quant"
tags: ["Alignment & variants"]
---

# Knock-in / prime-edit rate from Sanger traces

`POST /sanger_knockin_quant`

## Request

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

Measure the rate of a SPECIFIC intended edit from a pair of Sanger traces — an unedited control and the edited pool — by decomposing the edited trace onto three things at once: the wild-type allele, the intended edited allele, and the unintended indels. Serves both readouts that need this: HDR knock-in rate (what fraction of the pool carries the donor's edit, including an insert of novel sequence), and prime editing (the pegRNA's intended substitution, insertion, deletion or replacement as the intended column, and the indel byproducts at the nick as the shift columns). This is what sanger_indel_spectrum cannot do: that tool's basis is indexed by indel LENGTH, so an intended 6 bp knock-in and an accidental 6 bp NHEJ deletion are one column there. Returns knock-in / wild-type / unintended-indel percentages, the byproduct spectrum by shift, and the R² that says whether the model fits your traces at all. Non-negative least squares, so no allele is ever assigned a negative share. For a substitution or replacement the reference allele you name is checked against the control read before anything is fitted; an insertion and a deletion name no reference bases, so there only the position can be range-checked.

## Request body

- object
  - `controlBases` string, required: Base calls of the UNEDITED control read.
  - `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).
    - number[]
  - `editedBases` string, required: Base calls of the edited pool's read.
  - `editedChannels` array[], required: Per-base [A, C, G, T] intensities of the edited read, same convention.
    - number[]
  - `editKind` 'substitution' | 'insertion' | 'deletion' | 'replacement', required: Shape of the intended edit, spelled as prime_editing_design spells it. "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 two lengths differ.
  - `editPosition` number, required: 1-based position of the edit in CONTROL read coordinates: 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, which names the base before an insertion. The rule is uniform across all four kinds on purpose; a spec transcribed from VCF needs +1 on an insertion.
  - `refAllele` string: The control bases the edit replaces (substitution and replacement). Checked against the control read: a mismatch is rejected, because building the intended-edit column at the wrong position yields a confident, meaningless number.
  - `altAllele` string: The bases the edit installs in their place (substitution and replacement).
  - `insertedSeq` string: The novel bases inserted (insertion only).
  - `deletedLength` integer: How many bases are deleted (deletion only).
  - `cutPosition` number: 1-based CONTROL position where UNINTENDED indels start — the nuclease cut or the PE nick. Defaults to the edit start. Separate from editPosition because a byproduct allele is wild-type up to the cut and shifted after it, so a wrong cut position makes those columns wrong over the first part of the window.
  - `maxIndel` number: Largest unintended indel to fit, in bp (1-20; out of range is rejected, not clamped). Every shift from −maxIndel to +maxIndel is included except 0, which is wild-type. The intended edit's OWN net shift is included too whenever its column is measurably different from the intended-edit column — it is dropped only when the two are the same vector, which happens for a pure deletion whose cut is at the edit. See sameShiftByproduct in the result for which of the two happened.
  - `windowLength` number: Bases from the edit site downstream used for the decomposition (20-300; out of range is rejected, not clamped). Unlike sanger_indel_spectrum there is no guard region: the edited positions themselves are the only signal separating a substitution from wild-type.
  - `offset` number: Override the alignment offset between the reads (whole number, −40 to 40). By default it is found from the base calls upstream of the edit. upstreamIdentity is always measured AT the offset used, so an override that is wrong shows up as a failed same-amplicon check rather than borrowing the auto-detected offset's score.

## 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)
