@sajn/sdk
v0.1.0
Published
Official TypeScript SDK for sajn API
Downloads
7
Maintainers
Readme
sajn TypeScript SDK
Official TypeScript SDK for the sajn API - a document signing and management platform.
Features
- 🔐 Type-safe - Full TypeScript support with comprehensive type definitions
- 🚀 Modern - Built for Node.js 20+ using native fetch API
- 📦 Tree-shakeable - ESM and CommonJS support
- 🎯 Resource-based - Intuitive API organized by resources
- 🔄 Promise-based - Async/await support throughout
- 📤 File uploads - Built-in support for document uploads
- 🪝 Webhooks - Type definitions for webhook events
Installation
npm install @sajn/sdkQuick Start
import { sajnClient } from '@sajn/sdk';
const client = new sajnClient({
apiKey: 'YOUR_API_TOKEN', // Get from https://app.sajn.se/settings/developer
});
// Create a document
const document = await client.documents.create({
name: 'Service Agreement',
type: 'BLANK',
signers: [
{
name: 'John Doe',
email: '[email protected]',
role: 'SIGNER',
},
],
});
// Send for signing
await client.documents.send(document.documentId, {
deliveryMethod: 'EMAIL', // REQUIRED: EMAIL, SMS, or NONE
signatureType: 'DRAWING',
});Authentication
Get your API key from https://app.sajn.se/settings/developer
const client = new sajnClient({
apiKey: 'YOUR_API_TOKEN',
baseUrl: 'https://app.sajn.se/api/v1', // Optional: defaults to production
uploadUrl: 'https://upload.sajn.se/v1', // Optional: defaults to production
});API Reference
Documents
// List documents
const documentsList = await client.documents.list({
page: 1,
perPage: 10,
});
console.log(`Total pages: ${documentsList.totalPages}`);
console.log('Documents:', documentsList.documents);
// Get a document
const document = await client.documents.get('doc_id');
// Create a document
const newDocument = await client.documents.create({
name: 'Contract',
type: 'BLANK',
expiresAt: '2025-12-31T23:59:59Z',
signers: [
{
name: 'Jane Doe',
email: '[email protected]',
role: 'SIGNER',
signingOrder: 1,
},
],
});
console.log('Document ID:', newDocument.documentId);
console.log('Signing URLs:', newDocument.signers);
// Update a document
await client.documents.update('doc_id', {
name: 'Updated Contract Name',
documentMeta: {
subject: 'Please sign this contract',
message: 'This is an important contract',
},
});
// Send for signing (REQUIRED: deliveryMethod)
await client.documents.send('doc_id', {
deliveryMethod: 'EMAIL', // EMAIL, SMS, or NONE
signatureType: 'DRAWING', // DRAWING, BANKID, SMS, or TYPED
customMessage: 'Please review and sign',
});
// Download signed document
const download = await client.documents.download('doc_id', {
downloadOriginalDocument: false, // false = signed PDF, true = original
});
console.log('Download URL:', download.downloadUrl);
// Delete a document
await client.documents.delete('doc_id');Signers
Important: Signers require a contactId. You must create a contact first, then use the contact's ID to create a signer.
// Create a contact first
const contact = await client.contacts.create({
firstName: 'John',
lastName: 'Smith',
email: '[email protected]',
});
// Add the contact as a signer to a document
const signer = await client.documents.createSigner('doc_id', {
contactId: contact.id, // REQUIRED
role: 'SIGNER', // SIGNER, ORGANIZER, or REVIEWER
signingOrder: 2,
});
// Update a signer
await client.documents.updateSigner('doc_id', 'signer_id', {
name: 'John A. Smith',
signingOrder: 1,
phone: '+46701234567',
});
// Remove a signer
await client.documents.deleteSigner('doc_id', 'signer_id');Fields
Note: Field CRUD operations are not included in the SDK as they require complex internal document structure knowledge (fieldMeta schemas) that are not suitable for external API usage. Document fields (signature fields, text fields, PDF pages, etc.) are managed through the sajn web interface.
Contacts
// List contacts
const contactsList = await client.contacts.list({
page: 1,
perPage: 10,
});
console.log(`Total pages: ${contactsList.totalPages}`);
console.log('Contacts:', contactsList.contacts);
// Get a contact
const contact = await client.contacts.get('contact_id');
// Create a contact
const newContact = await client.contacts.create({
firstName: 'John',
lastName: 'Doe',
email: '[email protected]',
phone: '+46701234567',
ssn: '19900101-1234', // Optional
companyId: 'company_id', // Optional
companyRole: 'CEO', // Optional
});
// Update a contact
await client.contacts.update('contact_id', {
phone: '+46709876543',
companyRole: 'CTO',
});
// Delete a contact
await client.contacts.delete('contact_id');Companies
// List companies
const companies = await client.companies.list();
// Get a company
const company = await client.companies.get('company_id');
// Create a company
const newCompany = await client.companies.create({
name: 'Acme Corp',
orgNumber: '556677-8899',
country: 'SE',
});Tags
// List tags
const tagsList = await client.tags.list({ page: 1, perPage: 10 });
console.log(`Total pages: ${tagsList.totalPages}`);
console.log('Tags:', tagsList.tags);
// Create a tag
const tag = await client.tags.create({
name: 'Urgent',
color: '#FF0000',
availableFor: ['DOCUMENT', 'TEMPLATE'], // DOCUMENT, TEMPLATE, or CONTACT
});
// Update a tag
await client.tags.update('tag_id', {
name: 'High Priority',
availableFor: ['DOCUMENT', 'TEMPLATE', 'CONTACT'],
});
// Add tag to document
await client.tags.addToDocument('doc_id', {
tagId: 'tag_id',
});
// Remove tag from document
await client.tags.removeFromDocument('doc_id', 'tag_id');Custom Fields
// List custom fields
const customFieldsList = await client.customFields.list({
page: 1,
perPage: 10,
type: 'DOCUMENT', // Filter by DOCUMENT or CONTACT
});
console.log(`Total pages: ${customFieldsList.totalPages}`);
console.log('Custom fields:', customFieldsList.customFields);
// Create a custom field
const field = await client.customFields.create({
name: 'Department',
type: 'DOCUMENT', // DOCUMENT or CONTACT
inputType: 'SELECT', // TEXT, TEXTAREA, NUMBER, DATE, SELECT, CHECKBOX, RADIO
required: true,
options: JSON.stringify(['Sales', 'Marketing', 'Engineering']),
});
// Update a custom field
await client.customFields.update('field_id', {
options: JSON.stringify(['Sales', 'Marketing', 'Engineering', 'Support']),
});
// Delete a custom field
await client.customFields.delete('field_id');File Uploads
import { readFileSync } from 'fs';
// Upload a file
const fileBuffer = readFileSync('./contract.pdf');
const uploadResult = await client.uploads.uploadFile(fileBuffer, 'contract.pdf');
console.log(uploadResult.key); // Use this key when creating documents
console.log(uploadResult.file.id);Webhooks
The SDK includes TypeScript types for webhook events:
import type { WebhookRequest, WebhookEvent } from '@sajn/sdk';
// Example Express.js webhook handler
app.post('/webhook', (req, res) => {
const sajnSecret = req.headers['x-sajn-secret'];
if (sajnSecret !== process.env.WEBHOOK_SECRET) {
return res.status(401).json({ error: 'Unauthorized' });
}
const webhook: WebhookRequest = req.body;
switch (webhook.event) {
case 'DOCUMENT_CREATED':
// Handle document creation
break;
case 'DOCUMENT_SENT':
// Handle document sent
break;
case 'DOCUMENT_SIGNED':
// Handle document signed
break;
case 'DOCUMENT_COMPLETED':
// Handle document completed
break;
case 'DOCUMENT_REJECTED':
// Handle document rejected
break;
}
res.status(200).json({ success: true });
});Available Webhook Events
DOCUMENT_CREATED- Document was createdDOCUMENT_SENT- Document was sent for signingDOCUMENT_OPENED- Document was opened by a signerDOCUMENT_SIGNED- Document was signed by a signerDOCUMENT_COMPLETED- All signers have signed the documentDOCUMENT_REJECTED- Document was rejected by a signer
Error Handling
The SDK throws typed errors for different HTTP status codes:
import {
sajnError,
sajnAPIError,
sajnAuthenticationError,
sajnNotFoundError,
sajnValidationError,
} from '@sajn/sdk';
try {
await client.documents.get('invalid_id');
} catch (error) {
if (error instanceof sajnAuthenticationError) {
console.error('Invalid API key');
} else if (error instanceof sajnNotFoundError) {
console.error('Document not found');
} else if (error instanceof sajnValidationError) {
console.error('Validation error:', error.body);
} else if (error instanceof sajnAPIError) {
console.error(`API error ${error.status}:`, error.statusText);
}
}TypeScript Support
The SDK is written in TypeScript and includes comprehensive type definitions:
import type {
Document,
DocumentType,
DocumentStatus,
Signer,
SignerRole,
SignatureType,
Contact,
Company,
Tag,
CustomField,
} from '@sajn/sdk';Examples
See the examples directory for more usage examples:
- basic-usage.ts - Basic document creation and sending
- upload-document.ts - File upload example
- manage-contacts.ts - Contact management
- webhook-handling.ts - Webhook handling
- tags-and-custom-fields.ts - Tags and custom fields
Requirements
- Node.js 20 or higher
- TypeScript 5.x (if using TypeScript)
Development
# Install dependencies
npm install
# Build the SDK
npm run build
# Run type checking
npm run type-check
# Run tests
npm testLicense
MIT
Support
- Documentation: https://docs.sajn.se
- API Reference: https://app.sajn.se/api/v1/openapi
- Issues: GitHub Issues
