Skip to main content
[AVAILABLE], typescript/src/, v1.0.0. The original three gaps (no bearer-key auth, an unused error taxonomy, an empty test suite) were closed in an earlier pass. A follow-up full SDK audit found and fixed three more real issues: inaccurate model types (fields marked required that the real API doesn’t require, and a missing settlementConfirmations/signature field), two missing capabilities (POST /verify, GET /version), and one capability missing from both maintained SDKs (POST /transactions). All re-verified against a real running local server. See the fix history at the bottom of this page.
The package is named @parmana/sdk in typescript/package.json, private, not published to any registry a normal npm install could resolve. Install from a local path or a git reference instead. (Renamed from @parmana/legacy-reference, itself renamed from @parmana/typescript-sdk — see Changelog for when.)

Bearer-key authentication

Configuration.apiKey is sent as Authorization: Bearer <apiKey> on every request, by HttpTransport:
apiKey is optional in Configuration, for the same reason it’s optional server-side: local development against a server started with PARMANA_AUTH_DISABLED=true needs no key. Every real deployment requires one — an omitted or wrong key gets a real 401, thrown as AuthenticationError (see below), not a silent failure. See Authentication for how keys are minted.

Errors, they actually throw now

HttpTransport.send() checks response.status and throws the matching typed error for every non-2xx response, built from the real {error, code?} envelope (packages/api/src/middleware/error-handler.ts):
All extend ParmanaError, which carries a stable code (ErrorCode enum) and optional cause/requestId. 403 (AuthorizationError) is a real status this API returns — an authenticated caller asserting an authority.principalId it isn’t permitted to assert (isPrincipalAllowed, packages/api/src/routes/execute.ts) — found live during this pass and added to the Error catalog and the OpenAPI spec alongside this fix, both re-verified against source and a live server.
One route is deliberately exempt from this mapping. POST /policies/validate never uses the shared {error, code?} envelope: every status it returns (200, 400, 404) is {valid, errors}, the caller’s answer, not an SDK-level failure. PolicyApi.validate opts those two statuses out via TransportRequest.nonThrowingStatuses; a 401 on the same route still throws AuthenticationError, since that one is generated by caller-auth middleware before the route’s own handler runs, using the shared envelope like every other route. See Error handling.

Model types, corrected against the real schemas

typescript/src/models/*.ts is hand-maintained, unlike the Python SDK’s generated models — a full audit spot-checked every field against the real JSON schemas (schemas/common/*.schema.json) and found real inaccuracies, all fixed this pass:
  • Authority.displayName, Verification.message — were marked required; the real API makes them optional.
  • Authorization.expiresAt — missing entirely; now present (optional).
  • BusinessTransactionMetadata — every field except businessTransactionId was marked required; the real API requires only businessTransactionId. The most significant of these: it forced callers to supply fields (tenantId, correlationId, sourceSystem, submittedBy, submittedAt) the real API doesn’t need.
  • ExecutionTrustRecord — was missing the required signature field and the optional settlementConfirmations field (and the SettlementConfirmation/Signature models themselves) entirely.
  • Override.authorityIdwrong field name, should be approvedBy (the real schema has no authorityId on Override at all); also missing the optional justification field. Currently unreachable in practice (no route in this repository creates an Override), but wrong is wrong.
  • Decision.outcome, Execution.status, Execution.mode, BusinessTransaction.status — were bare string; now literal unions matching the real enums exactly.
  • Execution — was missing completedAt, evidence, and metadata entirely: real, commonly-used fields (evidence in particular is where Connector evidence lives) with no way to read them through this SDK’s types before this pass.

Two capabilities added this pass, previously unreachable from this SDK

  • client.verify(businessTransactionId)POST /verify, runs a fresh verification and appends a new Verification to the record’s history. Before this pass, the SDK could only read a cached verification via getLatestVerification() (GET /verification/:id); there was no way to trigger a fresh one at all.
  • client.version()GET /version. Had no method anywhere in the SDK.

POST /transactions, missing from both maintained SDKs, now added

client.createTransaction(transaction) — a second, independent entry point into the identical execution pipeline as execute() (POST /execute), differing only in its 201 status code. Confirmed stable before adding: the route has existed since near the start of this repository’s history (18 commits into a 141-commit history), was touched by the most recent security-fix commit in lockstep with /execute, and has dedicated test coverage (packages/api/tests/unit/transactions-api.test.ts) — not a new or evolving surface.

Install

Test suite

Previously 9 files, 0 bytes each, “9 passed” trivially. Now 129 tests across 15 files, npm run test (vitest run), confirmed against a real run this pass: unit tests for every error-mapping case (test/HttpTransport.test.ts, test/Errors.test.ts), unit tests for the three capabilities added in the model-audit pass (test/NewApiMethods.test.ts), a retry-logic suite (test/RetryPolicy.test.ts, real backoff on idempotent GETs against 502/503/504, POSTs never retried, matching the Python SDK’s own retry behavior), per-route unit suites (test/AuditApi.test.ts, test/HealthApi.test.ts, test/PolicyApi.test.ts, test/RefusalApi.test.ts, test/ReplayApi.test.ts, test/RuntimeApi.test.ts, test/VerificationApi.test.ts), and two integration suites that boot the actual @parmana/api Express application — real StaticKeyAuthenticator, real PolicyEngine, real Ed25519 signing, the real, NODE_ENV=test-only generic test-fixture connector (createTestFixtureConnector.ts, successor to the now-removed vendor-payment, see docs/VERIFICATION-GAPS.md G-27) — on a real OS-assigned TCP port and drive it with the real ParmanaClient over real HTTP: test/integration/parmana-client.integration.test.ts (a real 401, a real 403, a real 400, a real policy rejection, a real 404, a real 409 duplicate, plus version(), verify(), and createTransaction(), each asserted against the exact typed result and exact message the server returned) and test/integration/examples.integration.test.ts (runs the quickstart example script itself, see Changelog).

What’s still true from before

typescript/src/errors/ also declares VerificationError and ReplayError. Neither is thrown anywhere: no verified HTTP condition in this API corresponds to them (POST /verify and POST /replay return their semantic result — VERIFIED/FAILED, or a replay outcome — inside an ordinary 200, not as an error). They remain defined, unused, for the same reason they were before this pass: inventing a throw condition for them would be describing behavior the real API doesn’t have.

Next

Python SDK

The other maintained SDK — same bearer-key model, generated (not hand-maintained) models.

Error catalog

Every error the real API returns, independent of any SDK.