CLI tool
unicity-sphere/sphere-sdk avatar
unicity-sphere/sphere-sdk

Sphere SDK's two provider layers and where the tokens actually live

The SDK for autonomous economic agents. Give an agent an identity, a wallet, and the ability to find, negotiate with, and settle with other agents - peer-to-peer, with perfect privacy and ultra-fast finality

5,389 stars107 forksTypeScriptMIT

At a glance

What is it?
Sphere SDK is the TypeScript client for the Unicity state transition network, and its shape is dictated by custody: keys stay on the client while the wallet-api backend holds token inventory, so setup needs a second provider layer before a transfer can exist.
Who is it for?
Adopt Sphere SDK if you are writing a TypeScript application that needs Unicity payments, Nostr messaging and the Connect handshake behind one wallet, and you accept a backend that holds the token inventory. Skip it if you need balances on your own disk or a CLI from npm, because own-storage custody was rescinded and the sphere-cli package is not published.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on November 14, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • unicity-sphere/sphere-sdk5,389 ★ · -1
Star history
Repository2026-09-132026-11-14
unicity-sphere/sphere-sdk5.4k5.4k

-1 Stars in the last 62 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

npm install @unicitylabs/sphere-sdk, plus ws when the app runs on Node.js

Two npm lines cover the common setups, and the second one is not optional on Node.js:

bash
npm install @unicitylabs/sphere-sdk        # browser
npm install @unicitylabs/sphere-sdk ws     # Node.js: ws is required, see "Node.js Providers"

A first wallet needs imports from three entry points. The root exports `Sphere`, `TokenRegistry`, `getCoinIdBySymbol` and `randomUUID`. The provider factories sit under `impl`, and the wallet-api layer has its own subpath:

typescript
import { Sphere, TokenRegistry, getCoinIdBySymbol, randomUUID } from '@unicitylabs/sphere-sdk';
import { createBrowserProviders } from '@unicitylabs/sphere-sdk/impl/browser'; // untyped entry: add the declaration shim below
import { createWalletApiProviders } from '@unicitylabs/sphere-sdk/impl/shared/wallet-api';

// One network literal, used in all three places below.
const NETWORK = 'testnet2';

