JavaScript SDK v1

What are you trying to do?

Use Case: Replace My Login System

Add passwordless verification in 2 steps. Users verify via passkey, email code, SMS, SparkLink, or social login. Your backend verifies the signed JWT and maps the person by SVID. For a full login/session replacement, use the OIDC/BFF flow described in the Identity API docs.

Step 1: Add this to your HTML

Copy this snippet and edit the highlighted values:

html
<script
  src="https://cdn.sparkvault.com/sdk/v1/sparkvault.js"
  data-account-id="acc_YOUR_ACCOUNT_ID"
></script>

<script>
  SparkVault.products.identity.attach('.login-btn', {  // ← your login button selector
    onSuccess: async (result) => {
      await fetch('/api/auth/login', {             // ← your auth endpoint
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ token: result.token })
      });
      window.location.href = '/dashboard';         // ← your success redirect
    }
  });
</script>

Step 2: Verify the token on your backend

Security Critical

Always verify tokens server-side. Never trust the frontend result alone.

Identity Product Endpoint

Verification code must use https://auth.sparkvault.com for both the JWKS URL and the expected issuer.

import * as jose from 'jose';

const ACCOUNT_ID = 'acc_YOUR_ACCOUNT_ID';  // ← your account ID
const IDENTITY_URL = 'https://auth.sparkvault.com';

app.post('/api/auth/login', async (req, res) => {
  const { token } = req.body;

  const jwksUrl = `${IDENTITY_URL}/${ACCOUNT_ID}/.well-known/jwks.json`;
  const JWKS = jose.createRemoteJWKSet(new URL(jwksUrl));

  const { payload } = await jose.jwtVerify(token, JWKS, {
    issuer: `${IDENTITY_URL}/${ACCOUNT_ID}`,
    audience: ACCOUNT_ID,
    algorithms: ['EdDSA']
  });

  // Token is valid. SVID is the canonical identity key for your app.
  const svid = payload.svid || payload.sub;
  const user = await findOrCreateUserBySvid(svid, {
    identity: payload.identity,
    identityType: payload.identity_type
  });
  req.session.userId = user.id;
  res.json({ success: true });
});
import jwt
from jwt import PyJWKClient

ACCOUNT_ID = 'acc_YOUR_ACCOUNT_ID'  # ← your account ID
IDENTITY_URL = 'https://auth.sparkvault.com'

@app.route('/api/auth/login', methods=['POST'])
def login():
    token = request.json.get('token')

    jwks_url = f"{IDENTITY_URL}/{ACCOUNT_ID}/.well-known/jwks.json"
    jwks_client = PyJWKClient(jwks_url)
    signing_key = jwks_client.get_signing_key_from_jwt(token)

    claims = jwt.decode(token, signing_key.key, algorithms=["EdDSA"],
        issuer=f"{IDENTITY_URL}/{ACCOUNT_ID}", audience=ACCOUNT_ID)

    # Token is valid. SVID is the canonical identity key for your app.
    svid = claims.get('svid') or claims['sub']
    user = find_or_create_user_by_svid(
        svid,
        identity=claims['identity'],
        identity_type=claims['identity_type']
    )
    session['user_id'] = user.id
    return jsonify({'success': True})

Configure which auth methods to offer in Identity Product Settings.

Managed Sessions

The JavaScript SDK simple flow returns a signed verification proof. To have SparkVault own refresh-token rotation, revocation, and logout, use OIDC with a BFF: exchange codes server-side, keep refresh tokens in HttpOnly/Secure cookies, validate access JWTs locally with JWKS for normal requests, introspect only for hard checks, and call /revoke on logout.

Use Case: Accept Secure File Uploads

Let users upload files that get encrypted and stored in your vault.

Important: File Access

Uploaded files are encrypted at rest. To access them later, you need a vault member with download access or server-side access via the Ingots API. Public uploaders cannot retrieve files.

Step 1: Enable public upload

Vaults → Edit your vault → Enable Public Ingot Upload.

