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
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: http://127.0.0.1:27777

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

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.