Skip to content

SDK Reference

Two SDK packages provide Sign It functionality. Both sign through the user's Flowsta Vault: the user approves each signature in a Vault dialog and the keys never leave their device.

PackageUse CaseHow It Signs
@flowsta/authWeb apps using OAuthDetects the user's local Vault and signs through it (user approves each signature)
@flowsta/holochainDesktop Holochain appsDirect IPC call to Flowsta Vault - Vault signs locally, user approves

@flowsta/auth - Web App Signing

For web apps that use "Sign in with Flowsta" (OAuth). Requires the sign scope.

hashFile(file)

Hash a file using SHA-256 in the browser via SubtleCrypto. The file is never uploaded.

typescript
import { hashFile } from '@flowsta/auth';

const file = document.querySelector('input[type=file]').files[0];
const hash = await hashFile(file);
// hash = "a7f3b9c1e2d4..." (64 hex characters)
ParameterTypeRequiredDescription
fileFileYesFile object from file input or drag-and-drop

Returns: Promise<string> - hex-encoded SHA-256 hash (64 characters)


signFile(options)

Request a signature for a file hash. The file is never uploaded - only the hash leaves your app.

signFile() probes for a running Flowsta Vault on every call:

  • Vault running (the normal case): signs via the Vault. The user approves the signature in a Vault dialog - your clientId is included, so sponsored signing applies and the dialog shows whose quota pays. The key never leaves their device.
  • No Vault running: throws VaultRequiredError - signing keys live only in the user's Vault, so there's nothing else that can sign. Prompt the user to open or install Flowsta Vault.
typescript
const result = await flowsta.signFile({
  fileHash: hash,
  intent: 'Authorship',
  aiGeneration: 'none',
  contentRights: {
    license: 'cc-by',
    aiTraining: 'not_allowed',
    contactPreference: 'allow_contact_requests',
  },
});
console.log('Signed:', result.action_hash);
ParameterTypeRequiredDescription
fileHashstringYesSHA-256 hex string (64 characters)
intentstringNoAuthorship, Approval, Witness, Receipt, Agreement. Default: Authorship
aiGenerationstringNonone, assisted, generated
contentRightsobjectNoSee Content Rights for all fields

Returns:

FieldTypeDescription
successbooleantrue on success
file_hashstringThe hash that was signed
agent_pub_keystringSigner's Holochain agent key (uhCAk... format)
signed_atnumberUnix timestamp in milliseconds
action_hashstring | nullDHT action hash (hex)

Errors:

Error ClassCodeWhen
UserDeniedErroruser_deniedThe user declined the request in the Vault dialog
VaultRequiredErrorvault_requiredNo Vault is reachable - nothing else holds the user's signing keys. Also thrown (with a specific message) when the Vault is locked
VaultIdentityMismatchError (2.4.0)'vault_identity_mismatch'The local Vault holds a different identity than the signed-in user - refused before any signature; tell the user to switch Vaults, never fall back to remote signing
FlowstaAuthErrortimeoutThe user didn't respond to the Vault dialog in time (~60s)

Requires: sign scope

Signatures made via the Vault publish to Flowsta's tamper-proof network, built on Holochain, over the next few minutes via gossip - a just-signed file may briefly return no verification results.


signBatch(options)

One approval per signature

The Vault approves one document at a time, so signBatch() throws FlowstaAuthError with code batch_requires_individual_approval. Call signFile() per file instead so the user can approve each signature.

typescript
const result = await flowsta.signBatch({
  files: [
    { fileHash: hash1 },
    { fileHash: hash2, intent: 'Approval' },
  ],
  sharedMetadata: {
    intent: 'Authorship',
    aiGeneration: 'none',
    contentRights: { license: 'all-rights-reserved' },
  },
});
console.log(`Signed ${result.signed}, failed ${result.failed}`);
ParameterTypeRequiredDescription
filesarrayYesArray of { fileHash, intent?, aiGeneration?, contentRights? }. Max 100 files
sharedMetadataobjectNoApplied to all files unless overridden per-file

Returns:

FieldTypeDescription
resultsarrayPer-file results: { file_hash, action_hash, success, error? }
signednumberCount of successfully signed files
failednumberCount of failed files

Requires: sign scope


verifyFile(fileHash)

Check if a file has been signed. Public endpoint - no authentication required. Verification is free and unlimited on every plan.