Step 2: Add this to your HTML

html
<script
  src="https://cdn.sparkvault.com/sdk/v1/sparkvault.js"
  data-account-id="acc_YOUR_ACCOUNT_ID"
></script>

<script>
  SparkVault.vaults.upload.attach('.upload-btn', {  // ← your upload button selector
    vaultId: 'vlt_YOUR_VAULT_ID',                   // ← your vault ID
    onSuccess: (result) => {
      console.log('Uploaded:', result.ingotId, result.filename);
    }
  });
</script>
No code option

Share the public upload URL from Vault Settings directly, no code required.

Native integration (advanced)

Drive the upload yourself instead of using the SDK drop-zone. Pass a File from your own button or drop target; the SDK shows only the secure-upload progress dialog, then closes silently so your app renders its own result UI. Ideal for chat attachments and similar flows.

javascript
// e.g. a chat attachment paperclip
fileInput.addEventListener('change', () => {
  SparkVault.vaults.upload({
    vaultId: 'vlt_YOUR_VAULT_ID',
    file: fileInput.files[0],   // skip the SDK drop-zone
    folder: 'chat/thread-42',   // optional vault sub-path, created if missing
    token: vaultAccessToken,    // optional VAT: authorize without public upload
    hideSuccessScreen: true,    // close silently when the upload finishes
    onSuccess: (result) => {
      // your app renders the "attached" UI
      addAttachmentToChat(result.ingotId, result.filename);
    },
  });
});
upload() options

file skips the drop-zone, hideSuccessScreen closes the dialog silently on completion, folder targets a vault sub-path (find-or-created), and token (a Vault Access Token) authorizes the upload without public upload being enabled.

Use Case: Check API Availability

Use the SDK health module for lightweight online checks. It calls SparkVault's root health endpoint and returns a structured result instead of throwing on connectivity failures.

javascript
const health = await SparkVault.health.check();

if (!health.online) {
  console.log('SparkVault is unreachable:', health.error);
}

Installation

CDN (Recommended)

html
<script
  src="https://cdn.sparkvault.com/sdk/v1/sparkvault.js"
  data-account-id="acc_YOUR_ACCOUNT_ID"
></script>

npm / yarn

bash
npm install @sparkvault/sdk-js
javascript
import SparkVault from '@sparkvault/sdk-js';

const sparkvault = SparkVault.init({
  accountId: 'acc_YOUR_ACCOUNT_ID'
});
Browser-Only SDK

This SDK is for browser applications (it renders UI). For server-side operations, use the REST API.

React Native Mobile SDK

Use @sparkvault/sdk-mobile for React Native and Expo apps. It includes the same config-driven Identity Product experience as the web popup: email/phone UI derived from enabled delivery methods, configured branding, light/dark mode, SVID-scoped passkeys, and OTP email/SMS/voice.

bash
npm install @sparkvault/sdk-mobile
tsx
import { createSparkVaultMobileClient } from '@sparkvault/sdk-mobile';
import { SparkVaultIdentityDialog } from '@sparkvault/sdk-mobile/identity-dialog';

const client = createSparkVaultMobileClient({
  tokenStorage,
  identityAccountId: 'acc_YOUR_ACCOUNT_ID',
  identityBaseUrl: 'https://auth.sparkvault.com',
  apiBaseUrl: 'https://api.sparkvault.com/v1'
});

<SparkVaultIdentityDialog
  client={client}
  visible={visible}
  passkeyProvider={passkeyProvider}
  onCancel={() => setVisible(false)}
  onSuccess={async (result) => {
    await client.products.identity.verifyIdentityToken(result.token, { jwks: result.jwks });
    const session = await client.account.exchangeIdentityToken(result.token);
    // Continue only after local JWT verification and Core exchange succeed.
  }}
/>;
Token Verification

Mobile client-side verification protects the app flow before token exchange. Third-party backends must still verify Identity JWTs server-side with the JWKS endpoint and map product records by SVID.


Reference

Identity API Reference

