# ./docs/api/instalacion.md --- title: Installation of Totalum SDK sidebar_position: 1 --- # Introduction The package name is `totalum-api-sdk`. Use the Totalum API SDK to query, filter, modify, create, and delete Totalum data without limits. You can also use the API SDK to generate PDFs, perform OCR on images or PDFs, access ChatGPT, and more. # Ways to Use the API SDK ## Using the totalumSdk for JavaScript This is the easiest way to use the API, as it is an npm package with TypeScript that provides autocomplete for methods and offers a simpler interface for interacting with the API. ## Using the API Directly If you do not want or cannot use the SDK, you can use the Totalum REST API directly. ACCESS THE TOTALUM API DOCUMENTATION --- # Installation Totalum SDK is an npm package, compatible with nodejs and browsers. https://www.npmjs.com/package/totalum-api-sdk ```bash npm i totalum-api-sdk ``` If you are using Totalum from a custom HTML and cannot import it with npm, use the following script: ```html ``` Warning: We only recommend using TotalumSdk from the frontend in a custom HTML page within Totalum, or from a Totalum plugin or event. In all other cases, we recommend using the SDK from your own backend. If you use TotalumSdk from your own frontend that is open to the public, anyone could see your authentication token or apiKey, and could use it intentionally. --- # 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: ```typescript import {AuthOptions, TotalumApiSdk} from 'totalum-api-sdk'; // CHOICE FROM USE accessToken OR apiKey (API KEY IS RECOMMENDED) // the auth using token const options: AuthOptions = { token:{ accessToken: 'YOUR TOKEN' // get it from totalum project web localStorage } } // the auth using api key const options: AuthOptions = { apiKey:{ 'api-key': 'your_api_key', //the api key secret that is shown only once, example: sk_23r23r23r... } } const totalumClient = new TotalumApiSdk(options); // execute some TotalumApiSdk function const result = await totalumClient.crud.query('your_table_name'); ``` ## CommonJS Require: ```javascript const totalum = require('totalum-api-sdk'); // CHOICE FROM USE accessToken OR apiKey (API KEY IS RECOMMENDED) // the auth using token const options = { token:{ accessToken: 'YOUR TOKEN' // get it from totalum project web localStorage } } // the auth using api key const options = { apiKey:{ 'api-key': 'your_api_key', //the api key secret that is shown only once, example: sk_23r23r23r... } } const totalumClient = new totalum.TotalumApiSdk(options); // execute some TotalumApiSdk function 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 ```html
``` --- # ./docs/api/uso-de-la-api.md --- id: api title: Open API Documentation sidebar_position: 2 --- #### Warning: If your environment is JavaScript or Node.js, we recommend using the TotalumSdk npm package to simplify working with the Sdk API. Access to the Totalum HTTP REST API Documentation --- # ./docs/api/crearDatos.md --- title: Create Data sidebar_position: 5 --- # Create Data --- **📚 Setup Required:** For installation and usage of the Totalum SDK or API, see the [Installation Guide](/docs/api/instalacion). --- ### create item **Use Case:** Create an for from your element table. ```javascript // create item from your_element_table_name, you need to pass at least the required properties const tableElementName = 'your_element_table_name'; // replace 'your_element_table_name' with the name of your element table const result = await totalumClient.crud.createRecord(tableElementName, {your_item_property: 'new value'}); ``` **Example:** Imagine you have a table called `client` with the following properties: - `name` (text) - `email` (text) - `phone` (text) - `birthday` (date) And you want to create a new client with name `John Doe`, the email `jhon@gmail.com`, the phone `+34 123 456 789`, and the birthday `1990-01-01`. ```javascript const tableElementName = 'client'; const clientToCreate = { name: 'John Doe', email: 'jhon@gmail.com', phone: '+34 123 456 789', birthday: new Date('1990-01-01') }; const result = await totalumClient.crud.createRecord(tableElementName, clientToCreate); // The response contains the full created record const createdClient = result.data; const insertedId = createdClient._id; // this is the id of the client you just created console.log('Created client:', createdClient); ``` Note: If you want to create a field that is a type options, and select multiple options is enabled, you must put the options separated by commas, like this: ```javascript const result = await totalumClient.crud.createRecord('client', {optionsField: 'option1, option2, option3'}); ``` ### create item and add reference to another item (One to Many reference) **Use Case:** THIS IS ONLY FOR ONE TO MANY OR MANY TO ONE REFERENCES, IF YOU WANT TO CREATE A MANY TO MANY REFERENCE, SEE THE NEXT SECTION. Imagine you have a table called `client` and other called `order` that are referenced in a one to many relationship, (one client can have many orders). `client` table properties: - `name` (text) - `email` (text) - `phone` (text) - `birthday` (date) `order` table properties: - `summary` (text) - `date` (date) - `import` (number) - `client` (reference to client table) As is a one to many relationship, this tables are linked by a reference in the `order` table. So you see a property called `client` in the `order` table that is a reference to the `client` table. So, If you want to create a new `order` and link it to a `client` you can do it like this: ```javascript let clientIdToAddInOrder = '5f9b2b1b9c6f6b0001a3b2b1'; const orderToCreate = { summary: 'my order summary', date: new Date(), import: 1000, client: clientIdToAddInOrder // this is the reference to the client }; const result = await totalumClient.crud.createRecord('order', orderToCreate); // The response contains the full created record const createdOrder = result.data; const insertedId = createdOrder._id; // this is the id of the order you just created ``` ### create item and add reference to another item (Many to Many reference) **Use Case:** THIS IS ONLY FOR MANY TO MANY REFERENCES, IF YOU WANT TO CREATE A ONE TO MANY OR MANY TO ONE REFERENCE, SEE THE PREVIOUS SECTION. Imagine you have a table called `client` and other called `product` that are referenced in a many to many relationship, (one client can have many orders, and one order can have many clients). `client` table properties: - `name` (text) - `email` (text) - `phone` (text) - `birthday` (date) `product` table properties: - `summary` (text) - `date` (date) - `import` (number) As is a many to many relationship, this tables are linked by a a third join table. So you don't see id reference in the `client` or `product` tables. So if you want to create a new `client` and link it to a `product` you can do it like this: ```javascript const productToCreate = { summary: 'my product summary', date: new Date(), import: 1000 }; const result = await totalumClient.crud.createRecord('product', productToCreate); // The response contains the full created record const createdProduct = result.data; const productId = createdProduct._id; // this is the id of the product you just created const clientIdToAddInProduct = '5f9b2b1b9c6f6b0001a3b2b1'; // this is just an example const propertyName = 'client'; // this is the name of the property in the product table that is a reference to the client table const result2 = await totalumClient.crud.addManyToManyReferenceRecord('product', productId, propertyName, clientIdToAddInProduct); ``` If you want to see more many to many relation examples, see the edit data section. --- # ./docs/api/editarDatos.md --- title: Edit Data sidebar_position: 4 --- # Edit Data --- **📚 Setup Required:** For installation and usage of the Totalum SDK or API, see the [Installation Guide](/docs/api/instalacion). --- ### edit item by id **Use Case:** Edit an item by id from your element table. ```javascript // edit item by id from your_element_table_name, you can edit 1 or multiple properties at the same time (like a patch) const tableElementName = 'your_element_table_name'; // replace 'your_element_table_name' with the name of your element table let your_item_id = 'your_item_id'; // replace 'your_item_id' with the id of the item object const result = await totalumClient.crud.editRecordById(tableElementName, your_item_id, {your_item_property: 'new value'}); ``` **Example:** Imagine you have a table called `client` with the following properties: - `name` (text) - `email` (text) - `phone` (text) - `birthday` (date) And you want to edit the client with id `5f9b2b1b9c6f6b0001a3b2b1` and change the name to `John Doe`, the phone to `+34 123 456 789`, and the birthday to `1990-01-01`. ```javascript const tableElementName = 'client'; let your_item_id = '5f9b2b1b9c6f6b0001a3b2b1'; const result = await totalumClient.crud.editRecordById(tableElementName, your_item_id, {name: 'John Doe', phone: '+34 123 456 789', birthday: new Date('1990-01-01')}); // The response contains the full updated record const updatedClient = result.data; console.log('Updated client:', updatedClient); ``` Note: If you want to edit a field that is a type options, and select multiple options is enabled, you must put the options separated by commas, like this: ```javascript const result = await totalumClient.crud.editRecordById('client', your_item_id, {optionsField: 'option1, option2, option3'}); ``` ### Add or edit an item reference to another item (add or edit reference) (One to Many reference) **Use Case:** THIS IS ONLY FOR ONE TO MANY OR MANY TO ONE REFERENCES, IF YOU WANT TO ADD OR EDIT A MANY TO MANY REFERENCE, SEE THE NEXT SECTION. Imagine you have a table called `client` and other called `order` that are referenced in a one to many relationship, (one client can have many orders). `client` table properties: - `name` (text) - `email` (text) - `phone` (text) - `birthday` (date) `order` table properties: - `summary` (text) - `date` (date) - `import` (number) - `client` (reference to client table) As is a one to many relationship, this tables are linked by a reference in the `order` table. So you see a property called `client` in the `order` table that is a reference to the `client` table. So, If you want to create a new `order` and link it to a `client` you can do it like this: ```javascript let clientIdToAddInOrder = '5f9b2b1b9c6f6b0001a3b2b1'; const orderToCreate = { summary: 'my order summary', date: new Date(), import: 1000, client: clientIdToAddInOrder // this is the reference to the client }; const result = await totalumClient.crud.createRecord('order', orderToCreate); ``` If you want to take an existing `order` and link it to a `client` you can do it like this: ```javascript let clientIdToAddInOrder = '5f9b2b1b9c6f6b0001a3b2b1'; let orderId = '5f9b2b1b9c6f6b0001a3b2b1'; const result = await totalumClient.crud.editRecordById('order', orderId, {client: clientIdToAddInOrder}); ``` If you want to remove the reference to a `client` from an `order` you can do it like this: ```javascript let orderId = '5f9b2b1b9c6f6b0001a3b2b1'; const result = await totalumClient.crud.editRecordById('order', orderId, {client: null}); // now this order has no client linked ``` ### Add or edit an item to another item (add or edit reference) (Many to Many reference) **Use Case:** THIS IS ONLY FOR MANY TO MANY REFERENCES, IF YOU WANT TO ADD OR EDIT A ONE TO MANY OR MANY TO ONE REFERENCE, SEE THE PREVIOUS SECTION. Imagine you have a table called `client` and other called `product` that are referenced in a many to many relationship, (one client can have many products, and one product can have many clients). `client` table properties: - `name` (text) - `email` (text) - `phone` (text) - `birthday` (date) `product` table properties: - `name` (text) - `price` (number) - `category` (options) As is a many to many relationship, this tables are linked by a a third join table. So you don't see id reference in the `client` or `product` tables. So, if you want to create a new `product` and link it to a `client` you can do it like this: ```javascript const productToCreate = { name: 'my product name', price: 1000, category: 'my category' }; const result = await totalumClient.crud.createRecord('product', productToCreate); // The response contains the full created record const createdProduct = result.data; const productId = createdProduct._id; const clientId = '5f9b2b1b9c6f6b0001a3b2b1'; const propertyName = 'products'; // this is the name of the property in the client table that references the product table const result = await totalumClient.crud.addManyToManyReferenceRecord('client', clientId, propertyName, productId); ``` If you want to take an existing `product` and link it to a `client` you can do it like this: ```javascript const clientId = '5f9b2b1b9c6f6b0001a3b2b1'; const productId = '5f9b2b1b9c6f6b0001a3b2b1'; const propertyName = 'products'; // this is the name of the property in the client table that references the product table const result = await totalumClient.crud.addManyToManyReferenceRecord('client', clientId, propertyName, productId); ``` If you want to remove the reference to a `product` from a `client` you can do it like this: ```javascript const clientId = '5f9b2b1b9c6f6b0001a3b2b1'; const productId = '5f9b2b1b9c6f6b0001a3b2b1'; const propertyName = 'products'; // this is the name of the property in the client table that references the product table const result = await totalumClient.crud.dropManyToManyReferenceRecord('client', clientId, propertyName, productId); ``` --- # ./docs/api/borrarDatos.md --- title: Delete Data sidebar_position: 6 --- # Delete Data --- **📚 Setup Required:** For installation and usage of the Totalum SDK or API, see the [Installation Guide](/docs/api/instalacion). --- # delete item by id **Use Case:** Delete an item by id from your element table. ```javascript // delete item by id from your_element_table_name const tableElementName = 'your_element_table_name'; // replace 'your_element_table_name' with the name of your element table let your_item_id = 'your_item_id'; // replace 'your_item_id' with the id of the item object const result = await totalumClient.crud.deleteRecordById(tableElementName, your_item_id); ``` **Example:** Imagine you have a table called `client` with multiple client items, and you want to delete the client with id `5f9b2b1b9c6f6b0001a3b2b1`. ```javascript let itemIdToDelete = '5f9b2b1b9c6f6b0001a3b2b1'; const result = await totalumClient.crud.deleteRecordById('client', itemIdToDelete); ``` # delete item reference to another item (One to Many reference) **Use Case:** THIS IS ONLY FOR ONE TO MANY OR MANY TO ONE REFERENCES, IF YOU WANT TO DELETE A MANY TO MANY REFERENCE, SEE THE NEXT SECTION. Imagine you have a table called `client` and other called `order` that are referenced in a one to many relationship, (one client can have many orders). You want to delete the reference of the client to the order with id `5f9b2b1b9c6f6b0001a3b2b2`. That means that you only want to delete the reference, the client and the order will not be deleted. ```javascript const tableElementName = 'order' let orderItemId = '5f9b2b1b9c6f6b0001a3b2b2'; const result = await totalumClient.crud.editRecordById(tableElementName, orderItemId, {client: null}); ``` # delete item reference to another item (Many to Many reference) **Use Case:** THIS IS ONLY FOR MANY TO MANY REFERENCES, IF YOU WANT TO DELETE A ONE TO MANY OR MANY TO ONE REFERENCE, SEE THE PREVIOUS SECTION. Imagine you have a table called `client` and other called `product` that are referenced in a many to many relationship, (one client can have many products, and one product can have many clients). You want to delete the reference of the client to the product with id `5f9b2b1b9c6f6b0001a3b2b2`. That means that you only want to delete the reference, the client and the product will not be deleted. ```javascript const tableElementName = 'client' let clientItemId = '5f9b2b1b9c6f6b0001a3b2b2'; const propertyName = 'products'; // this is the name of the property in the client table that is a reference to the product table const productId = '5f9b2b1b9c6f6b0001a3b2b2'; const result = await totalumClient.crud.dropManyToManyReferenceRecord(tableElementName, clientItemId, propertyName, productId); ``` --- # ./docs/api/filtrarDatos.md --- title: Read and Filter Data sidebar_position: 3 --- # Read and Filter Data --- **📚 Setup Required:** For installation and usage of the Totalum SDK or API, see the [Installation Guide](/docs/api/instalacion). --- ## Get item by id **Use Case:** Get only one item by id from your element table ```javascript // get item by id from your_element_table_name const tableElementName = 'your_element_table_name'; // replace 'your_element_table_name' with the name of your element table let your_item_id = 'your_item_id'; // replace 'your_item_id' with the id of the item object const result = await totalumClient.crud.getRecordById(tableElementName, your_item_id); const item = result.data; ``` **example:** Imagine you have a table named `client`, and this table has some items inside. You want to get a client by id, so you can do this: ```javascript const tableElementName = 'client'; let clientId = 'the_client_id'; // replace 'the_client_id' with the id of the item object const result = await totalumClient.crud.getRecordById(tableElementName, clientId); const client = result.data; ``` --- ## Query (Recommended) `totalumClient.crud.query()` is the **recommended** method for reading data. > **Note:** If you get an error like `query is not a function`, update the SDK: `npm install totalum-api-sdk@latest` > If you are using deprecated methods like `getRecords`, `getNestedData`, `getManyToManyReferencesRecords`, or `nestedFilter`, see the [Deprecated Get Methods](./deprecated-get-methods) page for migration guide. It supports: - **Nested relations** (oneToMany, manyToOne, manyToMany) at any depth - **Filtering** with exact match, comparison operators, regex, `_or`, `in`, `contains`, `startsWith`, `endsWith` - **Sorting**, **pagination** (`_limit`, `_offset`) - **Parent filtering by children** (`_has`) - **Child counts** (`_count`) - **Field selection** (`_select`, `_omit`) - **Aggregations** (`_aggregate`, `_groupBy`) --- ### Get items (simple) Get items from a table without any filters (default limit: 50 items). ```javascript const result = await totalumClient.crud.query('client'); const clients = result.data; ``` ### Get items with nested relations **Use Case:** Imagine you have 3 tables: `client`, `order` and `product`. You want to get clients with all their orders and each order's products. ```javascript const result = await totalumClient.crud.query('client', { order: { product: true } }); const clients = result.data; /* Result structure: [ { _id: 'client_id_1', name: 'Client 1', order: [ { _id: 'order_id_1', date: '2023-01-01', product: [ { _id: 'product_id_1', name: 'Product 1' }, { _id: 'product_id_2', name: 'Product 2' } ] }, ] }, // more clients... ] */ ``` **Important:** The property names in the query (`order`, `product`) must be the **property names** (field names) defined in your table, not the table names. You can use `true` as a shorthand for `{}` — both expand the relation with default settings. ### Get items with manyToOne relations **Use Case:** Imagine you have a `task` table with a `employee` field (manyToOne) and `employee` has a `company` field (manyToOne). You want to get tasks with the full employee and company data. ```javascript const result = await totalumClient.crud.query('task', { employee: { company: true } }); const tasks = result.data; /* Result structure (manyToOne returns a single object, not an array): [ { _id: 'task_id_1', title: 'Fix bug', employee: { _id: 'emp_id_1', name: 'Alice', company: { _id: 'company_id_1', name: 'Acme Corp' } } }, // more tasks... ] */ ``` ### Get items with manyToMany relations **Use Case:** Imagine `employee` has a manyToMany relation `project`. You want to get all employees with their projects. ```javascript const result = await totalumClient.crud.query('employee', { project: true }); const employees = result.data; /* [ { _id: 'emp_id_1', name: 'Alice', project: [ { _id: 'proj_id_1', name: 'Website Redesign' }, { _id: 'proj_id_2', name: 'Mobile App' } ] }, // more employees... ] */ ``` --- ### Filter items (exact match) ```javascript const result = await totalumClient.crud.query('client', { _filter: { name: 'John' } }); const clients = result.data; ``` ### Filter with comparison operators Supported operators: `gte` (>=), `lte` (<=), `ne` (!=), `in`, `nin`, `contains`, `startsWith`, `endsWith`, `regex`. ```javascript // Get clients older than 18 with birthday after 2000 const result = await totalumClient.crud.query('client', { _filter: { age: { gte: 18 }, birthday: { gte: new Date('2000-01-01') } } }); ``` ### Filter with OR conditions ```javascript // Get clients named 'John' OR aged 18+ const result = await totalumClient.crud.query('client', { _filter: { _or: [ { name: 'John' }, { age: { gte: 18 } } ] } }); ``` ### Filter with AND + OR combined ```javascript // Get clients (named 'John' OR aged 18+) AND address contains 'street' const result = await totalumClient.crud.query('client', { _filter: { _or: [ { name: 'John' }, { age: { gte: 18 } } ], address: { contains: 'street' } } }); ``` ### Filter with `in` operator ```javascript // Get clients with status 'active' or 'pending' const result = await totalumClient.crud.query('client', { _filter: { status: { in: ['active', 'pending'] } } }); ``` ### Filter with `regex` ```javascript // Get clients whose name contains 'john' (case insensitive) const result = await totalumClient.crud.query('client', { _filter: { name: { regex: 'john', options: 'i' } } }); ``` ### Filter with `contains`, `startsWith`, `endsWith` ```javascript // These are shortcuts for common regex patterns const result = await totalumClient.crud.query('client', { _filter: { name: { startsWith: 'Jo' }, // names starting with "Jo" email: { endsWith: '@gmail.com' }, // gmail emails address: { contains: 'street' } // address contains "street" } }); ``` --- ### Sort results ```javascript // Sort by name ascending const result = await totalumClient.crud.query('client', { _sort: { name: 'asc' } }); // Sort by age descending const result2 = await totalumClient.crud.query('client', { _sort: { age: 'desc' } }); // You can also use 1 (asc) and -1 (desc) const result3 = await totalumClient.crud.query('client', { _sort: { name: 1, age: -1 } }); ``` ### Pagination (limit and offset) ```javascript // Get first 10 clients const result = await totalumClient.crud.query('client', { _limit: 10 }); // Get clients 11-20 (skip first 10) const result2 = await totalumClient.crud.query('client', { _limit: 10, _offset: 10 }); ``` ### Limit children ```javascript // Get companies with only the first 5 employees const result = await totalumClient.crud.query('company', { employee: { _limit: 5, _sort: { name: 'asc' } } }); ``` --- ### Filter on children You can filter children and also use `_has` to filter parents based on their children. ```javascript // Get companies that have at least one active employee const result = await totalumClient.crud.query('company', { employee: { _filter: { status: 'active' }, _has: true // only return companies that have matching employees } }); ``` `_has` supports: `true` (same as `'some'`), `'some'`, `'none'`, `'every'`. ```javascript // Get companies with NO employees const result = await totalumClient.crud.query('company', { employee: { _has: 'none' } }); ``` ### Count children ```javascript // Get companies with the count of their employees const result = await totalumClient.crud.query('company', { employee: { _count: true } }); const companies = result.data; /* [ { _id: 'company_id_1', name: 'Acme Corp', employee: [ ... ], _count: { employee: 15 } } ] */ ``` ### Count total (root level) ```javascript // Get total count of matching records (useful for pagination) const result = await totalumClient.crud.query('client', { _filter: { status: 'active' }, _count: true, _limit: 10 }); const clients = result.data; // Each record will have: _count: { _total: 150 } // So you know there are 150 total active clients, but only 10 returned ``` --- ### Select specific fields ```javascript // Only return name and email fields const result = await totalumClient.crud.query('client', { _select: { name: true, email: true } }); // Result: [{ _id: '...', name: 'John', email: 'john@...' }] // Other fields like age, address, etc. are NOT returned ``` ### Omit specific fields ```javascript // Return all fields EXCEPT password and internal_notes const result = await totalumClient.crud.query('client', { _omit: { password: true, internal_notes: true } }); ``` **Note:** `_select` and `_omit` cannot be used together at the same level. --- ### Hide children from response (_include: false) Use `_include: false` when you want to use `_has` or `_count` on children but don't want the actual child records in the response. ```javascript // Get companies that have employees, with employee count, but don't include employee data const result = await totalumClient.crud.query('company', { employee: { _has: true, _count: true, _include: false // don't include employee array in response } }); // Result: [{ _id: '...', name: 'Acme', _count: { employee: 15 } }] // No 'employee' array in the response ``` --- ### Aggregations Aggregate data with `_sum`, `_avg`, `_min`, `_max`, `_count`. ```javascript // Get total and average amount of all invoices const result = await totalumClient.crud.query('invoice', { _aggregate: { _sum: { amount: true }, _avg: { amount: true }, _count: true } }); /* Result: [ { _aggregate: { _sum: { amount: 50000 }, _avg: { amount: 250 }, _count: 200 } } ] */ ``` ### Aggregations with groupBy ```javascript // Get total invoice amount grouped by status const result = await totalumClient.crud.query('invoice', { _filter: { date: { gte: new Date('2024-01-01') } }, _aggregate: { _sum: { amount: true }, _count: true }, _groupBy: 'status' }); /* Result: [ { _group: { status: 'paid' }, _aggregate: { _sum: { amount: 35000 }, _count: 150 } }, { _group: { status: 'pending' }, _aggregate: { _sum: { amount: 15000 }, _count: 50 } } ] */ ``` ### Child aggregations ```javascript // Get companies with total salary of their employees const result = await totalumClient.crud.query('company', { employee: { _aggregate: { _sum: { salary: true }, _avg: { salary: true } }, _include: false } }); /* Result: [ { _id: 'company_id_1', name: 'Acme Corp', _aggregate: { employee: { _sum: { salary: 500000 }, _avg: { salary: 50000 } } } } ] */ ``` --- ### Full example: combining multiple features ```javascript // Get companies in Spain with active employees, count tasks per employee, sort by name const result = await totalumClient.crud.query('company', { _filter: { country: 'Spain' }, _sort: { name: 'asc' }, _limit: 10, _count: true, employee: { _filter: { status: { in: ['active', 'probation'] } }, _has: true, _count: true, _sort: { name: 'asc' }, _limit: 20, task: { _sort: { createdAt: 'desc' }, _limit: 5 } } }); ``` --- ## Get the historic updates of a record by its ID. **Use Case:** You can get all changes that have been made to a record. ```javascript const result = await totalumClient.crud.getHistoricRecordUpdatesById(yourRecordId); // replace yourRecordId with the id of the record const updates = result.data; ``` --- ## Filter using your custom mongoDb aggregation query **Use Case:** If you need to do a super complex custom query that is not supported by the previous methods, you can use this method to do a custom mongoDb aggregation query. This method is very powerful, you can do any query you want, but you need to know how to write mongoDb aggregation queries. See the documentation of mongoDb aggregation queries here: https://docs.mongodb.com/manual/aggregation/. Aggregation queries are very powerful for do custom complex queries like joins, group by, union, etc. (the same power as sql queries) **Note:** In Totalum mongoDb Database the tables and items has the following structure: ```json "_id": 2342342342342, // here goes all the properties of the item with the custom names and values that you have defined "property_name": "value", "property_name2": "value2", "property_name2": "value2" //etc... "createdAt": "2021-01-01T00:00:00.000Z", "updatedAt": "2021-01-01T00:00:00.000Z" ``` #### Each table in Totalum is a mongoDb collection (adding data_ prefix), and each record in the table is a document in the collection. #### So for example, if you have a table named `product`, in the mongoDb database the collection will be named `data_product`. #### Important Information: - **For match by Id (ObjectId)**, as the mongoDb query is a string, you need to put: ObjectId('your_id') in the query string, instead of just 'your_id'. - **For match by date**, you need to put the date in the format: Date('your_date') in the query string, instead of just 'your_date'. Ideally provide a iso date string like '2021-01-01T00:00:00.000Z' for avoid time zone issues. ```javascript // filter results from your_element_table_name applying a filter query (a custom mongodb aggregation query) const customMongoDbAggregationQueryInString = ` your custom mongo aggregation query in string, for more info: https://docs.mongodb.com/manual/aggregation/ or ask to chatgpt, he is very good writing mongo aggregation queries ;) `; const result = await totalumClient.filter.runCustomMongoAggregationQuery(tableElementName, customMongoDbAggregationQueryInString); ``` **example** Imagine you have a table named `product`, with properties `name` (text), `price` (number), `provider` (many to one relation with relationship with the table `provider`). And you want to get all the products that have a price greater than 10, and that have a provider that have the name 'John', and also return all products with the full provider autofill, so you can do this: ```javascript const tableElementName = 'product'; const customMongoDbAggregationQueryInString = ` [ { $match: { "price": {$gte: 10} } }, // Join the data_product with data_provider using provider as the linking _id { $lookup: { from: "data_provider", // we add the prefix "data_" to the table name localField: "provider", foreignField: "_id", as: "provider" // Now storing the result directly in the "provider" field } }, { $match: { "provider.name": "John" } }, // Simplify the provider to be an object instead of an array { $addFields: { "provider": { $arrayElemAt: ["$provider", 0] } } } ] `; const result = await totalumClient.filter.runCustomMongoAggregationQuery(tableElementName, customMongoDbAggregationQueryInString); const items = result.data; ``` --- --- ## Deprecated Methods The following methods are deprecated. See the full documentation and migration guide in the [Deprecated Get Methods](./deprecated-get-methods) page. --- # ./docs/api/howFilterWorks.md --- title: How filter works sidebar_position: 4 --- # How Filter Works This page describes the filter format used with `totalumClient.crud.query()`. > If you are using deprecated methods like `getRecords`, `getNestedData`, `getManyToManyReferencesRecords`, or `nestedFilter`, see [How Filter Works (Deprecated)](./deprecated-how-filter-works) for the old filter format. --- ## Basic structure ```javascript const result = await totalumClient.crud.query('your_table', { _filter: { property_name: "value" }, _sort: { property_name: "asc" }, // "asc" or "desc" _limit: 50, _offset: 0, }); ``` --- ## How pagination works Use `_limit` to set the number of items per page and `_offset` to skip items. Default limit is 100. ```javascript // Page 1: items 0-49 { _limit: 50, _offset: 0 } // Page 2: items 50-99 { _limit: 50, _offset: 50 } ``` ## How sorting works Use `_sort` with `"asc"` (ascending) or `"desc"` (descending): ```javascript { _sort: { name: "asc" } } { _sort: { created_at: "desc" } } ``` --- ## Filter operators ### Filter by exact value (string, number, or date) ```javascript { _filter: { name: "John" } } { _filter: { age: 25 } } { _filter: { date: "2024-01-01T00:00:00.000Z" } } ``` ### Filter by partial string (regex) ```javascript { _filter: { name: { regex: "john", options: "i" } } } // options: "i" = case insensitive ``` ### Filter by number range ```javascript { _filter: { price: { gte: 1, lte: 10 } } } ``` ### Filter by date range ```javascript { _filter: { date: { gte: "2024-01-01T00:00:00.000Z", lte: "2024-01-10T00:00:00.000Z" } } } ``` ### Filter by not equal to ```javascript { _filter: { status: { ne: "inactive" } } } ``` ### Filter by list (in / not in) ```javascript { _filter: { status: { in: ["active", "pending"] } } } { _filter: { status: { nin: ["deleted"] } } } ``` ### Filter by contains, startsWith, endsWith ```javascript { _filter: { name: { contains: "john" } } } { _filter: { name: { startsWith: "jo" } } } { _filter: { email: { endsWith: "@gmail.com" } } } ``` ### Filter by a table relation (One to Many) **Use Case:** Imagine you have 2 tables, `client` and `order`. Each client can have multiple orders. You want to get all the orders of a specific client. ```javascript const result = await totalumClient.crud.query('order', { _filter: { client: "the_client_id" } }); ``` --- ## Combining filters ### AND condition (all must match) All properties at the top level of `_filter` are combined with AND: ```javascript { _filter: { status: "active", country: "Spain", age: { gte: 18 }, name: { regex: "john", options: "i" }, role: { ne: "admin" } } } ``` ### OR condition (at least one must match) Use `_or` to combine conditions with OR: ```javascript { _filter: { _or: [ { status: "active" }, { status: "pending" }, { age: { gte: 65 } } ] } } ``` ### AND + OR combined ```javascript { _filter: { country: "Spain", // AND this _or: [ { status: "active" }, // OR this { status: "pending" } // OR this ] } } ``` This filter will return the items where country is "Spain" AND status is "active" or "pending". --- ## Full example ```javascript const result = await totalumClient.crud.query('product', { _filter: { category: "electronics", price: { gte: 10, lte: 500 }, name: { regex: "phone", options: "i" }, }, _sort: { price: "asc" }, _limit: 20, _offset: 0, }); const items = result.data; ``` --- # ./docs/api/enviar-emails.md --- title: Send Emails sidebar_position: 2 --- # Send Emails Totalum allows you to send emails programmatically using the Totalum API or SDK. The email service supports custom HTML content, attachments, CC, BCC, and reply-to options. --- **📚 Setup Required:** For installation and usage of the Totalum SDK or API, see the [Installation Guide](/docs/api/instalacion). --- ## Send a basic email ```javascript const emailPayload = { to: ['recipient@example.com'], subject: 'Your email subject', html: 'This is the email content in HTML
', }; const result = await totalumClient.email.sendEmail(emailPayload); ``` ## Send an email with all options ```javascript const emailPayload = { to: ['recipient1@example.com', 'recipient2@example.com'], // array of recipients subject: 'Your email subject', html: 'This is the email content in HTML
', fromName: 'Your Company Name', // optional: custom sender name cc: ['cc@example.com'], // optional: carbon copy recipients bcc: ['bcc@example.com'], // optional: blind carbon copy recipients replyTo: 'reply@example.com', // optional: reply-to address attachments: [ // optional: array of attachments (max 10, each up to 15MB) { filename: 'document.pdf', url: 'https://example.com/path/to/document.pdf', contentType: 'application/pdf' // optional }, { filename: 'image.png', url: 'https://example.com/path/to/image.png', contentType: 'image/png' // optional } ] }; const result = await totalumClient.email.sendEmail(emailPayload); ``` ## Send an email with files from Totalum storage If you have uploaded files to Totalum and want to send them as attachments, you need to get their download URLs first: ```javascript // First, get the download URL of the file uploaded to Totalum const fileNameId = 'your_file_name.pdf'; // the file name ID from Totalum const fileUrlResult = await totalumClient.files.getDownloadUrl(fileNameId); const fileUrl = fileUrlResult.data; // Then, send the email with the attachment const emailPayload = { to: ['recipient@example.com'], subject: 'Email with attachment from Totalum', html: 'Please find the attached document
', attachments: [ { filename: 'document.pdf', url: fileUrl, contentType: 'application/pdf' } ] }; const result = await totalumClient.email.sendEmail(emailPayload); ``` ## Important notes - **Maximum attachments**: 10 attachments per email - **Maximum size per attachment**: 15MB - **Attachment URLs**: All attachments must be provided as valid HTTP/HTTPS URLs - **HTML content**: You can use full HTML and CSS in the email body - **Recipients**: The `to` field must be an array of email addresses --- # ./docs/api/subirArchivos.md --- title: Upload and Download Files sidebar_position: 7 --- # Upload and Download Files --- **📚 Setup Required:** For installation and usage of the Totalum SDK or API, see the [Installation Guide](/docs/api/instalacion). --- In Totalum, you can upload files and link them to your data. For example, you can upload a PDF file and link it to a client, or upload an image and link it to a product. To do this, when creating a table, for example a `client` table, you can add a property of type `file`, and when creating or editing a client, you will be able to upload a file and link it to the client. ## 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) ```javascript const fileInput = document.getElementById('fileInput'); const fileBlob = fileInput.files[0]; ``` #### From a file in storage (Backend) ```javascript const fs = require('fs'); const yourFilePath = 'your_file_path'; // example: /user/your_file.pdf const fileBlob = fs.readFileSync(yourFilePath); ``` #### From a remote file (Backend) ```javascript const response = await axios.get('your_file_url', { responseType: 'stream' }); const fileBlob = response.data; ``` #### From a base64 string (Frontend/Backend) ```javascript // Convert base64 to binary 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; // Environment check: Node.js or Browser if (typeof process === 'object' && process.version) { // Node.js environment // Convert Uint8Array to Buffer for Node.js usage const buffer = Buffer.from(bytes.buffer); // Here, 'buffer' can be used similarly to how you'd use a Blob in the browser // Note: Direct Blob emulation isn't possible in Node.js, but Buffer is a close alternative for file handling fileBlob = buffer; } else { // Browser environment // Create a Blob from the Uint8Array const blob = new Blob([bytes], { type: fileType }); fileBlob = blob; } ``` ### 1.2 Upload the file to Totalum **Using Totalum SDK** ```javascript const FormData = require('form-data'); // if you are using node.js const fileName = 'your_file_name.png'; // replace 'your_file_name' with the name of your file, replace .png with the extension of your file const file = yourFileBlob // your blob file created in the previous step const formData = new FormData(); formData.append('file', file, fileName); const result = await totalumClient.files.uploadFile(formData); const fileNameId = result.data; ``` **Using Totalum API** ```javascript const FormData = require('form-data'); // if you are using node.js const fileName = 'your_file_name.png'; // replace 'your_file_name' with the name of your file, replace .png with the extension of your file const file = yourFileBlob // your blob file created in the previous step 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', // replace 'your api key here' with your api key } }); const fileNameId = result.data; ``` ### Upload a file to Totalum and link it to an item property ```javascript const fileName = 'your_file_name.png'; const file = yourFileBlob formData.append('file', file, fileName); const result = await totalumClient.files.uploadFile(formData); const fileNameId = result.data; //if you want to link this file to an item, you need to add the fileNameId to the item property of type file const result2 = await totalumClient.crud.editRecordById('your_element_table_name', 'your_item_id', {'your_file_property_name': {name: fileNameId}}); // now the file is linked to the item property, and you can see it in the totalum panel. //what happens if your_file_property_name is a multiple file property? const result2 = await totalumClient.crud.editRecordById('your_element_table_name', 'your_item_id', [{'your_file_property_name': {name: fileNameId}}]); // in this case, you must set an array of files, but if you don't want to lost existing files, you can set the existing files in the array and add the new file at the end of the array ``` **example:** Imagine you have a table called `client` with the following properties: - `name` (text) - `email` (text) - `phone` (text) - `photo` (file) And you want to create a new client with name `John Doe`, the email `jhon@gmail.com`, the phone `+34 123 456 789`, and the birthday `1990-01-01`, and you want to link a photo to the client. ```javascript // first, we upload the file const fileName = 'your_file_name.png'; const file = yourFileBlob formData.append('file', file, fileName); const result = await totalumClient.files.uploadFile(formData); const fileNameId = result.data; // then, we create the client const tableElementName = 'client'; const clientToCreate = { name: 'John Doe', email: 'jhon@gmail.com', phone: '+34 123 456 789', photo: { name: fileNameId } }; const result2 = await totalumClient.crud.createRecord(tableElementName, clientToCreate); // now the client is created and the photo is linked to the client //what happens if your_file_property_name is a multiple file property? const clientToCreate = { name: 'John Doe', email: 'jhon@gmail.com', phone: '+34 123 456 789', photo: [{ name: fileNameId }] }; // in this case, you must set an array of files, but if you don't want to lost existing files, you can set the existing files in the array and add the new file at the end of the array ``` ### Remove a file from Totalum ```javascript // you can remove a file from totalum using the file name id const fileNameId = 'your_file_name.png'; // replace 'your_file_name' with the name id of your file, replace .png with the extension of your file const result = await totalumClient.files.deleteFile(fileNameId); ``` #### If you want to remove a file linked to an item property, you can do it like this: ```javascript const tableElementName = 'client'; let your_item_id = '5f9b2b1b9c6f6b0001a3b2b1'; const result = await totalumClient.crud.editRecordById(tableElementName, your_item_id, {'photo': null}); // this will remove the photo from the client with id '5f9b2b1b9c6f6b0001a3b2b1' ``` ### Download a file from Totalum ```javascript // you can get the fileNameId from the result of the upload file function const fileNameId = 'your_file_name.png'; // replace 'your_file_name' with the name id of your file, replace .png with the extension of your file //optional options const options = { // the default expiration time is 128 hours, but you can set it to whatever you want, after the expiration time the url will not return the file expirationTime: Date.now() + (128 * 60 * 60 * 1000); // Set to expire in 128 hours, how it works is, set the current date in milliseconds + the milliseconds you want the url to expire } const result = await totalumClient.files.getDownloadUrl(fileNameId, options); let fileUrl = result.data; // the result will be a full url that you can use to download the file ``` ### Download a file linked to an item property **PD: usually, when you link a file to an item property, the property automatically generates a file url that you can use to download the file.** You can access the file linked to an item property in this way: Imagine you have a table called `client` with the following properties: - `name` (text) - `email` (text) - `phone` (text) - `photo` (file) And you want to download the photo of the client with id `5f9b2b1b9c6f6b0001a3b2b1`. ```javascript const tableElementName = 'client'; let clientId = '5f9b2b1b9c6f6b0001a3b2b1'; const result = await totalumClient.crud.getRecordById(tableElementName, clientId); const client = result.data; let clientPhotoUrl = client.photo.url; // this is the url of the photo, you can use it to download the photo // but in some cases, if you want to get a new temporal url to download the file, you can do it like this: const clientPhotoId = client.photo.name; const result2 = await totalumClient.files.getDownloadUrl(clientPhotoId); let fileUrl = result2.data; ``` --- # ./docs/api/creacion-pdf.mdx --- title: PDF Creation sidebar_position: 102 --- # PDF Creation Totalum allows you to create fully customizable and dynamic PDFs from HTML. --- **📚 Setup Required:** For installation and usage of the Totalum SDK or API, see the [Installation Guide](/docs/api/instalacion). --- ## Create a PDF from pure HTML If you want to create a PDF directly from HTML without creating a template first, you can use the `createPdfFromHtml` function. ```javascript const htmlContent = 'This is a PDF created from HTML
'; const fileName = 'my-generated-pdf.pdf'; // replace with your desired file name const result = await totalumClient.files.createPdfFromHtml({ html: htmlContent, name: fileName }); const fileResult = result.data.data; // fileResult contains the generated PDF file information // if you want to link this pdf to an item, you need to add the fileName to the item property of type file const result2 = await totalumClient.crud.editItemById('your_element_table_name', 'your_item_id', {'your_pdf_property_name': {name: fileResult.fileName}}); ``` **Note:** The HTML is automatically encoded to base64 by the SDK before sending it to the API. --- ## DEPRECATED: Video Tutorial and Handlebars Approach :::caution DEPRECATED The following video tutorial and Handlebars-based approach are deprecated. Please use the "Create a PDF from pure HTML" method above instead. :::