Totalum API SDK
Official TypeScript/JavaScript SDK for the Totalum API. This library provides a fully typed, modern interface to interact with all Totalum endpoints.
Installation
npm i totalum-api-sdk
Note: v3.0 requires Node.js 18+ (for native fetch support). If you're using an older Node.js version, you'll need to polyfill fetch or upgrade to Node.js 18+.
Usage of TotalumApiSdk
Totalum allows you to use the SDK to perform actions such as creating records, managing files, creating PDFs, sending emails, and more.
The SDK is a fully-typed wrapper around the Totalum REST API.
What happens if you are not programming in javascript?
If you are not programming in javascript, you can use the api directly, see TOTALUM API DOCUMENTATION
Authentication
Note: If you use totalumSdk inside a totalum plugin, you don't need to authenticate, you can start using totalum like this: modules.totalumSdk.your.function();-> example: modules.totalumSdk.crud.query('your_table')
You can choose to use one of the two authentication methods offered by Totalum Sdk:
-
Token: You can use an access token to authenticate. This token can be obtained from the localStorage of your browser from the web https://web.totalum.app
-
ApiKey: (RECOMMENDED OPTION) You can use an ApiKey to authenticate. This ApiKey can be obtained in the Api Keys section of the Configuration section of Totalum.
ES Module Import:
import {AuthOptions, TotalumApiSdk} from 'totalum-api-sdk';
const options: AuthOptions = {
token:{
accessToken: 'YOUR TOKEN'
}
}
const options: AuthOptions = {
apiKey:{
'api-key': 'your_api_key',
}
}
const totalumClient = new TotalumApiSdk(options);
const result = await totalumClient.crud.query('your_table_name');
CommonJS Require:
const totalum = require('totalum-api-sdk');
const options = {
token:{
accessToken: 'YOUR TOKEN'
}
}
const options = {
apiKey:{
'api-key': 'your_api_key',
}
}
const totalumClient = new totalum.TotalumApiSdk(options);
const result = await totalumClient.crud.query('your_table_name');
HTML script import: (Use this way if you are using standalone html, and you cannot import npm packages)
<head>
<script src="https://cdn.jsdelivr.net/npm/totalum-api-sdk@3.0.7/dist/totalum-sdk.min.js"></script>
</head>
<script>
const token=localStorage.getItem('token');
var totalumClient = new totalumSdk.TotalumApiSdk({
token:{
accessToken: token
}
});
const tableName = 'your-table-name';
totalumClient.crud.query(tableName).then((result) => {
if (result.errors) {
console.error("ERROR:", result.errors);
return;
}
const records = result.data;
console.log("THE RECORDS", records);
});
</script>
Response Structure
All SDK methods return a TotalumApiResponse<T> object with the following structure:
interface TotalumApiResponse<T> {
data?: T;
errors?: ErrorResult;
}
interface ErrorResult {
errorCode: string;
errorMessage: string;
hasManyErrors?: boolean;
multipleErrors?: Array<{ errorCode: string; errorMessage: string }>;
}
Example:
const result = await totalumClient.crud.getRecordById('users', 'user-id-123');
if (result.errors) {
console.error('Error:', result.errors.errorMessage);
console.error('Error Code:', result.errors.errorCode);
return;
}
const user = result.data;
console.log('User:', user);
Error Handling
The SDK provides a TotalumError class for structured error handling:
import { TotalumError } from 'totalum-api-sdk';
const result = await totalumClient.crud.getRecordById('users', 'invalid-id');
if (result.errors) {
const error = new TotalumError(result.errors);
console.error('Error Code:', error.errorCode);
console.error('Error Message:', error.errorMessage);
if (error.hasManyErrors && error.multipleErrors) {
error.multipleErrors.forEach(err => {
console.error(`- ${err.errorCode}: ${err.errorMessage}`);
});
}
}
Functions for create, read, filter, update, delete. (CRUD)
Get record by id
const tableName = 'users';
const recordId = 'record-id-123';
const result = await totalumClient.crud.getRecordById(tableName, recordId);
if (result.errors) {
console.error('Error:', result.errors.errorMessage);
return;
}
const record = result.data;
console.log('Record:', record);
Query records (Recommended)
totalumClient.crud.query() is the recommended method for reading data. It replaces getRecords, getNestedData, and getManyToManyReferencesRecords.
const result = await totalumClient.crud.query('users');
if (result.errors) {
console.error('Error:', result.errors.errorMessage);
return;
}
const records = result.data;
console.log('Records:', records);
Query with nested relations
const result = await totalumClient.crud.query('client', {
order: {
product: true
}
});
const clients = result.data;
Query with filters, sort, and pagination
const result = await totalumClient.crud.query('client', {
_filter: { name: 'John' },
_sort: { name: 'asc' },
_limit: 10
});
Query with OR conditions
const result = await totalumClient.crud.query('users', {
_filter: {
_or: [
{ role: 'admin' },
{ role: 'moderator' }
]
}
});
Query with nested filters and counts
const result = await totalumClient.crud.query('company', {
_filter: { country: 'Spain' },
_sort: { name: 'asc' },
_limit: 10,
employee: {
_filter: { status: 'active' },
_has: true,
_count: true,
task: { _sort: { createdAt: 'desc' }, _limit: 5 }
}
});
Query manyToMany relations
const result = await totalumClient.crud.query('students', {
courses: true
});
For full query documentation see: Read and Filter Data
Delete record by id
const tableName = 'users';
const recordId = 'record-id-123';
const result = await totalumClient.crud.deleteRecordById(tableName, recordId);
if (result.errors) {
console.error('Error:', result.errors.errorMessage);
return;
}
console.log('Deleted count:', result.data.deletedCount);
console.log('Acknowledged:', result.data.acknowledged);
Edit record by id
const tableName = 'users';
const recordId = 'record-id-123';
const updates = {
name: 'John Doe',
email: 'john@example.com',
age: 30
};
const result = await totalumClient.crud.editRecordById(tableName, recordId, updates);
if (result.errors) {
console.error('Error:', result.errors.errorMessage);
return;
}
const updatedRecord = result.data;
console.log('Updated record:', updatedRecord);
console.log('New name:', updatedRecord.name);
console.log('New email:', updatedRecord.email);
Create record
const tableName = 'users';
const newRecord = {
name: 'Jane Doe',
email: 'jane@example.com',
age: 25
};
const result = await totalumClient.crud.createRecord(tableName, newRecord);
if (result.errors) {
console.error('Error:', result.errors.errorMessage);
return;
}
const createdRecord = result.data;
console.log('Created record:', createdRecord);
console.log('Record ID:', createdRecord._id);
console.log('Name:', createdRecord.name);
Add many-to-many reference (add a reference to another record with a many-to-many relationship)
const tableName = 'students';
const recordId = 'student-id-123';
const propertyName = 'courses';
const referenceId = 'course-id-456';
const result = await totalumClient.crud.addManyToManyReferenceRecord(tableName, recordId, propertyName, referenceId);
if (result.errors) {
console.error('Error:', result.errors.errorMessage);
return;
}
console.log('Reference added successfully');
Drop many-to-many reference (remove a reference from a many-to-many relationship)
const tableName = 'students';
const recordId = 'student-id-123';
const propertyName = 'courses';
const referenceId = 'course-id-456';
const result = await totalumClient.crud.dropManyToManyReferenceRecord(tableName, recordId, propertyName, referenceId);
if (result.errors) {
console.error('Error:', result.errors.errorMessage);
return;
}
console.log('Reference removed successfully');
Get many-to-many references
Note: For reading manyToMany data, prefer using totalumClient.crud.query() with the relation property expanded (see "Query manyToMany relations" above).
Functions for filter data
Note: All filtering examples below use totalumClient.crud.query(), the recommended method. See "Query records" section above for more details.
Filter data using AND filter
const result = await totalumClient.crud.query('users', {
_filter: {
name: 'John',
email: { regex: '@example.com', options: 'i' },
age: { gte: 18, lte: 65 },
createdAt: { gte: new Date('2024-01-01'), lte: new Date('2024-12-31') }
},
_sort: { name: 'asc' },
_limit: 50
});
if (result.errors) {
console.error('Error:', result.errors.errorMessage);
return;
}
const records = result.data;
console.log('Filtered records:', records);
Filter data using OR filter
const result = await totalumClient.crud.query('users', {
_filter: {
_or: [
{ name: 'John' },
{ email: { regex: '@example.com', options: 'i' } },
{ age: { gte: 18 } }
]
},
_sort: { name: 'asc' },
_limit: 50
});
if (result.errors) {
console.error('Error:', result.errors.errorMessage);
return;
}
const records = result.data;
console.log('Filtered records:', records);
Filter data using AND and OR combined
const result = await totalumClient.crud.query('users', {
_filter: {
_or: [
{ role: 'admin' },
{ role: 'moderator' }
],
status: 'active'
},
_sort: { name: 'asc' },
_limit: 50
});
if (result.errors) {
console.error('Error:', result.errors.errorMessage);
return;
}
const records = result.data;
console.log('Filtered records:', records);
Filter using custom MongoDB aggregation query
const tableName = 'users';
const customMongoDbAggregationQueryInString = `
Your custom MongoDB aggregation query in string format
For more info: https://docs.mongodb.com/manual/aggregation/
`;
const result = await totalumClient.filter.runCustomMongoAggregationQuery(tableName, customMongoDbAggregationQueryInString);
if (result.errors) {
console.error('Error:', result.errors.errorMessage);
return;
}
const results = result.data;
Get historic updates of a record
const recordId = 'record-id-123';
const result = await totalumClient.crud.getHistoricRecordUpdatesById(recordId);
if (result.errors) {
console.error('Error:', result.errors.errorMessage);
return;
}
const historicUpdates = result.data;
console.log('Historic updates:', historicUpdates);
Functions for create download and manipulate files
Upload a file to Totalum (you can upload any file type)
1. Upload the file to Totalum
To scan a document, first you need to upload the file to Totalum. You can do this using the Totalum API directly or using the Totalum SDK.
1.1 Transform the file to a blob
If you are not using javascript, you will need to do this step using the language you are using. Search
on internet how to transform a file to a blob in your language. Or also you can ask chatgpt to transform the following examples to your language.
Depending on the platform you are using, you will need to transform the file to a blob. Here are some examples:
From a file input (Frontend)
const fileInput = document.getElementById('fileInput');
const fileBlob = fileInput.files[0];
From a file in storage (Backend)
const fs = require('fs');
const yourFilePath = 'your_file_path';
const fileBlob = fs.readFileSync(yourFilePath);
From a remote file (Backend)
const response = await axios.get('your_file_url', { responseType: 'stream' });
const fileBlob = response.data;
From a base64 string (Frontend/Backend)
const binaryStr = atob(base64String);
const len = binaryStr.length;
const bytes = new Uint8Array(len);
for (let i = 0; i < len; i++) {
bytes[i] = binaryStr.charCodeAt(i);
}
let fileBlob;
if (typeof process === 'object' && process.version) {
const buffer = Buffer.from(bytes.buffer);
fileBlob = buffer;
} else {
const blob = new Blob([bytes], { type: fileType });
fileBlob = blob;
}
1.2 Upload the file to Totalum
Using Totalum SDK
const FormData = require('form-data');
const fileName = 'your_file_name.png';
const file = yourFileBlob
const formData = new FormData();
formData.append('file', file, fileName);
const result = await totalumClient.files.uploadFile(formData);
if (result.errors) {
console.error('Error:', result.errors.errorMessage);
return;
}
const fileNameId = result.data;
Using Totalum API
const FormData = require('form-data');
const fileName = 'your_file_name.png';
const file = yourFileBlob
const formData = new FormData();
formData.append('file', file, fileName);
const result = await axios.post('https://api.totalum.app/files/upload', formData, {
headers: {
'Content-Type': 'multipart/form-data',
'api-key': 'your api key here',
}
});
const fileNameId = result.data;
const tableName = 'documents';
const recordId = 'record-id-123';
const result2 = await totalumClient.crud.editRecordById(tableName, recordId, {
'attachmentFile': { name: fileNameId }
});
if (result2.errors) {
console.error('Error:', result2.errors.errorMessage);
return;
}
console.log('File linked to record successfully');
Remove a file from Totalum
const fileNameId = 'your_file_name.png';
const result = await totalumClient.files.deleteFile(fileNameId);
if (result.errors) {
console.error('Error:', result.errors.errorMessage);
return;
}
console.log('File deleted successfully');
Get the download URL of a file
const fileNameId = 'your_file_name.png';
const options = {
expirationTime: Date.now() + (128 * 60 * 60 * 1000)
};
const result = await totalumClient.files.getDownloadUrl(fileNameId, options);
if (result.errors) {
console.error('Error:', result.errors.errorMessage);
return;
}
const fileUrl = result.data[0];
console.log('Download URL:', fileUrl);
Generate a PDF from a template
const templateId = 'template-id-123';
const variables = {
'customerName': 'John Doe',
'orderDetails': {
'orderId': 'ORD-12345',
'amount': 150.50,
'date': new Date(),
},
};
const fileName = 'invoice_12345.pdf';
const result = await totalumClient.files.generatePdfByTemplate(templateId, variables, fileName);
if (result.errors) {
console.error('Error:', result.errors.errorMessage);
return;
}
const generatedFileName = result.data;
console.log('PDF generated:', generatedFileName);
const tableName = 'invoices';
const recordId = 'invoice-record-123';
const result2 = await totalumClient.crud.editRecordById(tableName, recordId, {
'pdfFile': { name: generatedFileName }
});
const fileNameId = 'uploaded_image.png';
const result = await totalumClient.files.ocrOfImage(fileNameId);
if (result.errors) {
console.error('Error:', result.errors.errorMessage);
return;
}
const ocrResult = result.data;
console.log('Extracted text:', ocrResult.text);
console.log('Full details:', ocrResult.fullDetails);
const fileNameId = 'uploaded_document.pdf';
const result = await totalumClient.files.ocrOfPdf(fileNameId);
if (result.errors) {
console.error('Error:', result.errors.errorMessage);
return;
}
const ocrResult = result.data;
console.log('Extracted text:', ocrResult.text);
console.log('Full details:', ocrResult.fullDetails);
const fileName = 'invoice.png';
const file = yourFileBlob;
const formData = new FormData();
formData.append('file', file, fileName);
const uploadResult = await totalumClient.files.uploadFile(formData);
if (uploadResult.errors) {
console.error('Error:', uploadResult.errors.errorMessage);
return;
}
const fileNameId = uploadResult.data;
const result = await totalumClient.files.scanInvoice(fileNameId);
if (result.errors) {
console.error('Error:', result.errors.errorMessage);
return;
}
const invoiceData = result.data;
const metadata = result.data.metadata;
console.log('Invoice data:', invoiceData);
console.log('Total amount:', invoiceData.totalAmountIncludingTaxes);
console.log('Invoice number:', invoiceData.complete_invoice_number);
console.log('Usage units:', metadata.usageUnits);
const fileName = 'document.png';
const file = yourFileBlob;
const formData = new FormData();
formData.append('file', file, fileName);
const uploadResult = await totalumClient.files.uploadFile(formData);
if (uploadResult.errors) {
console.error('Error:', uploadResult.errors.errorMessage);
return;
}
const fileNameId = uploadResult.data;
const properties = {
"fecha": {
"type": "string",
"format": "date",
"description": "The date of the document"
},
"import": {
"type": "number",
"description": "The total amount"
},
"currency": {
"type": "string",
"enum": ["EUR", "USD", "GBP", "OTHER"],
"description": "Currency code"
}
};
const result = await totalumClient.files.scanDocument(fileNameId, properties);
if (result.errors) {
console.error('Error:', result.errors.errorMessage);
return;
}
const documentData = result.data;
const metadata = result.data.metadata;
console.log('Extracted data:', documentData);
console.log('OCR text:', metadata.ocrFullResultText);
console.log('Usage units:', metadata.usageUnits);
Create PDF from HTML
Create a PDF directly from custom HTML:
const htmlContent = `
<html>
<body>
<h1>Hello World</h1>
<p>This is a PDF created from HTML</p>
</body>
</html>
`;
const fileName = 'my-generated-pdf.pdf';
const result = await totalumClient.files.createPdfFromHtml({
html: htmlContent,
name: fileName
});
if (result.errors) {
console.error('Error:', result.errors.errorMessage);
return;
}
const generatedFileName = result.data;
console.log('PDF generated:', generatedFileName);
const tableName = 'documents';
const recordId = 'doc-record-123';
const result2 = await totalumClient.crud.editRecordById(tableName, recordId, {
'pdfFile': { name: generatedFileName }
});
Note: The HTML is automatically encoded to base64 by the SDK before sending it to the API. Works in both Node.js and browser environments.
Functions for send emails
Send a basic email
const emailPayload = {
to: ['recipient@example.com'],
subject: 'Your email subject',
html: '<h1>Hello</h1><p>This is the email content in HTML</p>',
};
const result = await totalumClient.email.sendEmail(emailPayload);
if (result.errors) {
console.error('Error:', result.errors.errorMessage);
return;
}
console.log('Email sent successfully');
console.log('Message ID:', result.data.messageId);
Send an email with all options
const emailPayload = {
to: ['recipient1@example.com', 'recipient2@example.com'],
subject: 'Your email subject',
html: '<h1>Hello</h1><p>This is the email content in HTML</p>',
fromName: 'Your Company Name',
cc: ['cc@example.com'],
bcc: ['bcc@example.com'],
replyTo: 'reply@example.com',
attachments: [
{
filename: 'document.pdf',
url: 'https://example.com/path/to/document.pdf',
contentType: 'application/pdf'
},
{
filename: 'image.png',
url: 'https://example.com/path/to/image.png',
contentType: 'image/png'
}
]
};
const result = await totalumClient.email.sendEmail(emailPayload);
if (result.errors) {
console.error('Error:', result.errors.errorMessage);
return;
}
console.log('Email sent successfully');
console.log('Message ID:', result.data.messageId);
Send an email with files from Totalum storage
const fileNameId = 'your_file_name.pdf';
const fileUrlResult = await totalumClient.files.getDownloadUrl(fileNameId);
if (fileUrlResult.errors) {
console.error('Error:', fileUrlResult.errors.errorMessage);
return;
}
const fileUrl = fileUrlResult.data;
const emailPayload = {
to: ['recipient@example.com'],
subject: 'Email with attachment from Totalum',
html: '<h1>Hello</h1><p>Please find the attached document</p>',
attachments: [
{
filename: 'document.pdf',
url: fileUrl,
contentType: 'application/pdf'
}
]
};
const result = await totalumClient.email.sendEmail(emailPayload);
if (result.errors) {
console.error('Error:', result.errors.errorMessage);
return;
}
console.log('Email sent successfully');
Important notes:
- Maximum attachments: 10 per email
- Maximum size per attachment: 15MB
- All attachments must be provided as valid HTTP/HTTPS URLs
- The SDK validates attachments before sending
Functions for call OpenAI API without need to have an OpenAI account
Create a completion (deprecated, use createChatCompletion instead)
const body = {
model: 'gpt-3.5-turbo-instruct',
prompt: 'Say hello in Spanish',
max_tokens: 50
};
const result = await totalumClient.openai.createCompletion(body);
if (result.errors) {
console.error('Error:', result.errors.errorMessage);
return;
}
const completion = result.data;
console.log('Completion:', completion);
Create a chat completion
const body = {
messages: [
{ content: 'You are a math specialist assistant', role: 'system' },
{ content: 'How do I solve a matrix?', role: 'user' }
],
model: 'gpt-3.5-turbo',
max_tokens: 150,
};
const result = await totalumClient.openai.createChatCompletion(body);
if (result.errors) {
console.error('Error:', result.errors.errorMessage);
return;
}
const chatCompletion = result.data;
console.log('Response:', chatCompletion.choices[0].message.content);
console.log('Tokens used:', chatCompletion.usage.total_tokens);
Generate an image
const result = await totalumClient.openai.generateImage({
prompt: 'A beautiful sunset over the mountains',
fileName: 'sunset_image',
size: '1024x1024',
quality: 'low',
output_format: 'png',
background: 'auto'
});
if (result.errors) {
console.error('Error:', result.errors.errorMessage);
return;
}
const { fileName, imageUrl } = result.data;
console.log('Image file:', fileName);
console.log('Image URL:', imageUrl);
Edit an image
Edit or transform existing images: change clothes, combine images, use as style reference, etc.
const result = await totalumClient.openai.editImage({
prompt: 'Change ONLY the clothing to a blue suit. Keep the face and background the same.',
imageUrls: ['https://example.com/photo.jpg'],
fileName: 'edited-photo',
input_fidelity: 'high',
size: '1024x1024',
quality: 'low',
output_format: 'png'
});
if (result.errors) {
console.error('Error:', result.errors.errorMessage);
return;
}
const { fileName, imageUrl } = result.data;
console.log('Edited image:', fileName);
console.log('Image URL:', imageUrl);