TRIMWISE · API V1

API documentation.

The API exposes three operations with one JSON interface. Start with a single trim, then use batches or a shared context budget.

Quickstart

Base URL: https://trimwise.aatbit.com. Send JSON over HTTPS. No API key is required.

Queryless curl

With strategy: auto and no query, Trimwise uses structural selection.

curl -sS https://trimwise.aatbit.com/api/v1/trim \
  -H 'Content-Type: application/json' \
  -d '{
  "text": "The answer is in this sentence. Background text follows.",
  "limit": 7,
  "unit": "words",
  "strategy": "auto"
}'

Query-aware curl

Add a question to focus selection. With auto, a nonblank query selects lexical ranking.

curl -sS https://trimwise.aatbit.com/api/v1/trim \
  -H 'Content-Type: application/json' \
  -d '{
  "text": "The answer is in this sentence. Background text follows.",
  "limit": 7,
  "unit": "words",
  "strategy": "auto",
  "query": "Where is the answer?"
}'

Python (queryless)

import json, urllib.request
data = {"text": "The answer is in this sentence. Background text follows.", "limit": 7, "unit": "words", "strategy": "auto"}
request = urllib.request.Request(
    "https://trimwise.aatbit.com/api/v1/trim",
    data=json.dumps(data).encode(),
    headers={"Content-Type": "application/json"},
)
with urllib.request.urlopen(request) as response:
    print(json.load(response))

JavaScript (queryless)

const data = {
  "text": "The answer is in this sentence. Background text follows.",
  "limit": 7,
  "unit": "words",
  "strategy": "auto"
};
const response = await fetch("https://trimwise.aatbit.com/api/v1/trim", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify(data),
});
console.log(await response.json());

Request bodies

Send a JSON object with Content-Type: application/json. Field types are strict; unknown fields are rejected. The machine-readable schema is at /openapi.json.

POST /api/v1/trim

Trim one text under its own output budget.

{
  "text": "The answer is in this sentence. Background text follows.",
  "limit": 7,
  "unit": "words",
  "strategy": "auto"
}
  • text — required string to trim; an empty string is valid.
  • limit — required integer, zero or greater. This is the maximum output size in unit; zero returns empty text.
  • unit — optional tokens, words, or characters; omitted or null uses the current default.
  • strategy — optional auto, structural, lexical, semantic, or hybrid; omitted or null uses the current default. Only enabled strategies are accepted.
  • query — optional string or null. A nonblank question makes auto query-aware; explicit lexical, semantic, and hybrid require one. Explicit structural does not use it for ranking.

POST /api/v1/trim/batch

Trim each input separately. Every input has its own limit and can use a different unit, strategy, or query. There is no shared output budget for the batch.

{
  "inputs": [
    {
      "text": "The answer is in this sentence. Background text follows.",
      "limit": 7,
      "unit": "words",
      "strategy": "auto"
    },
    {
      "text": "Another source has context.",
      "limit": 18,
      "unit": "characters",
      "strategy": "lexical",
      "query": "context"
    }
  ]
}
  • inputs — required nonempty array of up to 20 single-trim objects. Missing unit or strategy uses the current default for that input. The batch body accepts only inputs at the top level; a top-level limit, unit, strategy, or query returns 422.
  • All inputs are checked before trimming starts. If one is invalid—for example, a negative limit or lexical without a query—the whole request fails with 422; there is no partial result.

POST /api/v1/context

Choose excerpts from several sources under one shared output limit. Set limit, unit, strategy, and query once for the whole request.

{
  "sources": [
    "First source evidence.",
    {
      "text": "Second source evidence.",
      "prefix": "Source 2: "
    }
  ],
  "limit": 8,
  "unit": "words",
  "separator": "\n\n"
}
  • sources — required nonempty array of strings or source objects; at most 20 sources. A source object requires string text; optional string prefix and suffix default to empty strings. Wrappers appear around contributing excerpts but do not affect ranking.
  • limit — required integer, zero or greater, shared by all sources.
  • unit, strategy, query — optional, with the same types, defaults, and query rules as a single trim.
  • Sources cannot override the shared limit, unit, strategy, or query. Adding those fields to a source object returns 422. Use a batch if each text needs different settings. A source may receive no excerpt when the shared budget is spent elsewhere, but it still has a response row.
  • deduplicate — optional boolean, default false. For semantic or hybrid ranking, identical passages can share embedding work; it does not remove duplicate sources or response rows.
  • separator — optional string or null, default null. A string is copied between contributing sources and enables a complete rendered text, even when it is empty.

