---
title: "Mixed bases and the uncalled tail of a Sanger trace"
method: POST
path: "/trace_secondary_peaks"
tags: ["Alignment & variants"]
---

# Mixed bases and the uncalled tail of a Sanger trace

`POST /trace_secondary_peaks`

## Request

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

Read a chromatogram for what the basecaller did not report: positions where a second dye is present under the called base (a heterozygote, or a contaminating template), and bases still visible in the scan past where base calling stopped. Both are arithmetic on the channel intensities already in the file — a ratio, and a peak position extrapolated from the median spacing — not a model. Returns the called sequence rewritten with IUPAC ambiguity codes, the extra bases, and every threshold that produced the answer. Takes the SCAN arrays, because the tail lies past the last peak location.

## Request body

- object
  - `baseCalls` string, required: Base calls, e.g. from parse_sanger_trace.
  - `peakLocations` number[], required: Scan index of each called base's peak — one per base call.
  - `channelA` number[], required: Full A channel, indexed by SCAN (not by base).
  - `channelC` number[], required: Full C channel, indexed by scan.
  - `channelG` number[], required: Full G channel, indexed by scan.
  - `channelT` number[], required: Full T channel, indexed by scan.
  - `quality` number[]: Optional per-base Phred scores; echoed beside each mixed position.
  - `mixedRatio` number: Secondary/primary intensity ratio at which a position is reported as mixed (0-1 exclusive). A convention, not a measurement.
  - `skipLeading` number: Bases at the read's start excluded from the mixed scan (0-1000). The dye blob lives here and lifts every channel; without this every read reports a wall of false heterozygotes at its start.
  - `tailSignalToNoise` number: How far above the measured noise floor a channel must sit before the tail extension calls it (1-100).
  - `maxExtension` number: Most extra bases to call past the last called base (0-400). The cap is part of the method: peak positions are extrapolated and the extrapolation drifts.

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