System One
System One
DocumentationSDK documentationModelsAPI referenceOpen System OneDocumentation index

SDK & API

TypeScript SDKExtract typed fields with Clairic

Build with decisions

Choose a modelDecision primitivesAgent integration: typed tool routingSystem One for coding agents (Claude Code, Cursor, Codex)

Usage & data

Billing and creditsPrivacy and zero data retention
SDK documentation

Extract typed fields with Clairic

Call extract({ state, fields }) with Clairic — field types, images, and hosted HTTP body examples.

Clairic is a System One extraction model. It reads shared state — the text or structured context you want values taken from — and a map of typed fields, then returns one typed value per field. It does not generate free-form text and it does not answer Choice, Score, or Noul questions.

Use extract({ state, fields }) on the same SystemOne client you use for evaluate(). Do not pass fields to evaluate(), and do not pass questions to extract().

The public model name is clairic, the same style as jev and clef. Copy that name, or the exact name from GET /v1/models when the catalog lists it. Do not add a prefix to the model name.

Try the same invoice task in the signed-in invoice extraction demo. Model facts and credit rates are on the Clairic model page.

Answer-ready

Q: How do I use the Clairic SDK?
A: Call extract({ state, fields }) with Clairic to pull typed fields from agent state. Use the System One TypeScript SDK or the hosted HTTP API with the Clairic model.

Q: Is Clairic the same as Choice?
A: No. Choice picks among options; Clairic extract returns structured fields you define. Both are part of System One.

Install

Extraction needs core 0.8.0, the hosted adapter 0.7.0, and Fetch transport 0.8.0. All three resolve @system-one-ai/core@^0.8.0.

npm install @system-one-ai/core@0.8.0 @system-one-ai/adapter-system-one@0.7.0 @system-one-ai/transport-fetch@0.8.0

systemOneAdapter posts extract requests to {baseURL}/systemone. The adapter default is https://system-one.dev/v1, so the hosted path is POST https://system-one.dev/v1/systemone with a fields body. The default extract model is clairic.

Extract an invoice

Save as extract-invoice.mts. Set SYSTEM_ONE_API_KEY to a System One platform key. Every run creates a new billable operation.

import {
  createSystemOne, defineFields, textField, numberField, dateField, listField, estimateField,
} from '@system-one-ai/core';
import { systemOneAdapter } from '@system-one-ai/adapter-system-one';
import { createFetchTransport } from '@system-one-ai/transport-fetch';

const apiKey = process.env.SYSTEM_ONE_API_KEY;
if (!apiKey) throw new Error('Set SYSTEM_ONE_API_KEY.');

const client = createSystemOne({
  adapter: systemOneAdapter,
  transport: createFetchTransport(),
  apiKey,
  timeoutMs: 30_000,
  maxRetries: 0,
});

const fields = defineFields({
  invoice_number: textField({ instructions: 'The invoice id printed on the document.' }),
  due_date: dateField({ instructions: 'Issue date plus the net payment days.' }),
  total: numberField({ decimals: 2, instructions: 'The total amount due.' }),
  contacts: listField({ items: 'text' }),
  days_to_pay: estimateField({ min: 0, max: 120, step: 1 }),
});

const result = await client.extract({
  model: 'clairic',
  state: [
    'INVOICE INV-2291',
    'From: Northwind Supply',
    'To: Contoso Ltd',
    'Issued: 2026-09-02, net 30',
    'Total due: 1080.00 including shipping',
    'Contact: Dana Ruiz, Priya Shah',
  ].join('\n'),
  fields,
  referenceDate: '2026-10-19',
  options: { includeQuantiles: false },
});

const invoice: string | null = result.answers.invoice_number.value;
console.log({
  model: result.model,
  invoice,
  dueDate: result.answers.due_date.value,
  total: result.answers.total.value,
  contacts: result.answers.contacts.value,
  daysToPay: result.answers.days_to_pay.median,
  truncated: result.truncated,
  usage: result.usage,
});
node --env-file=.env extract-invoice.mts

createSystemOne() returns a SystemOne instance. new SystemOne({ ... }) is the same constructor. defineFields() preserves literal field IDs for ExtractRequest, ExtractResult, and FieldAnswers.

Request

FieldRule
fieldsRequired. At least one named field. Names match [A-Za-z_][A-Za-z0-9_.-]{0,63}.
stateString to read. Required and nonempty unless images are sent. Text answers are spans of this string — a span is the start and end character index of that value in state.
imagesOptional. At most four embedded PNG, JPEG, or WebP images (4MB decoded each, 8MB total). Remote URLs are rejected. The full JSON request body must not exceed 13MB (the catalog may set a stricter limit).
modelOptional. Hosted default is clairic. Per-request model overrides the client.
referenceDateOptional ISO date (YYYY-MM-DD) that fills in dates written without a year. The HTTP body uses reference_date.
options.nullThresholdOptional (0, 1]. The service default is 0.5. Applied to scalar fields that omit their own threshold. value is null when pNull is above the threshold; guess may still hold a value.
options.includeQuantilesOptional. Adds all 99 percentiles to estimate and forecast answers.
options.returnStateTextOptional. Returns the text that spans index into.