// A per-device id: stable across launches on this device, different on every device.
function deviceId(): string {
  let id = localStorage.getItem('sphere-device-id');
  if (!id) {

Storage differs by target rather than by config: IndexedDB in a browser, a wallet file under `./sphere-data` on Node.js, which wants version 22 or newer. Keep the per-device id stable across launches on that device, which is what the comment in the sample requires of you.

The network literal has to reach three call sites

Money cannot move until `walletApi` exists, because `createBrowserProviders` and `createNodeProviders` build only the base ports: `storage` for keys, identity and journals, `transport` for Nostr, and `oracle` for the gateway and trust base. Handing that base to `createWalletApiProviders` is what attaches the config the payments vertical is composed from:

typescript
{ network, baseUrl, deviceId?, fetchFn?, webSocketFactory?, paymentsV2Transport? }

Four of those keys are optional, and `network` has to agree with two other places. Neither provider factory returns a `network` field, so spreading the provider object cannot supply it. `Sphere.init` compares its own `network` with `walletApi.network` as plain strings and throws `INVALID_CONFIG` on a mismatch, including when `Sphere.init` gets no `network` at all, and that comparison happens before any storage write. `'testnet'` and `'testnet2'` reach the same endpoints, which is exactly the trap: different strings, so a mix fails the check. Use one constant for the base providers, the `walletApi` config and `Sphere.init`.

Nostr carries the messages, wallet-api carries the tokens

Two networks live inside one wallet and they do not overlap. Nostr handles NIP-17 direct messages, NIP-29 group chat and nametag publishing. Transfers take a different route: the token engine certifies the transfer on chain, and the finished token is deposited into the recipient's wallet-api mailbox, with intents kept server side and resumed under the same `transferId` after a crash. Wire up only the Nostr transport and you have a working chat bot with no payments, which is why the feature list marks messaging as not the payment rail.

Custody runs against the usual wallet story. The wallet-api backend holds your token inventory and your keys never leave the client. Own-storage custody was rescinded, so there is no local token store to fall back on, and a team that planned to hold balances on its own disk has to redesign that part before writing a line of integration code.

generatedMnemonic is returned once, and a thrown init swallows it

`generatedMnemonic` comes back from exactly one call, the `Sphere.init` that created the wallet. The phrase is written to storage before the rest of setup runs, so a failure later in that same call, a requested `nametag` that is already taken is the case given, leaves a wallet on disk whose phrase your code never received. The next `Sphere.init` then loads that wallet with `created: false`, which looks like an ordinary existing wallet and hides the loss.

Read the phrase again with `sphere.getMnemonic()` until the user confirms, and gate the backup prompt on your own `backup confirmed` flag rather than on `created`. Treating `created: true` as proof that you captured the phrase loses the backup for a wallet the user can still open.

Every nametag send reports recipient:network-unverified

Nametag bindings carry no network today, so the SDK cannot prove that a `@nametag` recipient sits on the same network as the sender. Each such send emits a `transfer:attention` event carrying `code: 'recipient:network-unverified'` and an empty `transferId`, then proceeds on the sender's network. That event is information rather than an error, and nothing inside the SDK converts it into a block.

On mainnet the check falls on the operator: confirm the recipient runs mainnet before you send, because this event is the only warning you get. A bare 66-hex chain pubkey is taken as being on your network, so the unverified path belongs to friendly names, where a wrong guess is easiest to make.

paymentsV2Transport swaps the money ports, and skipped e2e files hide the gap

`StoragePort` and `DeliveryPort` in `modules/payments-v2/ports.ts` have wallet-api implementations, and the `paymentsV2Transport` slot in the `walletApi` config accepts a whole replacement bundle. That is the sanctioned place to point tests at a fake host or a private deployment.

End to end runs are less forgiving. `.env.example` lists the values `npm run test:e2e` reads, and the file says twice that missing keys skip suites quietly:

bash
TESTNET2_GATEWAY=https://gateway.testnet2.unicity.network
TESTNET2_API_KEY=sk_ddc3cfcc001e4a28ac3fad7407f99590
TESTNET2_TRUSTBASE_URL=https://raw.githubusercontent.com/unicitynetwork/unicity-ids/main/bft-trustbase.testnet2.json
STAGING_AGGREGATOR_KEY=sk_ddc3cfcc001e4a28ac3fad7407f99590
STAGING_WALLET_API=https://wallet-api.staging.unicity.network

Without `TESTNET2_API_KEY` the token-engine testnet2 run is skipped, and without `STAGING_AGGREGATOR_KEY` the staging suites in `tests/e2e/*.staging.e2e.test.ts` never reach the real wallet-api. The file tells you to check that a run reports seven files rather than six, because a missing key leaves a green build with the payment path untested. A wallet that never touches money passes `walletApi: 'none'` and skips all of it, which is the right call for a chat bot and the wrong one for anything you intend to pay with.

The sphere-cli package 404s, and ./impl/browser ships no declarations

Command line use goes through a separate repository, `unicity-sphere/sphere-cli`, and that package is not on npm: `npm install -g @unicity-sphere/cli` fails with a 404. Its `package.json` depends on this SDK through a local path, `file:../../sphere-sdk`, so the CLI builds only next to a checkout of this repository. A team that wants a command line wallet is signing up for a sibling checkout on disk, not an npm dependency.

TypeScript runs into a second gap on the browser side. The exports map in `package.json` gives `./impl/browser` no `types` condition, while `./impl/nodejs` and `./impl/shared/wallet-api` carry one. The quick start table repeats this and points at a declaration shim, so a strict build needs that shim committed before the browser entry point resolves.

MIT terms, a 2026-10-02 push, and a manifest version past every tag

MIT is the licence, which adds no copyleft requirement to code that links the SDK. On upkeep, the last push landed on 2026-10-26 and the tagged releases are sparse: v0.8.0 on 2026-05-29, described as UXF Inter-Wallet Transfer Protocol plus profile-layer hardening, and v0.2.4 on 2026-02-11.

`package.json` declares `0.19.2`, a version that appears in no tag. Pin the npm package by its manifest version and read `CHANGELOG.md` for what changed, because a tag name is not a safe upgrade marker here. The repository carries four Vitest configs, including `vitest.e2e.config.ts` and `vitest.relay.config.ts`, and a `.nvmrc`, so the Node.js 22 floor in the quick start table has somewhere concrete to live.

Editorial conclusion

Adopt Sphere SDK if you are writing a TypeScript application that needs Unicity payments, Nostr messaging and the Connect handshake behind one wallet, and you accept a backend that holds the token inventory. Skip it if you need balances on your own disk or a CLI from npm, because own-storage custody was rescinded and the sphere-cli package is not published. Verify three things first: that 'testnet2' is one literal across the base providers, the walletApi config and Sphere.init, that ./impl/browser is shimmed for a strict TypeScript build, and that the deployment behind baseUrl signs your network.

Frequently asked questions

What is the purpose of an SDK?

An SDK gives an application a ready-made client instead of a raw protocol surface. Sphere SDK is the TypeScript package @unicitylabs/sphere-sdk for Unicity wallet operations, wrapping BIP39 and BIP32 key derivation, engine-certified token payments, payment requests, an intent board, Nostr messaging and the Connect protocol behind one wallet object.

Does Sphere SDK keep my private keys on the wallet-api backend?

No. The wallet-api backend holds the token inventory while your keys stay on the client. Own-storage custody was rescinded, so the SDK keeps no local token store either.

What happens if I pass only createBrowserProviders to Sphere.init?

Sphere.init throws INVALID_CONFIG. The base providers supply storage, transport and oracle only, so the wallet-api transport config has to be attached with createWalletApiProviders before any transfer can be attempted.

Does Sphere SDK ship TypeScript declarations for the browser entry point?

Not yet. The exports map in package.json gives ./impl/browser no types condition while ./impl/nodejs and ./impl/shared/wallet-api carry one, so TypeScript users add the declaration shim the quick start table points at.

Official sources

  1. License: MIT
  2. Project website
  3. README
  4. Releases
  5. unicity-sphere/sphere-sdk on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/unicity-sphere-sphere-sdk.svg)](https://hysenlabs.com/projects/unicity-sphere-sphere-sdk)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/unicity-sphere-sphere-sdk.svg)](https://hysenlabs.com/projects/unicity-sphere-sphere-sdk)

Was this useful?