Namespaced under products

Identity is a first-party product and lives at sparkvault.products.identity. All methods below are called as sparkvault.products.identity.signIn(...), etc.

signIn(options?)

Open the sign-in popup. Returns a promise that resolves with the verification result. This is the single programmatic entry point. attach() binds it to element clicks. Sign-in always runs in a first-party popup on the Identity origin (so cross-domain SSO works); there is no inline/in-page mode.

javascript
const result = await sparkvault.products.identity.signIn({
  email: 'user@example.com',  // Pre-fill email (optional)
  onCancel: () => { ... }     // Called if user closes the popup
});

// result.token - Signed JWT (verify on backend!)
// result.identity - Verified email or phone
// result.identityType - 'email', 'phone', or 'social'
// result.svid - Canonical SparkVault ID
// result.sessionId - Managed Identity session ID

Options

ParameterTypeRequiredDescription
email string Optional Pre-fill email address
phone string Optional Pre-fill phone (E.164 format: "+14155551234")
backdropBlur boolean Optional Override backdrop blur for this popup (uses global config if omitted)
flow "auto" | "popup" | "redirect" Optional "auto" (default) and "popup" open the popup; "redirect" navigates the tab to the sign-in page instead (its return leg is handleRedirectResult())
onSuccess function Optional Callback on success
onError function Optional Callback on error
onCancel function Optional Callback when user closes the popup

Result

FieldTypeDescription
token string Signed JWT token (Ed25519). Verify on your backend.
identity string Verified email or phone number
identityType "email" | "phone" | "social" Type of identity verified
svid string Canonical SparkVault ID for the person
sessionId string Managed Identity session ID
refreshToken string Present only for flows that intentionally return managed-session refresh material

handleRedirectResult(options?)

Call once on every page load. It redeems a returned one-time, PKCE-bound code (from a flow: 'redirect' sign-in, or the silent SSO self-heal), never the token itself, and, when a popup's result was lost (e.g. a mobile browser discarded the backgrounded tab mid-login), it silently re-mints from the SSO session so the sign-in still completes. It no-ops (resolves null) otherwise. Wiring it is strongly recommended: it is what makes the popup reliable on mobile. The result arrives here as the same shape signIn() delivers; verify result.token on your backend.

javascript
// On EVERY page load: redeems a returned code or self-heals a lost popup result.
sparkvault.products.identity.handleRedirectResult({
  onSuccess: (result) => createSession(result.token),  // same handler as signIn()
}).catch((error) => showError(error));

SparkVault.isRecoveryPending()

Static, side-effect-free, and instance-free: returns true when this page load has a sign-in to complete: a returned handoff code/error, or a popup whose result was lost. On a high-traffic page where you defer init() for performance, call this first so you only boot the SDK when handleRedirectResult() actually has work to do. A visitor who never signed in always gets false.

javascript
// Boot the SDK for the return leg ONLY when a sign-in needs completing.
if (SparkVault.isRecoveryPending()) {
  SparkVault.init({ accountId: 'acc_...' })
    .products.identity.handleRedirectResult({
      onSuccess: (result) => createSession(result.token),
    }).catch(showError);
}

attach(selector, options)

Bind verification to element clicks. Returns a cleanup function.

javascript
const cleanup = sparkvault.products.identity.attach('.login-btn', {
  onSuccess: (result) => { ... },
  onCancel: () => { ... }
});

// Later: remove click handlers
cleanup();

close()

Programmatically close the sign-in popup.

javascript
sparkvault.products.identity.close();

signInWithFedcm(options?)

One-click sign-in through the browser's native FedCM account chooser. When the person is already signed into auth.sv (carrying the SSO session), the browser surfaces a "Continue as …" prompt with no popup, redirect, or typing. Requires a registered clientId in the SDK config. Resolves with the verified result, or null when the browser has no FedCM support (so you can fall back to signIn()); throws UserCancelledError when the person dismisses the chooser. Feature-detect with the static IdentityModule.isFedcmAvailable().