Core validates field names, per-type properties, and image representation before the request is sent. The full JSON request body must not exceed 13MB (the catalog may set a stricter limit). Adapters that do not set supportsExtract: true reject extract() with UnsupportedFeatureError before I/O.

Field types

Factories are exported from @system-one-ai/core. Inline { type: 'text' } objects are also valid.

TypeFactoryvalueNotes
texttextField()string | nullOptional span: [start, end].
numbernumberField({ unit, integer, decimals })number | nulldecimals is 0–6.
datedateField()string | nullCalendar date.
timetimeField()string | nullTime of day.
datetimedateTimeField()string | nullCombined date and time.
durationdurationField({ unit, integer, decimals })number | nullUnits: seconds, minutes, hours, days, weeks, months, years.
listlistField({ items })readonly arrayitems is required: text, number, or date.
estimateestimateField({ min, max })number | stringmin and max are required. Optional step, scale (linear | log), unit.
forecastforecastField({ min, max })readonly arraySame range options as estimate, plus horizon (1–64) and interval.

Every field may include instructions and, except lists, nullThreshold. Lists may include unit and decimals.

import {
  defineFields, dateTimeField, durationField, forecastField, timeField,
  type ExtractRequest, type ExtractResult, type FieldAnswers,
} from '@system-one-ai/core';

const more = defineFields({
  opens: timeField(),
  signed: dateTimeField(),
  delay: durationField({ unit: 'days' }),
  travelers: forecastField({ min: 500_000, max: 4_000_000, horizon: 1, interval: 'day' }),
});

type MoreRequest = ExtractRequest<typeof more>;
type MoreResult = ExtractResult<typeof more>;
type MoreAnswers = FieldAnswers<typeof more>;

Response

Only value is guaranteed on each answer. Scalar types also report guess, confidence, and pNull when the model sends them. Text may include span. Lists include value and optional spans. Estimates and forecasts include mean, median, p10, p90, pBelow, and pAbove; they do not use confidence / pNull. Forecast value is an array with one value per step (horizon steps).

truncated is always a boolean. usage normalizes token counts to inputTokens, outputTokens, totalTokens, and optional stateTokens, imageTokens, schemaTokens, passes. Optional counts that were not returned do not appear on the result.

result.model may differ from the requested ID. Record both.

Images with extract()

Clairic accepts up to four PNG, JPEG, or WebP images on extract(). state may be '' when images are present. ImageInput is exported by core: an embedded base64 data URL or { mediaType: 'image/png', base64: '...' }.

import { readFile } from 'node:fs/promises';
import { createSystemOne, textField, type ImageInput } from '@system-one-ai/core';
import { systemOneAdapter } from '@system-one-ai/adapter-system-one';
import { createFetchTransport } from '@system-one-ai/transport-fetch';

const apiKey = process.env.SYSTEM_ONE_API_KEY;
const imagePath = process.argv[2];
if (!apiKey || !imagePath) throw new Error('Set SYSTEM_ONE_API_KEY and supply a PNG path.');

const images: readonly ImageInput[] = [{
  mediaType: 'image/png',
  base64: (await readFile(imagePath)).toString('base64'),
}];

const client = createSystemOne({
  adapter: systemOneAdapter,
  transport: createFetchTransport(),
  apiKey,
  timeoutMs: 30_000,
  maxRetries: 0,
});

const result = await client.extract({
  model: 'clairic',
  state: '',
  images,
  fields: { invoice_number: textField() },
});
console.log(result.answers.invoice_number.value);

This is extraction, not a decision. Decision images on hosted Clef still use Fetch because systemOneAdapter does not encode evaluate() images.

HTTP equivalent

CamelCase field names in the SDK become snake_case in the actual HTTP request (for example referenceDate → reference_date). The following body is what POST /v1/systemone accepts for the same task:

{
  "model": "clairic",
  "state": "INVOICE INV-2291\nIssued: 2026-09-02, net 30\nTotal due: 1080.00",
  "reference_date": "2026-10-19",
  "fields": {
    "invoice_number": { "type": "text" },
    "total": { "type": "number", "decimals": 2 }
  }
}

See the API extraction contract for authentication, idempotency (retrying the same operation with the same key does not create a second charge while the replay record remains), and headers. Extraction credits are billed once per request from input size, not multiplied by field count. Check the current credit rate before sending.

Next steps

  • SDK install and evaluate()
  • Hosted SDK quickstart
  • Choose a model
  • API reference

TypeScript SDK

Install the System One TypeScript SDK, choose a service, and work with typed decisions and Clairic extract.

Get started with the TypeScript SDK

Install the System One TypeScript SDK, connect to the hosted API, pick a model, and read a typed decision.

On this page

Answer-readyInstallExtract an invoiceRequestField typesResponseImages with extract()HTTP equivalentNext steps