# TVX SDK 0.1.0: API contracts

Source: OpenForex TVX SDK 0.1.0, docs/API.md. The source text below is reproduced from the bundled implementation documentation. The SDK code and documentation are MIT licensed.

Read the [toolkit overview](?page=developer/tvx-sdk), download the [source archive](?page=developer/tvx-sdk&artifact=source), or verify the [release checksums](?page=developer/tvx-sdk&artifact=checksums).

All exports are available from `@openforex/tvx` after installing the downloaded
tarball. Type declarations are generated in `dist/index.d.ts`.

## Numeric representation

`Decimal` is a TypeScript alias for string; runtime validation is authoritative.
Inputs are unsigned base-10 decimals, at most 96 characters with at most 36
fractional digits. Exponents, whitespace, grouping separators, leading plus/minus,
leading zeros (except zero itself), empty strings, NaN, and Infinity are rejected.
`amount` may be zero; TVX values must be strictly positive.

Outputs are decimal strings with the requested fixed scale. Default output scale
is 8, allowed range 0–18. Default rounding is `half-even`; `half-up` and `down`
are also supported. Precision and rounding are library choices, not a statement
that these defaults are mandated by a monetary standard.

## convert(input) and calculate(input)

| Field | Type | Meaning |
| --- | --- | --- |
| amount | Decimal | Source instrument amount |
| fromValue | Decimal | Common-reference value per source unit |
| toValue | Decimal | Same-reference value per target unit |
| decimals | number, optional | Output scale, 0–18 |
| rounding | Rounding, optional | half-even, half-up, or down |

`convert` returns the target amount. `calculate` returns a frozen record with
the original inputs, result, output policy, and exactNumerator/exactDenominator.
The fraction is not reduced, so compare ratios rather than numerator text across
different input representations. Same-currency conversion still applies output
rounding; it is not a bypass around input validation.

## pairRate(fromValue, toValue, decimals?, rounding?)

Computes the result for one source unit. Use `convert` for an amount calculation
rather than multiply a separately rounded pair rate. Reverse a pair by swapping
the values. Reciprocal/triangular identities may differ after output rounding.

## createSnapshot(input)

Validates unknown input and returns a copied, frozen snapshot with frozen
observations. Required metadata: `id`, `source`, `method`, `referenceUnit`.
Each is a nonempty string of at most 256 characters. `values` must contain
1–10,000 observations keyed by codes matching `[A-Z][A-Z0-9]{1,11}`.

Each observation requires `value` and `observedAt`. Timestamps use UTC ISO format
with seconds and either no fraction or exactly three millisecond digits:
`2026-09-24T12:00:00Z` or `2026-09-24T12:00:00.000Z`.
Impossible calendar dates and local/offset timestamps are rejected; normalize
provider times explicitly before creating the snapshot.

## quote(input)

Requires snapshot, amount, from, to, now, and maxAgeMs; accepts the same optional
numeric policy as convert. `maxAgeMs` is a nonnegative safe integer. Selected
observations in the future are rejected. Age equal to maxAgeMs is accepted.

Returns calculation fields plus from, to, snapshotId, source, method,
referenceUnit, quotedAt, sourceObservedAt, and targetObservedAt. The snapshot is
revalidated before computation; all its observations must be structurally valid,
but freshness checks apply to the selected pair. No current clock is read.

## fromSapaPayload(payload, metadata, options?)

Input is an unknown JSON object. `success` must equal true; `currencies` must be a
nonempty array. Each row needs code, tvx_value, and rate_quoted_at. Codes are
uppercased; whitespace is not silently trimmed. Metadata supplies the same four
fields as createSnapshot. Feed-level quoted_at is not substituted for a missing
row timestamp because it can conceal older observations.

Options: `aliases` explicitly maps source codes to canonical codes;
`allowNumberValues` allows finite Number inputs to be converted to decimal text.
If that conversion produces exponent notation it is rejected by the decimal
contract. Prefer decimal strings at the provider boundary.

Other fields are ignored. The adapter never substitutes market_rate_to_usd,
board_rate_to_usd, tvx_rate_to_usd, an AFRA value, or a cached fallback.
If the provider includes unusable rows, an upstream integration may deliberately
select a valid subset and record that selection before calling this adapter.

## structuralValue(input, policy)

Input: population, gdpNominal, gdpPpp, efficiency, supportFactor; optional
gdpEffectiveNominal and gdpEffectivePpp override corresponding raw GDP values.
Provided overrides must be positive; an invalid override does not silently fall
back. Policy: goldAnchor, goldWeight, alpha, beta, gamma, delta. Weights must be
nonnegative and have a finite positive sum; other consumed values must be finite
and strictly positive. No live policy defaults are supplied.

Returns value (Number), normalizedWeights, effectiveGdpNominal, and
effectiveGdpPpp. Fractional powers and their products have binary floating-point
error; extreme magnitudes may fail with NUMERIC_RANGE. A consuming valuation
pipeline must specify decimal serialization, calibration, and accepted error
tolerance before using this output as a quote observation.

## Error codes

Catch `TvxError` and inspect `.code`; messages provide context but are not stable
machine identifiers. Invalid JavaScript call shapes outside the typed API can
also produce a native TypeError; validate transport request bodies first.

| Code | Meaning |
| --- | --- |
| INVALID_DECIMAL | Invalid decimal syntax, type, or length |
| INVALID_VALUE | Nonpositive TVX value |
| INVALID_PRECISION | Unsupported output scale |
| INVALID_ROUNDING | Unknown rounding mode |
| INVALID_CODE | Malformed currency identifier |
| INVALID_METADATA | Missing or invalid snapshot metadata |
| INVALID_TIME | Invalid time or freshness policy |
| INVALID_SNAPSHOT | Invalid/empty observation map |
| DUPLICATE_CODE | Feed rows collide after normalization |
| MISSING_CURRENCY | Selected pair is absent |
| STALE_VALUE | Selected observation is too old |
| FUTURE_VALUE | Selected observation is after quote time |
| INVALID_FEED | Invalid response envelope or row structure |
| INVALID_STRUCTURE | Invalid structural inputs or weights |
| NUMERIC_RANGE | Structural overflow or underflow |

The library does not prescribe HTTP status codes. An API wrapper should define
its own authenticated request contract and map failures without exposing secrets.
