Skip to main content
POST

Authorizations

Authorization
string
header
required

Authorization: Bearer np_live_…

One credential form. There is no query-parameter, cookie or x-api-key alternative — the legacy x-api-key header stopped being accepted at the Bearer cutover and now fails authorization.

Keys are org-scoped, never user-scoped, and the secret is shown exactly once at mint. Rotation is create-then-revoke.

Body

application/json

ContextRequest. Maximum body size is 6 MB — the AWS Lambda synchronous payload cap. API Gateway rejects an oversized body before the service is invoked, so guard it client-side rather than relying on a readable error.

request_id
string
required

Your correlation id for this unit of work. The response echoes it back byte-for-byte, and the published client raises if it does not match — so it is the key you join a response back to a request on.

Keep it to ≤ 128 characters from [A-Za-z0-9._:-]. An id outside that bound is still echoed to you unchanged, but the internal correlation copy is truncated and de-fanged, and the response then carries format_metrics.request_id_sanitized: true so you can see it happened. Two consequences worth designing for: an id that differs only past character 128 is indistinguishable in our logs, and anything you put in this field reaches our logs — so do not put record content, customer text or credentials in it.

Example:

"req-2026-08-01-0001"

records
object[]
required

The state Needlepath may keep, drop or excerpt. An empty array is accepted and yields an empty selection.

Order is a tie-breaker. Records that score equally are ranked by the order they arrived in, so reordering an otherwise identical request can change which records survive a tight budget. Send a stable order if you want stable results.

Record count is capped per request alongside the token ceiling, because selection cost scales with count as well as size. See Limits.

task
object
required

The query the selected context has to serve.

budget
object
required

The operating point, in arm-neutral quantities only.

No method-tuning knobs appear here or anywhere else in the request. Thresholds, weightings, tier rules and gate parameters are resolved server-side from the operating_point label. That is a contract property, not an omission: it is what makes a published label reproducible and what keeps a benchmark comparison honest.

render
boolean
default:true

Ask for rendered_context, a model-facing string assembled from the selection. Set false if you assemble the prompt yourself from selected[].

Currently ignored — the rendered block is always built and returned. Discard it client-side until this is wired.

render_format
enum<string>
default:plain

A neutral rendering hint, not a method knob.

plain (the default) leaves excerpts as text. hybrid additionally allows a structured excerpt — JSON, typically — to be re-encoded into a more compact form when that would save tokens; excerpt_format on each selected record reports which form was used. Send plain if you intend to re-parse excerpts as JSON.

Available options:
plain,
hybrid
return_per_record
boolean
default:true

Include the selected[] detail — per-record score, reason, excerpt and token count. Set false and you get rendered_context plus the token arithmetic only, which is a materially smaller response body.

Response

A selection. Includes stand-downs and engine-internal failures — see fallback_used and selection_error. This service returns 200 with a usable body rather than a 5xx when its own selection pass fails, because the correct client behaviour in that case is to send the original context, which the body already contains.

The selection.

Required by the contract (the published client raises if any is missing, or if request_id does not echo): request_id, rendered_context, tokens_before, tokens_after, tokens_saved, records_available, records_selected, fallback_used, engine_latency_ms.

Everything else is optional and new optional fields ship within /v1 — ignore what you do not recognise.

The first field that will exercise that rule is already designed and is documented in this file as the Usage schema. It is deliberately not listed as a property below, because it is not serving: listing it would make every generated client carry a field that never arrives.

request_id
string
required

Your request_id, echoed byte-for-byte.

rendered_context
string
required

The model-facing block, assembled from the selection. Empty when you sent render: false.

tokens_before
integer
required

The engine's own accounting of the context available before filtering.

On this deployment it works out to exactly Σ estimate_tokens(record.text). It is still not the billing quantity: the meter additionally counts record.title, task.prompt and task.recent_prompts, so input_tokens is the larger number and the two will not match.

It is also an engine-internal quantity by definition rather than by promise — it is a per-record sum taking a maximum against the summary the engine holds, which on this deployment is your text. Budget against it; do not reconcile an invoice with it.

tokens_after
integer
required

Context size after selection, on the same engine-internal basis as tokens_before.

tokens_saved
integer
required

tokens_before − tokens_after. Zero on a stand-down, and that is a correct outcome rather than a failed one.

records_available
integer
required

How many records the engine considered.

records_selected
integer
required

How many it selected.

fallback_used
boolean
required

The engine stood aside and returned your context essentially intact.

fallback_used = true does not tell you why, and three different causes produce it: a deliberate gate stand-down, an empty or unusable record set, and an engine-internal exception. Read gate and selection_error to tell them apart, and see format_metrics.engine_fallback_reason.

engine_latency_ms
number<double>
required

Server-measured selection time. It excludes network transit, so it is not your round trip, and the two are different measurements that must not be compared or added together casually.

Example values in this document are illustrative and are not a performance commitment. Measure your own end-to-end latency from your own client.

policy_version
string | null

The frozen version behind the operating_point that actually ran. Record it with every result: it is what makes a result file self-describing, and it is how you detect that you inherited a default you did not choose.

selected
object[]

Per-record detail, in selection order. Empty when you sent return_per_record: false, and also empty on some stand-downs — an empty selected[] is not by itself evidence that nothing was selected. Read records_selected for that.

selection_error
string | null

Set when the engine's own selection pass raised. The HTTP status is still 200 — the body carries a usable full-context result, which is what a client should send anyway. If you monitor Needlepath, alarm on this field, not on 5xx: an availability metric defined on status code reports health straight through an engine outage.

budget_tokens
integer

The budget the returned selection was produced under.

attempted_budget_tokens
integer[]

Every rung attempted on the adaptive ladder, in order. Empty on the fixed path. This is the field to watch if you want to know whether an adaptive workload is doing several selection passes per request.

reduction_ratio
number<double>

tokens_saved / tokens_before, on the engine-internal basis. Zero when tokens_before is zero.

safety
object | null

Present only when a coverage verdict actually ran. null on the plain fixed-budget path, so a null safety means "no verdict was computed", never "the verdict was fine".

gate
object | null

Present when a gate decision was made.

format_metrics
object

Free-form, additive rendering and diagnostic telemetry. Treat unknown keys as informational. Keys you may see today:

  • engine_fallback_reason — present only when the engine actually stood aside, carrying its own reason. This is the field that distinguishes "nothing cleared the selection floor" from other stand-downs on the fixed path, where safety is null.
  • request_id_sanitized: true — your request_id violated the length or charset bound and the internal copy was truncated and de-fanged. The echo you received is still your bytes.
  • client_latency_msadded by the client, not by the server. The published Python client records its own round trip here. Do not read it as a server measurement.