typescript
const result = await flowsta.verifyFile(hash);
if (result.count > 0) {
  result.signatures.forEach(sig => {
    console.log(`Signed by ${sig.signer} on ${new Date(sig.signed_at)}`);
    console.log(`License: ${sig.content_rights?.license}`);
  });
}
ParameterTypeRequiredDescription
fileHashstringYesSHA-256 hex string (64 characters)

Returns:

FieldTypeDescription
signaturesarrayArray of signature objects (see Verification API)
countnumberTotal number of signatures

getContentRights(fileHash)

Convenience wrapper over verifyFile() that returns just the content rights info from non-revoked signatures.

typescript
const rights = await flowsta.getContentRights(hash);
if (rights.signed) {
  rights.rights.forEach(r => {
    console.log(`${r.signer}: ${r.license}, AI training: ${r.aiTraining}`);
  });
}

Returns:

FieldTypeDescription
signedbooleanWhether the file has any signatures
signerCountnumberTotal number of signers
rightsarrayArray of { signer, license?, aiTraining?, commercialLicensing?, contactPreference?, aiGeneration? }. Values are the network's enum forms (e.g. CCBY, NotAllowed)

@flowsta/holochain - Desktop App Signing

For Holochain apps that run alongside Flowsta Vault. Signs via IPC - the user approves in Vault.

signDocument(options)

Request Vault to sign a file hash. Shows an approval dialog in Vault with your app name, the file label, the metadata, and whose signing quota pays (sponsored signing).

typescript
import { signDocument } from '@flowsta/holochain';

const result = await signDocument({
  clientId: 'flowsta_app_abc123...',
  appName: 'ArtStudio',
  fileHash: 'a7f3b9c1e2d4...',
  label: 'Illustration.png',
  intent: 'authorship',
  contentRights: {
    license: 'cc-by',
    aiTraining: 'not_allowed',
    contactPreference: 'allow_contact_requests',
  },
});
ParameterTypeRequiredDescription
clientIdstringYesYour app's client ID from dev.flowsta.com
appNamestringYesShown in Vault approval dialog
fileHashstringYesSHA-256 hex string (64 characters)
labelstringNoHuman-readable file name for the dialog
intentstringNoauthorship, approval, witness, receipt, agreement (Vault normalizes to the network's capitalized form, e.g. Authorship)
aiGenerationstringNonone, assisted, generated
contentRightsobjectNoSee Content Rights
ipcUrlstringNoDefault: sweeps 127.0.0.1:27777-27779 for the Vault (SDK v3 / auth 2.4)

Returns:

FieldTypeDescription
successbooleantrue if signed
fileHashstringThe hash that was signed
signaturestringBase64 Ed25519 signature
agentPubKeystringSigner's agent key (uhCAk... format)
signedAtstringISO 8601 timestamp
actionHashstring | nullDHT action hash

Errors:

Error ClassWhen
VaultNotFoundErrorVault is not running
VaultLockedErrorVault is locked
UserDeniedErrorUser rejected the signing request
SigningDnaNotInstalledErrorSigning DNA not available in Vault
IdentityMismatchError (v3)identity_mismatch

getSigningStatus(ipcUrl?)

Check if Vault is available for document signing.

typescript
import { getSigningStatus } from '@flowsta/holochain';

const status = await getSigningStatus();
if (status.available) {
  // Show "Sign with Flowsta" button
}

Returns:

FieldTypeDescription
availablebooleantrue if Vault is running, unlocked, and ready to sign
vaultRunningbooleantrue if Vault IPC server is reachable
vaultUnlockedbooleantrue if Vault is unlocked

Content Rights Object

Used by both @flowsta/auth and @flowsta/holochain:

FieldTypeValues
licensestringall-rights-reserved, cc0, cc-by, cc-by-sa, cc-by-nc, cc-by-nc-sa, mit, apache-2, gpl-3
commercialLicensingstringnot_available, open_to_licensing
aiTrainingstringallowed, allowed_with_attribution, requires_license, not_allowed
contactPreferencestringno_contact, allow_contact_requests

All fields are optional. Only declared fields are recorded in the signature. On the network (and in verification responses) these are stored in their enum forms - e.g. cc-byCCBY, not_allowedNotAllowed.

Documentation licensed under CC BY-SA 4.0.