SDK & API
Configure the public settlement API and separate authenticated Organization API, then use the browser SDK safely.
Run the read-only service
Use an actual reviewed policy and matching RPC. The API defaults to loopback. Set an exact Front CORS origin; a hosted HTTPS Front needs a reachable HTTPS API. Send public operation data, never wallet secrets or private notes.
The settlement service does not automatically load .env files. Start the index worker separately before attaching its SQLite database. The default API address is 127.0.0.1:3001; it has no signing key, private-note upload, proving or broadcast endpoint.
export CORE_POLICY_FILE=/absolute/path/to/trusted-policy.json
export CORE_RPC_URL=https://rpc.testnet.near.org
export CORE_ALLOWED_ORIGINS=https://your-front-origin.example
export CORE_INDEX_DB=/absolute/path/to/settlement.sqlite
npm run index -- once
npm run serve
# In a separate process, keep indexing new records.
npm run index -- watchHTTP endpoints
| Method | Path | Purpose |
|---|---|---|
| GET | /healthz | Process liveness; not chain readiness. |
| GET | /readyz | Verified deployment and attached-index readiness snapshot. |
| GET | /v1/config | Public policy for independent comparison. |
| GET | /v1/group/capacity | Pinned tree capacity and first-member deposit observation. |
| GET | /v1/vaults | Verified finalized vault discovery. |
| POST | /v1/recipients/readiness | Finalized account existence, token registration and exact registration call. |
| POST | /v1/deposits/prepare | Public commitment/root planning with bounded verified capacity. |
| POST | /v1/ft/preflight | Balances, registrations, storage prerequisites, and costs. |
| POST | /v1/settlements/status | Bound finalized state and permitted recovery. |
| POST | /v1/transactions/verify | Exact finalized wallet-call verification. |
| POST | /v1/invoices/verify | Merchant signature and current FullAccess key. |
| POST | /v1/invoices/status | Indexed invoice totals, references, timing, and coverage. |
| GET | /v1/index/status | Checkpoint, provenance, and discovery coverage. |
| GET | /v1/activity | Public journal events with stable filtered pagination. |
Browser SDK and wallet execution
Front vendors Core’s browser-safe SDK/declarations with a SHA-256 manifest checked at build. Wallets sign each reviewed call; no service signing key is used.
Build the bundle in Core and synchronize it into Front. This repository workflow does not require a published npm package.
cd Core
npm run build:client
cd ../Front
npm run sync:core
npm run verify:core
npm run buildIndex coverage and failure states
SQLite persists journal records, checkpoints, and verified provenance. V2 invoice lookup uses a disclosure-root index for up to 32 signed-derived references, with bounded matching-record reads.
Errors distinguish disabled, not-ready, and failed reads. Incomplete coverage yields review_required. The checkpoint is not a latest-chain assertion or proof of complete company history.
API limits and cancellation
The default API permits two concurrent work requests and 120 weighted points per direct socket peer per minute. Capacity/catalog/readiness queries cost 5 points. Per-route source-read budgets and a 15-second deadline bound each request. Rate or concurrency rejections provide Retry-After; clients do not automatically repeat wallet signatures.
The CLI server cancels its HTTP RPC transport on timeout or disconnect. Non-cancellable adapters keep their work slot until underlying reads settle. Forwarding headers are ignored; clients behind a proxy share its peer budget unless the edge enforces individual limits.
/healthz checks liveness. /readyz verifies the deployment and, when attached, index age, block lag and current journal count. Set CORE_API_REQUIRE_INDEX=true to require an index. Readiness is a snapshot, not complete provenance or a guarantee of payment liquidity.
Recipient readiness
POST /v1/recipients/readiness accepts only a public recipient account. The server verifies the pinned group and reads account existence and token registration at one final block. It returns account_missing, registration_required or ready, with no account-creation estimate or broadcast. The browser client first checks the API policy and rejects substituted destinations or registration calls.
const result = await gateway.recipientReadiness(trustedPolicy, recipient, { signal });
// result.state, result.checkedAtBlock, result.registrationCall
npm run cli -- recipient-readiness trusted-policy.json https://rpc.testnet.near.org receiver.testnetBrowser notes and public deposits
createPrivateNote, encryptNoteBackup and openNoteBackup run locally. The note domain and Poseidon commitment match the existing circuits. The encrypted core-private-note format binds the complete policy and is separate from journal and invoice-library storage.
POST /v1/deposits/prepare accepts only a public commitment, disclosure root and optional vault. The server verifies the original group at one final block and returns a public FT plan and bounded capacity observation. The client checks policy, commitment, reference, vault, token, add-on fee and attachments before returning the plan.
The default deposit scan checks up to 20 vault records. An explicit member can be verified beyond that window, but remains a partial scan unless checkedRecords equals vaultCount. A prepared plan is a snapshot, not a reservation; full groups reject new deposits.
const note = await createPrivateNote(trustedPolicy);
const encrypted = await encryptNoteBackup(trustedPolicy, note, passphrase);
const restored = await openNoteBackup(downloadedFile, passphrase, trustedPolicy);
const result = await gateway.prepareDeposit(trustedPolicy, {
commitment: restored.note.commitment, disclosureRoot
});
// Import result.plan in the existing wallet session.Local receipt SDK
createReceipt, encryptReceiptBackup, openReceiptBackup, discloseReceipt and verifyReceiptDisclosure run locally. The eight fixed fields and SHA-256 Merkle paths match the existing Node receipt format. No receipt HTTP route is added.
The CLI disclose command accepts browser-encrypted receipts using CORE_RECEIPT_PASSWORD in the environment. Public selected proofs remain compatible with verify-bundle.
const receipt = await createReceipt(values);
const encrypted = await encryptReceiptBackup(receipt, passphrase);
const full = await openReceiptBackup(downloadedBackup, passphrase);
const selected = await discloseReceipt(full, ['asset', 'amount']);
await verifyReceiptDisclosure(selected, independentlyObtainedRoot);Run the Organization API
Use a separate process and database for team access. The loopback default is port 3002, while the settlement API uses port 3001. Enter the independently configured Organization API origin in the Organization workspace. Do not point it at the read-only settlement API.
The server requires its own audience origin, owner-only database file, exact frontend Origin allowlist and HTTPS testnet RPC. localhost and 127.0.0.1 are different origins. A hosted frontend requires a reachable HTTPS backend; the current site does not include a deployed public Organization API.
export CORE_ORGANIZATION_ORIGIN=http://localhost:3002
export CORE_ORGANIZATION_DB="$PWD/data/organizations/organizations.sqlite"
export CORE_ORGANIZATION_ALLOWED_ORIGINS=http://localhost:3000
export CORE_ORGANIZATION_RPC_URL=https://rpc.testnet.near.org
npm run serve:organizationsOrganization API endpoints
These routes belong to the Organization API origin. Except for process liveness and challenge/login, requests need an approved Origin and an origin-bound bearer session. The server checks the current finalized wallet key and current organization membership. A browser sends Origin automatically; a nonbrowser HTTP caller must provide it explicitly.
Existing-record mutations need the returned version. Never automatically replay a role, invitation, removal or ownership change after an uncertain response. Refresh the organization and audit log first.
| Method / route | Purpose |
|---|---|
| POST /v1/auth/challenge | Create a five-minute account/audience/origin-bound sign-in challenge. |
| POST /v1/auth/login | Redeem the NEP-413 signature once for a one-hour session. |
| POST /v1/auth/logout | Revoke the supplied session; does not require an identity RPC read. |
| GET /v1/organizations | List only the principal’s active organization memberships. |
| POST /v1/organizations | Create a workspace name with the authenticated account as Owner. |
| GET /v1/organizations/:id | Read the current role, permissions and versions. |
| GET /v1/organizations/:id/members | Read the member directory when permitted. |
| PATCH /v1/organizations/:id/members/:account | Change a permitted role using the member version. |
| DELETE /v1/organizations/:id/members/:account | Remove a permitted member or leave using the membership version. |
| GET /v1/me/invitations | Read only invitations addressed to this authenticated account. |
| POST /v1/me/invitations/:id/accept or /decline | Explicitly resolve a targeted invitation using its version. |
| GET / POST /v1/organizations/:id/invitations | List or create permitted directed invitations. |
| DELETE /v1/organizations/:id/invitations/:invite | Revoke a permitted invitation using its version. |
| GET /v1/organizations/:id/roles | Read the fixed role/permission matrix. |
| PATCH /v1/organizations/:id | Rename the workspace using the organization version. |
| POST /v1/organizations/:id/ownership | Explicitly transfer to an active member using the organization version. |
| GET /v1/organizations/:id/audit?before=<sequence> | Read up to 50 organization-scoped audit events per page. |
Organization browser client
After verified wallet sign-in, create the client for that same approved service origin and keep the returned session only in memory. This example runs inside Front after the user selects an organization; only an Owner or Admin can rename it. The complete login and role boundaries are described in Organizations & access.
import { OrganizationClient, type Organization } from "@/vendor/core-client/index.js";
// session comes from the verified NEP-413 login flow.
const client = new OrganizationClient(organizationApiOrigin, session.token);
const path = `/v1/organizations/${selectedOrganizationId}`;
const organization = await client.request<Organization>(path);
await client.request(path, "PATCH", {
name: "Example workspace",
version: organization.version,
});Use the private invoice API
The SDK transports signed terms with an explicit in-memory organization session. It does not persist plaintext invoice terms or tokens. A saved record is an archive, not a payment confirmation; checkout still verifies the current merchant key, independently trusted policy, fees and finalized settlement.
const invoices = new OrganizationInvoiceClient(
new OrganizationClient(apiOrigin, session.token), organizationId
);
const saved = await invoices.save(stableRequestId, signedInvoice, signal);
const page = await invoices.list(undefined, signal);
const original = await invoices.get(saved.invoice.id, signal);Reconcile and export organization invoices
invoiceHistory verifies archived terms and the API policy without requiring the historic merchant key to remain current. It never authorizes payment. Existing invoiceStatus and checkout retain the current-key requirement. The dashboard validates exact root/policy/amount bindings and marks uncertainty explicitly. CSV protects formula-like business fields; JSON retains exact atomic amount strings and nullable unknown values.
const records = await loadOrganizationInvoices(invoices, organizationId, signal);
const status = await gateway.invoiceHistory(record.invoice, { signal });
const observation = await invoiceDashboardObservation(
record, trustedPolicy, gateway.url, status
);
const rows = [{ record, observation, unavailable: false }];
const filtered = filterInvoiceDashboard(rows, { search: 'INV-', state: 'paid' });
const csv = exportInvoiceDashboard(filtered, 'csv');Verify and deduplicate payment events
Use the original raw request body; do not parse and re-serialize it before HMAC verification. Signature headers are Core-Event-Id, Core-Webhook-Timestamp, Core-Webhook-Key-Id and Core-Webhook-Signature. Retain deliberate previous keys during rotation. The authenticated event identifies one finalized payment, not a mutable aggregate invoice-paid flag.
OrganizationWebhookClient manages callbacks, delivery pagination, attempt details and versioned retry/rotation. PaymentWebhookInbox is in the Node SDK; its synchronous SQL handler must not perform asynchronous external fulfillment. External work needs a separate transactional outbox/idempotency key. HMAC authenticates the integration; it is not independent light-client or legal/tax verification.
const event = await verifyPaymentWebhook(rawUtf8Body, headers, [secret], { organizationId });
// Node SDK: combine receipt uniqueness and business SQL in one transaction.
const inbox = new PaymentWebhookInbox('/private/receiver.sqlite', organizationId);
const result = await inbox.accept(rawUtf8Body, headers, [secret], (db, event) => {
db.prepare('INSERT INTO received_payments(event_id,amount_tokens) VALUES(?,?)')
.run(event.id, event.data.amountTokens);
});
// Acknowledge 2xx only after commit, including exact duplicate receipts.Create and reconcile payout runs
A public manifest contains 1–20 entries with stable intentId, declared worker/contractor category and immutable CorporateContent. Mixed payer/policies and duplicate notes are rejected. All amounts are exact atomic strings, with token fees added on top of note principal. Arbitrary salary amounts/FX/withholding are outside the current fixed-denomination protocol.
PayoutBatchSession keeps a separate guarded operation for each recipient within one encrypted journal. It never batches invisible wallet signatures. Recovery binds the existing destination and shows additional storage. The same origin-bound current organization permissions and one-use corporate dispatch checks apply before each new payment.
const batches = new PayoutBatchClient(client, organizationId);
const batch = await batches.create(savedManifest, signal);
// A different Owner/Admin approves each exact recipient request.
const run = new PayoutBatchSession(journal, gateway, wallet, client, batch);
const row = batch.payments[0].payload.paymentId;
const review = await run.review(row);
// Review fee/recipient/call, then explicitly request wallet approval.
await run.submitReviewed(row, review.callHash);
const observations = await reconcilePayoutBatch(batch, gateway, gateway.url, signal);
const report = exportPayoutSettlement(batch, observations, 'json');Source-bound draft SDK
OrganizationTaxDraftClient supports scoped create/list/get, immutable revisions, review decisions and durable generation status/abandonment. draftBasis checks report arithmetic and exact disclosed-value bindings; validateDraftPlan rejects unsupported model content. renderTaxDraft and exportTaxDraft retain citations and preparation scope. verifyTaxDraft checks payload/source-bank hashes; current organization acceptance remains an authorized service decision.