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 inunit; zero returns empty text.unit— optionaltokens,words, orcharacters; omitted ornulluses the current default.strategy— optionalauto,structural,lexical,semantic, orhybrid; omitted ornulluses the current default. Only enabled strategies are accepted.query— optional string ornull. A nonblank question makesautoquery-aware; explicitlexical,semantic, andhybridrequire one. Explicitstructuraldoes 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. Missingunitorstrategyuses the current default for that input. The batch body accepts onlyinputsat the top level; a top-levellimit,unit,strategy, orqueryreturns422.- All inputs are checked before trimming starts. If one is invalid—for example, a negative limit or
lexicalwithout a query—the whole request fails with422; 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 stringtext; optional stringprefixandsuffixdefault 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, orquery. Adding those fields to a source object returns422. 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, defaultfalse. For semantic or hybrid ranking, identical passages can share embedding work; it does not remove duplicate sources or response rows.separator— optional string ornull, defaultnull. A string is copied between contributing sources and enables a complete renderedtext, 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.
autouses document structure when there is no nonblank query, or word matching when there is one. It never selects semantic or hybrid ranking.structuraluses document structure and ignores a supplied query for ranking.lexicalmatches words from the query;semanticuses the configured CPU model to match meaning;hybridcombines 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
textis the result. It may join several excerpts with omission markers rather than copy one continuous passage.input_countmeasures the original text;output_countmeasures the result. Both useunit, and the output count stays withinlimit.limitandunitshow the budget used, including the default unit when you omit it.strategyshows what actually ran. Anautorequest reportsstructuralorlexical.trimmedistruewhen the result differs from the original text.spansshow where retained excerpts came from in the original text. Eachstartis included and eachendis 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.
limitandunitshow the shared budget;strategyshows the method that actually ran.sourceshas one row per input source, in input order.source_indexis its zero-based position. A source with no selected excerpt still has a row with emptytext, zerooutput_count, and nospans.- In each source row,
textis the selected excerpt,input_countandoutput_countmeasure that source before and after trimming,trimmedsays whether its text changed, andspanspoint into the original source text. - The top-level
textis 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 andseparatoris omitted ornull, it isnull; use the source rows instead. - The top-level
input_counttotals the original source texts.output_countmeasures renderedtextwhen present; otherwise it totals the source-row output counts. It stays within the sharedlimit. Source-row counts exclude wrappers and separators, so they may not add up to the rendered count. - The top-level
trimmedistrueif 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
| Limit | Current value | What it covers |
|---|---|---|
| Input words | 15,000 aggregate input words | All submitted text, queries, prefixes, suffixes, and separators together. |
| JSON body | 1,048,576 bytes | Actual request body size, including chunked uploads. |
| Batch or context size | 20 items | Inputs in one batch or sources in one context request. |
| Query | 5,000 codepoints | Length of each query. |
| Source wrappers | 5,000 codepoints | Combined prefix and suffix for each context source. |
| Separator | 5,000 codepoints | Length of the context separator. |
| Processing | 100 active requests | API requests that can process at the same time. |
| Waiting | 150 requests, 60 seconds | Maximum queue size and time allowed before processing starts. |
| Body read | 30 seconds | Time 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.
| Status | Meaning |
|---|---|
422 | Invalid or missing fields, including a required query or an overlong query, wrapper, or separator. |
413 | Request body, aggregate word count, or batch/context item count exceeds its limit. |
415 | Content type is not application/json. |
408 | The body did not arrive in time, or the client disconnected while sending it. |
503 | Processing is busy, queue wait expired, or semantic processing is unavailable. |
500 | Unexpected server error. |
A 503 response includes Retry-After: 7 (seconds).
Every response includes X-Request-ID for support and troubleshooting.