Options and behavior

Set the output size

limit is the maximum size of the returned text. unit says how to measure it: tokens use the server's configured tokenizer, words split on whitespace, and characters count Unicode codepoints. The current default unit is tokens. A limit of 0 returns no text.

Choose which excerpts to keep

The current default strategy is auto. This server allows auto, structural, lexical, semantic, hybrid.

  • auto uses document structure when there is no nonblank query, or word matching when there is one. It never selects semantic or hybrid ranking.
  • structural uses document structure and ignores a supplied query for ranking.
  • lexical matches words from the query; semantic uses the configured CPU model to match meaning; hybrid combines both.

Choose lexical, semantic, or hybrid only with a nonblank query; otherwise the request returns 422.

Response bodies

Successful requests return JSON. Here is a single-trim response for Cats matter. with a five-word limit, auto strategy, and no query:

{
  "text": "Cats matter.",
  "input_count": 2,
  "output_count": 2,
  "limit": 5,
  "unit": "words",
  "strategy": "structural",
  "trimmed": false,
  "spans": [
    {
      "start": 0,
      "end": 12
    }
  ]
}

Single trim

  • text is the result. It may join several excerpts with omission markers rather than copy one continuous passage.
  • input_count measures the original text; output_count measures the result. Both use unit, and the output count stays within limit.
  • limit and unit show the budget used, including the default unit when you omit it.
  • strategy shows what actually ran. An auto request reports structural or lexical.
  • trimmed is true when the result differs from the original text.
  • spans show where retained excerpts came from in the original text. Each start is included and each end is excluded: original[start:end] gives that excerpt. Offsets use Unicode codepoints (Python string positions), which can differ from JavaScript UTF-16 positions. Generated markers have no spans.

Batch

results contains one single-trim response for each input, in the same order: results[0] belongs to inputs[0]. Each result reports its own limit, unit, and resolved strategy, even when the inputs use different settings.

Shared context

One response covers the shared budget and includes a row for every source.

  • limit and unit show the shared budget; strategy shows the method that actually ran.
  • sources has one row per input source, in input order. source_index is its zero-based position. A source with no selected excerpt still has a row with empty text, zero output_count, and no spans.
  • In each source row, text is the selected excerpt, input_count and output_count measure that source before and after trimming, trimmed says whether its text changed, and spans point into the original source text.
  • The top-level text is the complete rendered context when you provide a source object or a separator, even an empty one. It includes wrappers and separators that fit the budget. If every source is a plain string and separator is omitted or null, it is null; use the source rows instead.
  • The top-level input_count totals the original source texts. output_count measures rendered text when present; otherwise it totals the source-row output counts. It stays within the shared limit. Source-row counts exclude wrappers and separators, so they may not add up to the rendered count.
  • The top-level trimmed is true if any source text changed, even if rendering also adds wrappers.

Source spans refer to each source's original text, not wrappers, separators, or generated omission markers.

Limits and errors

Latest limits. The aggregate word limit counts the entire request, including every batch input or context source.

Request limits

LimitCurrent valueWhat it covers
Input words15,000 aggregate input wordsAll submitted text, queries, prefixes, suffixes, and separators together.
JSON body1,048,576 bytesActual request body size, including chunked uploads.
Batch or context size20 itemsInputs in one batch or sources in one context request.
Query5,000 codepointsLength of each query.
Source wrappers5,000 codepointsCombined prefix and suffix for each context source.
Separator5,000 codepointsLength of the context separator.
Processing100 active requestsAPI requests that can process at the same time.
Waiting150 requests, 60 secondsMaximum queue size and time allowed before processing starts.
Body read30 secondsTime allowed to receive a request body.

Error responses

Errors return {"error":{"code":"...","message":"..."}}. Use code to identify the reason; message is a short, safe description.

StatusMeaning
422Invalid or missing fields, including a required query or an overlong query, wrapper, or separator.
413Request body, aggregate word count, or batch/context item count exceeds its limit.
415Content type is not application/json.
408The body did not arrive in time, or the client disconnected while sending it.
503Processing is busy, queue wait expired, or semantic processing is unavailable.
500Unexpected server error.

A 503 response includes Retry-After: 7 (seconds). Every response includes X-Request-ID for support and troubleshooting.