javascript
import { IdentityModule } from '@sparkvault/sdk-js';

const result = IdentityModule.isFedcmAvailable()
  ? await sparkvault.products.identity.signInWithFedcm()
      .catch(() => sparkvault.products.identity.signIn())
  : await sparkvault.products.identity.signIn();
ParameterTypeRequiredDescription
mediation 'optional' | 'required' | 'silent' Optional FedCM mediation mode passed to the browser's credential request
nonce string Optional Replay-binding value carried into the token's nonce claim (generated when omitted)

portalUrl(options?)

Build a deep link into the auth.sv self-service Identity portal, where a signed-in person manages their SparkVault Identity across every SparkVault-integrated site. Returns an absolute URL on the configured portalBaseUrl (default https://auth.sv).

javascript
// Manage this site (block, notifications, etc.)
window.location.href = sparkvault.products.identity.portalUrl({ section: 'sites' });

// Open the security screen
const url = sparkvault.products.identity.portalUrl({ section: 'security' });
ParameterTypeRequiredDescription
section string Optional Portal screen to open: home | identity | security | sessions | sitesDefault: home
site string Optional Focus a specific connected site on the Sites screen (an acc_… account ID). When section is sites and site is omitted, defaults to this SDK's own accountId. Ignored for other sections.

decodeToken(token)

Decode an identity token's claims without verifying its signature. This is an unverified, client-side decode: it parses the JWT payload and sanity-checks structure, exp, iss, aud, and the header alg (rejecting none and any non-EdDSA algorithm). It does not verify the Ed25519 signature, so its result must never be trusted for an authorization decision. Verify tokens server-side against the Identity JWKS endpoint before trusting any claim.

javascript
const claims = sparkvault.products.identity.decodeToken(result.token);
console.log(claims.svid, claims.exp);

Authentication Methods

Configure which methods to offer in Identity Product Settings.

Social redirects

Social providers use a full-page OAuth redirect. When the provider returns to your page with #token=..., products.identity.signIn() and products.identity.attach() consume that fragment once, clear it from the URL, and call onSuccess with the same result shape as passkey, OTP, and SparkLink.

Method Description
passkeyWebAuthn biometric or security key
otp_email6-digit code via email
otp_sms6-digit code via SMS
otp_voice6-digit code via voice call
sparklinkOne-click sign-in link via email
social_googleSign in with Google
social_appleSign in with Apple
social_microsoftSign in with Microsoft
social_githubSign in with GitHub
social_facebookSign in with Facebook
social_linkedinSign in with LinkedIn

Token Claims

json
{
  "iss": "https://auth.sparkvault.com/acc_xxx",
  "sub": "ing_019e66a4e27875f2822ede0e4f5d8792",
  "aud": "acc_xxx",
  "jti": "0192f3a1-7c4e-7b21-b3d4-9a8e6f5c2d10",
  "identity": "user@example.com",
  "identity_type": "email",
  "method": "otp_email",
  "verified_at": 1703977200,
  "svid": "ing_019e66a4e27875f2822ede0e4f5d8792",
  "session_id": "sess_abc123",
  "iat": 1703977200,
  "exp": 1703977500
}

Simple tokens expire after 5 minutes by default (exp = iat + 300). Optional claims (nonce, amr, acr, and action_hash) appear only when the flow binds them.

Upload API Reference

upload(options)

Open the upload widget. Returns a promise that resolves when upload completes.

javascript
const result = await sparkvault.vaults.upload({
  vaultId: 'vlt_abc123',
  target: '#container',  // Render inline instead of modal (optional)
  onProgress: (p) => console.log(p.percentage + '%')
});

// result.ingotId - Uploaded file ID
// result.filename - Original filename
// result.sizeBytes - File size

Options

ParameterTypeRequiredDescription
vaultId string Required Vault ID to upload to (public upload must be enabled unless token is provided)
target HTMLElement | string Optional CSS selector or element for inline rendering
file File Optional Upload this File directly, skipping the SDK drop-zone. Your app owns file selection and the SDK shows only the secure-upload progress dialog
folder string Optional Slash-delimited folder path within the vault (e.g. Accounts/001xx); missing path segments are find-or-created. Omitted means the vault root.
token string Optional Vault Access Token (VAT). When provided, the VAT authorizes the upload; no public-upload flag required. When omitted, the public upload flow is used.
backdropBlur boolean Optional Blur background in dialog mode (default: true)
hideUploadAnother boolean Optional Hide "Upload Another File" button on success (for single-file flows)
hideSuccessScreen boolean Optional Skip the success screen entirely: on completion the SDK fires onSuccess and closes the dialog, so your app renders its own post-upload UI
onSuccess function Optional Callback on success
onError function Optional Callback on error
onCancel function Optional Callback when user cancels
onProgress function Optional Callback for progress updates

Result

FieldTypeDescription
ingotId string Unique identifier for the uploaded file
vaultId string Vault the file was uploaded to
filename string Original filename
sizeBytes number File size in bytes
uploadTime string Upload timestamp (ISO 8601)

Progress callback

javascript
{
  bytesUploaded: 52428800,
  bytesTotal: 104857600,
  percentage: 50,
  phase: 'uploading'  // 'uploading' | 'ceremony' | 'complete'
}

upload.attach(selector, options)

Bind upload to element clicks. Returns a cleanup function.

javascript
const cleanup = sparkvault.vaults.upload.attach('.upload-btn', {
  vaultId: 'vlt_abc123',
  onSuccess: (result) => { ... }
});

cleanup(); // Remove handlers

upload.close()

Programmatically close the upload widget.

upload.pop(options) / upload.render(options)

Aliases on the callable: pop() opens the upload widget as a dialog, equivalent to calling upload(options), and render() renders it inline, equivalent to upload({ ...options, target }).

Vaults API Reference

The vaults module is the control plane: create vaults, unseal them for data-plane access, and manage their sharing and upload configuration. The browser upload widget (vaults.upload, documented above) also lives here.

Store the VMK

create() returns the Vault Master Key (vmk) exactly once. It cannot be recovered. Store it securely. Unsealing, deleting, and enabling sharing all require it.

javascript
// Create a vault. Save the VMK!
const vault = await sparkvault.vaults.create({ name: 'My Vault' });

// Unseal to get a short-lived Vault Access Token (VAT).
// The returned object is passed to ingots/folders calls.
const unsealed = await sparkvault.vaults.unseal(vault.id, vault.vmk);

// Inspect, rename, seal
const detail = await sparkvault.vaults.get(vault.id);
await sparkvault.vaults.update(vault.id, { name: 'Renamed' });
await sparkvault.vaults.seal(vault.id);

// List vaults — paginated: returns a page { vaults, nextCursor }.
// Follow nextCursor to fetch subsequent pages.
const page = await sparkvault.vaults.list();
page.vaults.forEach((v) => console.log(v.name));

// Delete requires the vault's exact name as confirmation (sent as the
// X-Confirm-Name header, case-sensitive) — not the VMK.
await sparkvault.vaults.delete(vault.id, vault.name);

Sharing

javascript
const config = await sparkvault.vaults.getSharingConfig(vault.id);

await sparkvault.vaults.enableSharing(vault.id, vault.vmk, {
  allIngotsPublic: false,
  sessionLengthSeconds: 3600,
});
await sparkvault.vaults.updateSharingConfig(vault.id, { sessionLengthSeconds: 7200 });
await sparkvault.vaults.disableSharing(vault.id);

Upload configuration & access-log retention

javascript
const upload = await sparkvault.vaults.getUploadConfig(vault.id);

await sparkvault.vaults.enableUploadPortal(vault.id, vault.vmk);
await sparkvault.vaults.disableUploadPortal(vault.id);
await sparkvault.vaults.enableUploadWidget(vault.id, vault.vmk);
await sparkvault.vaults.disableUploadWidget(vault.id);
await sparkvault.vaults.updateUploadConfig(vault.id, {
  maxSizeBytes: 1048576,
  notificationEmail: 'ops@example.com',
});

const retention = await sparkvault.vaults.getAccessLogRetention(vault.id);
await sparkvault.vaults.updateAccessLogRetention(vault.id, 7776000);

Ingots API Reference

The ingots module operates on the contents of an unsealed vault. Pass the object returned by vaults.unseal(...) as the first argument. It carries the short-lived Vault Access Token.

Primitives vs. high-level flows

createUpload() and createDownloadLink() are discrete primitives that return a Forge URL. upload() and download() are the high-level flows: they drive the resumable transfer end-to-end and verify server-side finalization.

javascript
const unsealed = await sparkvault.vaults.unseal(vault.id, vault.vmk);

// High-level upload: creates the session, streams over TUS, verifies finalized.
const ingot = await sparkvault.ingots.upload(unsealed, {
  file: myFile,
  name: 'document.pdf',
  onProgress: (uploaded, total) => console.log(uploaded / total),
});

// High-level download: fetches a fresh signed link and returns a Blob.
const blob = await sparkvault.ingots.download(unsealed, ingot.id);

// Discrete primitives: drive the transfer yourself.
const session = await sparkvault.ingots.createUpload({
  vault: unsealed, name: 'big.zip', contentType: 'application/zip', sizeBytes: file.size,
});
const link = await sparkvault.ingots.createDownloadLink(unsealed, ingot.id);

Manage & organize

javascript
await sparkvault.ingots.rename(unsealed, ingot.id, 'renamed.pdf');
await sparkvault.ingots.move(unsealed, ingot.id, 'fld_xyz');   // null = vault root
await sparkvault.ingots.replace(unsealed, ingot.id, { file: newFile });
await sparkvault.ingots.delete(unsealed, ingot.id);

const meta = await sparkvault.ingots.get(unsealed, ingot.id);
const { ingots } = await sparkvault.ingots.list(unsealed);
const found = await sparkvault.ingots.search(unsealed, { q: 'invoice' });
const contents = await sparkvault.ingots.listContents(unsealed, { folderId: 'fld_xyz' });

list(), search(), listContents(), and getAccessLogs() accept { limit, cursor } pagination and return a nextCursor. list() and listContents() also accept sortBy (name | size | content_type | created | access_count) and sortOrder (asc | desc); search() also accepts fileType, minSize, maxSize, and sortOrder.

Sharing & access logs

javascript
await sparkvault.ingots.updateSharingConfig(unsealed, ingot.id, { shared: true, visibility: 'invite_only' });
const sharing = await sparkvault.ingots.getSharingConfig(unsealed, ingot.id);

// Optional 4th arg: invite lifetime (omit to inherit the link's existing expiry)
const invite = await sparkvault.ingots.addInvite(unsealed, ingot.id, 'user@example.com', { expiresInSeconds: 86400 });
await sparkvault.ingots.revokeInvite(unsealed, ingot.id, invite.id);

const { logs } = await sparkvault.ingots.getAccessLogs(unsealed, ingot.id, { limit: 100 });

Folders API Reference

The folders module organizes ingots within an unsealed vault. The flat list returned by list() is enough to build the folder tree client-side.

javascript
const unsealed = await sparkvault.vaults.unseal(vault.id, vault.vmk);

const folders = await sparkvault.folders.list(unsealed);
const folder = await sparkvault.folders.create(unsealed, { name: 'Invoices' });
const detail = await sparkvault.folders.get(unsealed, folder.id);
const trail = await sparkvault.folders.getBreadcrumb(unsealed, folder.id);

await sparkvault.folders.update(unsealed, folder.id, { name: 'Renamed' });
await sparkvault.folders.move(unsealed, folder.id, 'fld_parent');  // null = vault root
await sparkvault.folders.togglePin(unsealed, folder.id, true);
await sparkvault.folders.moveIngot(unsealed, 'ing_abc', folder.id); // null = vault root
await sparkvault.folders.delete(unsealed, folder.id);

Sparks API Reference

Sparks are end-to-end encrypted, read-once ephemeral secrets scoped to your account (no vault or VAT required). Reading a spark with get() burns it.

javascript
const spark = await sparkvault.sparks.create({
  payload: 'top secret',
  ttlMinutes: 60,             // defaults to 1440 (24h)
  contentType: 'text/plain',  // optional MIME type (base64 payload for binary types)
  filename: 'note.txt',       // optional, for file payloads
});

// Kindling groups related sparks into a family
const first = await sparkvault.sparks.create({ payload: 'one', withKindling: true });
const sibling = await sparkvault.sparks.create({ payload: 'two', kindling: first.kindling });

const { sparks } = await sparkvault.sparks.list();       // filters: { kindling, status, limit, cursor }
const revealed = await sparkvault.sparks.get(spark.id);  // burns the spark
await sparkvault.sparks.delete(spark.id);

Public sharing (SparkLink)

javascript
// Share via a public x.sv link
const share = await sparkvault.sparks.share(spark.id, { visibility: 'public' });
console.log(share.shareUrl);   // https://x.sv/...

const status = await sparkvault.sparks.getShare(spark.id);
await sparkvault.sparks.unshare(spark.id);

Entropy API Reference

Generate cryptographically strong random values from the SparkVault hardware-backed entropy service.

javascript
// Formatted output: hex | base64 | base64url | alphanumeric | alphanumeric-mixed | password | numeric | uuid | bytes
const { value } = await sparkvault.entropy.generate({ bytes: 32, format: 'hex' });

// Raw bytes as a Uint8Array
const key = await sparkvault.entropy.generateBytes(32);

bytes must be an integer from 1 to 1024 (a ValidationError is thrown otherwise). For format: 'bytes' the value is a number array.

Notifications API Reference

The signed-in user's metadata-only notification inbox. The recipient is always derived from the session token, so every call reads or mutates only the caller's own inbox. Rows are locked pointers: the content lives behind each row's SparkLink (sparklink_code), never in the row itself. Requires an access token (accessToken / getAccessToken).

javascript
// Page the inbox (newest first). Views: all | unseen | unread | archived (default all).
const { notifications, cursor } = await sparkvault.notify.getInbox({ state: 'unread', limit: 50 });
// A page can come back SHORT of limit yet still carry a non-null cursor — always follow the cursor.

// Bounded unseen badge count; `capped` true means render "N+".
const { unread_count, capped } = await sparkvault.notify.getUnreadCount();

// Mark one of your rows seen | read | archived (idempotent). `createdAt` MUST be the row's own
// created_at, round-tripped from the list row — the id alone cannot address the row.
await sparkvault.notify.markState(row.notification_id, { createdAt: row.created_at, state: 'read' });

Browser Web Push

Opt the current browser into push notifications for the pointer (never content). Call from a user gesture. Your app hosts and registers the service worker; the SDK handles the VAPID key, permission, subscription, and server registration, returning a typed status instead of throwing on the expected declines. subscribeWebPush returns not_configured until the platform VAPID key is provisioned, so gate your UI on isWebPushSupported() and that status.

javascript
if (sparkvault.notify.isWebPushSupported()) {
  const registration = await navigator.serviceWorker.register('/sw.js');
  const { status } = await sparkvault.notify.subscribeWebPush({ serviceWorkerRegistration: registration });
  // status: 'subscribed' | 'already_subscribed' | 'not_supported' | 'not_configured' | 'permission_denied'

  // Later, to turn it off on this device:
  await sparkvault.notify.unsubscribeWebPush({ serviceWorkerRegistration: registration });
}

Health API Reference

health.check(options?)

Check SparkVault API availability. Returns a structured result and does not throw for offline/network failures.

javascript
const result = await sparkvault.health.check({
  timeout: 5000
});

// result.online - true when the API returns 2xx
// result.status - 'healthy' | 'unhealthy' | 'unreachable'
// result.httpStatus - HTTP status when a response was received
// result.checkedAt - Unix timestamp
// result.error - network/timeout message when unreachable

health.isOnline(options?)

Convenience method that resolves to a boolean.

javascript
const online = await sparkvault.health.isOnline({ timeout: 5000 });

Error Handling

javascript
try {
  const result = await sparkvault.products.identity.signIn();
} catch (error) {
  switch (error.code) {
    case 'user_cancelled':
      // User closed the popup (not an error)
      break;
    case 'validation_error':
      console.error('Invalid input:', error.message);
      break;
    case 'network_error':
      console.error('Network error');
      break;
    case 'timeout_error':
      console.error('Request timed out');
      break;
    default:
      console.error('Error:', error.message);
  }
}
Code Description
user_cancelledUser closed the popup
validation_errorInvalid input or configuration (HTTP 400)
authentication_errorMissing or invalid credentials (HTTP 401)
authorization_errorNot permitted to access this resource (HTTP 403)
PLAN_REQUIREDThe account has no active subscription and attempted a billable action (HTTP 402); surface a subscribe CTA to admins
QUOTA_EXCEEDEDA pooled-capacity or seat limit is exhausted (HTTP 402); error.resource identifies the pool: storage | bandwidth | seats | identity
network_errorNetwork connectivity failure
timeout_errorRequest timed out
popup_blockedBrowser blocked popup

The 401/403 and 402 billing gates apply to the authenticated vaults, ingots, and sparks calls on this page. Each code maps to an exported error class (e.g. PlanRequiredError, QuotaExceededError) for instanceof checks.

Configuration Options

javascript
const sparkvault = SparkVault.init({
  accountId: 'acc_YOUR_ACCOUNT_ID',  // Required
  backdropBlur: true,                 // Blur background on modals (default: true)
  timeout: 30000,                     // HTTP timeout in ms (default: 30000)
  preloadConfig: true                 // Preload config for instant modals (default: true)
});

Advanced options

ParameterTypeRequiredDescription
apiBaseUrl string Optional Core API origin. A trailing /v1 is accepted and normalized.Default: https://api.sparkvault.com
identityBaseUrl string Optional Identity Product API base URLDefault: https://auth.sparkvault.com
portalBaseUrl string Optional auth.sv portal origin for portalUrl() deep linksDefault: https://auth.sv
accessToken string Optional Static SparkVault Core access token for authenticated API calls
getAccessToken function Optional Dynamic Core access-token provider (sync or async) for authenticated API calls
apiKey string Optional API key for server-side SDK use
clientId string Optional OIDC client ID registered for this account. Required only for FedCM one-click sign-in (signInWithFedcm()).
allowedDownloadHostPatterns RegExp[] Optional Host allowlist for backend-issued ingot download URLs. Defaults to the canonical SparkVault Forge / S3 / CloudFront hosts; override only when pointing at a custom deployment.

TypeScript

typescript
import SparkVault, {
  SparkVaultConfig,
  VerifyOptions,
  VerifyResult,
  UploadOptions,
  UploadResult,
  UserCancelledError,
  ValidationError,
  PlanRequiredError,
  QuotaExceededError,
  NetworkError
} from '@sparkvault/sdk-js';

const config: SparkVaultConfig = {
  accountId: 'acc_YOUR_ACCOUNT_ID'
};

const sparkvault = SparkVault.init(config);

const result: VerifyResult = await sparkvault.products.identity.signIn();

Debug Mode

Enable verbose console logging:

html
<script
  src="https://cdn.sparkvault.com/sdk/v1/sparkvault.js"
  data-account-id="acc_YOUR_ACCOUNT_ID"
  data-debug="true"
></script>

Browser Support

  • Chrome 80+
  • Firefox 75+
  • Safari 13.1+
  • Edge 80+

Passkey authentication requires WebAuthn support. On unsupported browsers, passkey won't appear as an option.