Home Automation & AI

Automation & AI

Workflows, buttons, webforms and AI.
Christian
By Christian
• 13 articles

How to create workflows

Simply CRM allows you to streamline your business by automating certain tasks and operations, such as sending emails, creating activities, etc. This will save you time and allow you to focus on more important operations. How to create a workflow process To create a new workflow, go to Settings and select Workflows under Automation. Press the New Workflow button in the top right corner. Step 1: Provide basic information Once you press the New Workflow button, a new window will appear. In it, you will need to provide the basic information about the workflow, including its name, module and conditions. Important: All workflow conditions are predefined. Workflow triggers This determines when the workflow will be activated. Record creation – triggers the workflow when a new record is created. Record update – triggers the workflow when a record is updated (including the creation). Recurrence Only first time conditions are met – triggers the workflow if the conditions, which will be specified in step 2, are met. After the first execution, the workflow will not trigger again on the same record. However, it will still trigger actions on other records within the same module. Every time conditions are met – triggers the workflow whenever the condition is met. Step 2: Add conditions When you add conditions, the workflow is only executed on the records that satisfy the conditions that you define. For example, if you want to create a workflow for the Contacts module and send a greeting email on the Contact’s birthday. In this case, you will need to configure the condition as shown below. When you define conditions, you will have to options at your disposal: All Conditions and Any Conditions. 1. All Conditions filters reconds according to the AND condition and triggers the workflow only when all defined conditions are satisfied. 2. Any Conditions filters records according to the OR condition and triggers the workflow if at least one condition is satisfied. Simply CRM allows you to compare different fields with the Equals To condition. For example, if you want to create a workflow that executes a certain operation on the records in the Deals module when the Amount is 1000. You can select this option from the drop-down menu options. Simply CRM also allows you to add conditions for dates in regards to the current date. For example, if you want to create a workflow that sends an email 2 days before the Support End Date, your condition will be Support End Date less than days ago 3. Important: To help you group the conditions, Simply CRM automatically enables the AND Condition for All Conditions and Any Conditions. When you’re defining a condition, you can use the predefined criteria or create a custom criterion. You can configure multiple conditions for your workflows. Press the Add Condition button to add new conditions to a workflow. Count only workdays in workflows You can configure workdays to only include workdays configured in Business Hours. For instance, you can set up a workflow that will send an email to a customer three days before the Deal Closing Date. After you define the conditions, don’t forget to configure the workflow actions. Set up workflows on the email opt-in field Simply also allows you to set up workflows on the email opt-in fields. For example, if you want to know when a customer confirms an email subscription, you can create a workflow for the Contacts module. Then, set the Entry Criteria to Email Opt-in as Double Opt-in. Configure the Update action to configure the Email Confirmation Date as Today. Step 3: Add actions You can configure the previously described tasks using actions instead of workflows. All you need to do is press the Add Action button and choose your task. Below, you will a list of all available actions and their descriptions. | Field | Description | |---|---| | Send Mail | Used to send an email | | Invoke Custom Function | Used to update the target fields of records within a module when certain actions are executed over the source fields in another module | | Create Task | Used to create a new task | | Create Event | Used to create a new event | | Update Fields | Used to update the fields of the selected module | | Create Record | Used to create/update fields when the conditions on the parent record are met | | SMS Task | Used to send SMS notifications | | Mobile Push Notification | Used to notify a user when a task is assigned to him | Important: Workflows are executed in the instance owner context, even if the record owner does not have the write permission. For example, if you have a workflow that creates a Deal when the Lead Status is Hot, and a Sales representative who does not have the permission to create a Deal edits the Lead record to configure the status to Hot, the Deal will still be created. The Created By/Last Modified will automatically be set to the instance owner in this case. Similarly, scheduled workflows also run in the instance owner context. However, the create and update actions are done in admin context to ensure that the workflows will not be blocked by user profile restrictions. How to edit a workflow To edit or modify a workflow, go to Settings and choose Workflows in the Automation drop-down menu. Open the workflow that you want to edit by pressing on it and edit its properties. Once you’re done modifying the workflow, press Save to confirm the changes.

Last updated on Nov 07, 2026

Simply CRM Workflow Action Expressions Guide

This guide explains the workflow expressions available in Simply CRM for Update fields and related workflow actions that use the same expression engine. It includes: - supported expression syntax - available functions - practical examples - important usage notes What these expressions are used for Workflow expressions let a workflow calculate, transform, or retrieve values when it runs. Typical uses include: - filling a field from other fields - combining text values - calculating dates - formatting text - applying conditions - reading related-record values - working with JSON data in advanced workflows Basic syntax rules Strings use single quotes Use: 'Open' Not: "Open" Fields can be referenced directly Example: firstname Expressions can be combined Example: concat(firstname, ' ', lastname) Arithmetic and comparisons are supported Examples: amount + 100 quantity * unit_price amount >= 5000 Conditional logic is supported Syntax: if condition then value_if_true else value_if_false end Example: if amount > 1000 then 'Large deal' else 'Standard deal' end Fields from related records can be read directly Syntax: (reference_field : (Module) fieldname) Example: (account_id : (Accounts) phone) This reads the phone field from the related Account record referenced by account_id. Common examples Use a field value directly firstname Returns the value of firstname. Build a full name concat(firstname, ' ', lastname) Example result: John Smith Categorize a record by amount if amount > 1000 then 'Large deal' else 'Standard deal' end Read a related record field (account_id : (Accounts) phone) Returns the related Account phone number. Supported functions 1. substring(string, start, end) Returns part of a string. Example substring(subject, 0, 10) Returns the first 10 characters of subject. Example substring(accountname, 3, 8) Returns characters from position 3 to 8. Note If used with only 2 parameters, it returns the text from the start position to the end of the string. 2. preg_replace_str_only(pattern, replacement, subject) Performs a regex replacement on a string. Example preg_replace_str_only('/[^0-9]/', '', phone) Removes all non-numeric characters from a phone number. Example result If phone is: +49 (123) 456-789 Result: 49123456789 3. split(string, separator, index) Splits a string and returns one part. Example split(email, '@', 0) Returns the part before @. Example split(email, '@', 1) Returns the domain part of the email. Example result If email is: john@example.com Then: split(email, '@', 0) returns: john and: split(email, '@', 1) returns: example.com 4. concat(a, b, ...) Joins multiple values together. Example concat(firstname, ' ', lastname) Result: John Smith Example concat('INV-', invoice_no) Result: INV-100045 Note This function can accept more than two values. Example: concat(firstname, ' ', lastname, ' - ', email) 5. time_diff(a, b) Returns the difference between two date/time values. Example time_diff(closingdate, createdtime) Returns the time difference between closingdate and createdtime. 6. time_diff(a) Returns the difference between the current date/time and the provided value. Example time_diff(duedate) Useful in advanced date/time calculations. 7. time_diffdays(a, b) Returns the difference in days between two date/time values. Example time_diffdays(closingdate, createdtime) Returns the number of days between the two dates. 8. time_diffdays(a) Returns the number of days between now and the provided value. Example time_diffdays(duedate) Useful for overdue or remaining-days logic. 9. add_days(datefield, noofdays) Adds days to a date. Example add_days(closingdate, 7) Returns a date 7 days after closingdate. Example add_days(30) Returns a date 30 days from today. Common use Set a due date 14 days from today: add_days(14) 10. sub_days(datefield, noofdays) Subtracts days from a date. Example sub_days(closingdate, 3) Returns a date 3 days before closingdate. Example sub_days(10) Returns the date 10 days before today. 11. add_months(datefield, noofmonths) Adds months to a date. Example add_months(start_date, 1) Returns a date 1 month after start_date. Example add_months(contract_start_date, 12) Returns the anniversary date one year later. 12. sub_months(datefield, noofmonths) Subtracts months from a date. Example sub_months(contract_end_date, 2) Returns a date 2 months before contract_end_date. 13. get_date('today') Returns today’s date. Example get_date('today') 14. get_date('tomorrow') Returns tomorrow’s date. Example get_date('tomorrow') 15. get_date('yesterday') Returns yesterday’s date. Example get_date('yesterday') Common use Set a field to the current date: get_date('today') 16. add_time(timefield, minutes) Adds minutes to a time value. Example add_time(time_start, 30) Returns a time 30 minutes after time_start. Example add_time(15) Returns the current time plus 15 minutes. 17. sub_time(timefield, minutes) Subtracts minutes from a time value. Example sub_time(time_end, 45) Returns a time 45 minutes before time_end. 18. power(base, exponential) Raises a number to a power. Example power(2, 3) Returns: 8 Example power(quantity, 2) Returns the square of quantity. 19. getDateValue(dateValue, format) Formats a date/time value. Example getDateValue(createdtime, 'd/m/Y') Formats createdtime as day/month/year. Example getDateValue(createdtime, 'l j \of F Y h:i:s A') Could produce something like: Monday 4 of March 2026 09:15:22 AM Example getDateValue('d/m/Y') Formats the current date/time using the given format. Common use Store a user-friendly date string: getDateValue(closingdate, 'd.m.Y') 20. str_contains(a, b) Checks whether two |##|-separated multi-value strings share at least one common value. Example str_contains(cf_1234, 'Blue|##|Green') Returns true if cf_1234 contains either Blue or Green. Important note This is not a normal substring search. It is mainly useful for multi-select picklist style values. Example If cf_1234 contains: Red|##|Blue|##|Yellow then: str_contains(cf_1234, 'Blue|##|Green') returns true. 21. RecurrenceRuleAsDates(sourcefield, format, endDate, startDate) Creates a comma-separated list of dates from a recurrence rule field. Example RecurrenceRuleAsDates(recurrence_rule, 'd/m/Y', '31/12/2026', '01/01/2026') Useful in advanced scheduling or recurrence-based workflows. 22. GetFieldValue(sourcefield) Returns a field value. Example GetFieldValue(firstname) Returns the value of firstname. Example with related field GetFieldValue((account_id : (Accounts) phone)) Returns the phone number from the related Account. Note In many simple cases, the field can be used directly without wrapping it in GetFieldValue(). 23. GetTime(sourcefield) Converts a decimal hour value into HH:MM. Example GetTime(1.5) Returns: 01:30 Example GetTime(hours_worked) If hours_worked is 2.75, the result would be: 02:45 24. UrlDecode(sourcefield) URL-decodes a string. Example UrlDecode(cf_encoded_text) If the field contains: Hello%20World it returns: Hello World 25. changeCase(sourcefield, operation) Changes the letter case of text. Supported operations: - 'upper' - 'lower' - 'ucfirst' - 'ucwords' Example changeCase(lastname, 'upper') Result: SMITH Example changeCase(firstname, 'ucfirst') Result: John Example changeCase(accountname, 'ucwords') If the value is: big blue systems the result is: Big Blue Systems Common use Normalize all-uppercase imports: changeCase(firstname, 'ucfirst') 26. searchModule(module, field, operator, value, returnFields) Searches another module and returns matching records as JSON. Supported operators: - 'equal' - 'contains' - 'notequal' Example searchModule('Contacts', 'email', 'equal', email, '[firstname,lastname,email]') Searches Contacts where email exactly matches the current record email. Example searchModule('Accounts', 'accountname', 'contains', accountname, '[id,accountname,phone]') Searches Accounts whose account name contains the current record account name. Note This is an advanced function, mainly useful for integrations and automation logic. 27. jsonArrayMerge(param1, param2) Merges two JSON arrays or JSON objects. Example jsonArrayMerge('{"a":1}', '{"b":2}') Result: {"a":1,"b":2} Example jsonArrayMerge(cf_json_part1, cf_json_part2) Combines two JSON values from fields. 28. json_get(fieldname, key) Reads a value from JSON using a key path. Example json_get(cf_json_payload, 'customer.name') Returns the nested value of customer.name. Example json_get(cf_json_payload, 'items[0].sku') Returns the sku of the first item in the items array. Example If cf_json_payload contains: {"customer":{"name":"John"}} then: json_get(cf_json_payload, 'customer.name') returns: John 29. json_set(fieldname, key, value) Sets or updates a value in JSON. Example json_set(cf_json_payload, 'customer.name', firstname) Updates customer.name using the current record firstname. Example json_set(cf_json_payload, 'status', 'Processed') Sets the top-level status value to Processed. Example If cf_json_payload contains: {"status":"New"} then: json_set(cf_json_payload, 'status', 'Processed') returns updated JSON similar to: {"status":"Processed"} 30. json_get_line_items(recordId) Returns line items from an inventory record as JSON. Example json_get_line_items(id) Useful in modules such as: - Quotes - Sales Orders - Purchase Orders - Invoices This is mainly for advanced integrations or JSON transformations. 31. getfieldOptions(Module.fieldname) Returns the available picklist options for a field as JSON. Example getfieldOptions('HelpDesk.ticketstatus') Returns the available values for the ticketstatus field in HelpDesk. Note This is mostly useful in advanced workflows or integrations. Arithmetic operators These operators can be used directly in expressions. Addition amount + 100 Adds 100 to amount. Subtraction amount - discount_amount Subtracts discount_amount from amount. Multiplication quantity * unit_price Calculates the total from quantity and unit price. Division amount / 2 Divides amount by 2. Comparison operators These operators can be used inside conditions. Equal amount == 1000 Greater than amount > 0 Less than amount < 0 Greater than or equal amount >= 500 Less than or equal amount <= 2000 Conditional expressions The expression engine supports if / then / else / end. Basic example if bill_country == 'Denmark' then 'DK' else 'Other' end Another example if amount >= 10000 then 'Enterprise' else 'SMB' end Nested example if amount > 10000 then 'Large' else if amount > 5000 then 'Medium' else 'Small' end Use nested conditions carefully to keep expressions readable. Related field syntax A field from a related record can be read using: (reference_field : (Module) fieldname) Example (contact_id : (Contacts) email) Returns the email of the related Contact. Example (account_id : (Accounts) phone) Returns the phone number of the related Account. Practical use Fill a field on the current record with a value from a linked Account: (account_id : (Accounts) website) Practical examples 1. Build a full name concat(firstname, ' ', lastname) 2. Create a due date 14 days from today add_days(14) 3. Create a due date 7 days after another date add_days(closingdate, 7) 4. Convert text to uppercase changeCase(lastname, 'upper') 5. Capitalize a first name changeCase(firstname, 'ucfirst') 6. Extract an email domain split(email, '@', 1) If email is john@example.com, the result is: example.com 7. Strip formatting from a phone number preg_replace_str_only('/[^0-9]/', '', phone) 8. Categorize a deal by amount if amount >= 10000 then 'Enterprise' else 'SMB' end 9. Pull a related Account phone number (account_id : (Accounts) phone) 10. Read a value from JSON json_get(cf_api_response, 'data.customer_id') 11. Format a date for display getDateValue(closingdate, 'd.m.Y') 12. Prefix a reference number concat('CASE-', ticket_no) Important notes 1. Always use single quotes for text Correct: 'Closed Won' Incorrect: "Closed Won" 2. concat() can take multiple parts Example: concat(firstname, ' ', lastname, ' (', email, ')') 3. str_contains() is for multi-value strings It checks overlap in values separated by |##|, not ordinary text search. 4. Some functions are advanced These are typically used in more advanced workflows or integrations: - searchModule() - jsonArrayMerge() - json_get() - json_set() - json_get_line_items() - getfieldOptions() - RecurrenceRuleAsDates() 5. Related-record syntax is especially useful Example: (account_id : (Accounts) phone) This makes it possible to pull values directly from linked records without custom code. Quick reference Text functions - substring() - preg_replace_str_only() - split() - concat() - UrlDecode() - changeCase() Date and time functions - time_diff() - time_diffdays() - add_days() - sub_days() - add_months() - sub_months() - get_date() - add_time() - sub_time() - getDateValue() - GetTime() Logic and numeric functions - power() - if / then / else / end - arithmetic operators - comparison operators Related-record access - (reference_field : (Module) fieldname) - GetFieldValue() JSON and advanced functions - searchModule() - jsonArrayMerge() - json_get() - json_set() - json_get_line_items() - getfieldOptions() - RecurrenceRuleAsDates() Summary These workflow expressions support: - field-based calculations - text formatting - date arithmetic - conditional logic - related-record lookups - JSON transformation - module search functions Most commonly used expressions include: - concat() - changeCase() - split() - add_days() - get_date() - if ... then ... else ... end - related-record syntax such as (account_id : (Accounts) phone)

Last updated on Nov 07, 2026

Workflow Actions in Simply CRM

Overview Workflow actions in Simply CRM let you automate what happens after a workflow condition is met. Instead of only notifying users, a workflow can also update data, create records, send emails, trigger external systems, generate documents, and even use AI-powered actions. This article covers the workflow actions currently available in your setup, what each action does, how it works, and a practical example of when to use it. Before you start A few workflow actions depend on optional features or add-on modules being enabled in your Simply CRM instance, such as: - Document Designer - Rollup - Real-Time Field Updates - AI features - Custom functions If one of these actions appears in your workflow builder, it is available in your environment. Available workflow actions Send Mail Sends an email automatically when the workflow runs. How it works This action builds and sends an email from workflow settings and record data. It supports: - dynamic recipients - CC and BCC - Reply-To - sender selection - HTML email content - attachments - optional PDF attachments - document-based attachments - linking the sent email back to the related record This is useful when you want a workflow to send a message without relying on a predefined email template. Example When a Deal is marked as Won, send a confirmation email to the customer with the deal summary and a PDF attachment. Invoke Custom Function Runs a custom backend function from a workflow. How it works This action calls a registered custom method when the workflow is triggered. It is typically used for advanced business logic that is too specific for standard workflow actions. This is a developer-driven action, so the exact behavior depends on the custom function that has been added to your Simply CRM setup. Example When an Invoice is approved, call a custom function that sends the invoice data to an accounting system and stores the returned external ID. Update Fields Updates field values on the current record, or on referenced records, as part of the workflow. How it works This is the standard field update action. It can: - set a fixed value - copy a value from another field - calculate a value using an expression - update reference-related fields - handle dates, times, currencies, picklists, multipicklists, and owners - update record labels when name fields change This is the main action to use when you want the workflow to keep record data clean and consistent. Example When a Lead is converted to a Customer, automatically set: - Status = Customer - Lifecycle Stage = Active - Follow-up Date = 7 days from today Create Record Creates a new record in another module from the current record. How it works This action creates a new record and maps values from the source record into the target module. It can also populate a reference field so the new record is connected back to the source record. Depending on configuration, it can also support more advanced creation patterns such as multiple record creation or split-based creation in some modules. Example When an Opportunity reaches Proposal Sent, automatically create a Quote and copy over the Account, Contact, Amount, and Expected Close Date. Add WebHook Sends data from Simply CRM to an external URL. How it works This action makes an HTTP request to a configured endpoint. It supports: - URL variables - record field placeholders - global variables - authentication - headers - URL parameters - payload values - file sending - response handling It can also process the response and write returned values back into Simply CRM fields. Example When a Sales Order is created, call the warehouse API to create a fulfillment request and write the returned shipment reference back to the order. Update Relations (One To Many) Updates fields on records that are already related to the current record. How it works This action looks at a related module and writes values from the current record into related records. It is designed for one-to-many style updates and can update: - all related records - only the last related record This is useful when a parent record should push a value down to its related records. Example When an Account owner changes, update the same owner or account segment field on all related Contacts. Send email from template Sends an email using a selected email template. How it works This action renders a template with data from the current record and then sends it. It supports: - dynamic recipients - CC and BCC - Reply-To - template-based subject and body - default/fallback templates in some setups - optional PDF attachment support - email tracking and linking back to the record This is the best choice when your emails follow a consistent format. Example When a Support Ticket is closed, send a branded closure email using the ticket-close email template. Select RelatedRecord Finds one or more records in another module and relates them to the current record, or writes the found record into a reference field. How it works This action searches in a target module using: - a source field value - an expression - exact match or contains logic - optional advanced filters Once matching records are found, it can either: - create a relation in the related list, or - set a reference field on the current record Use this when the workflow should automatically find the right existing record. Example When a Lead is created and its Company Name matches an existing Account Name, automatically link the Lead to that Account. Rollup/Calculate Fields Task Recalculates or aggregates values based on related records. How it works This action is tied to the Rollup feature. It is typically used to calculate values such as: - totals - counts - averages - latest values - summary fields pulled from related records The exact options depend on how the Rollup module is configured in your system. Example When an Invoice is created, recalculate the total billed amount on the related Account. Select Related Module Pulls related records from one module into another relation on the current record. How it works This action works by using an already-related source module and then copying that source module’s related records into another related module on the current record. In practice, it helps carry relations across connected records. Example If an Opportunity is related to an Account, and that Account already has related Contacts, this action can relate those same Contacts to the Opportunity automatically. Send Email with Document Designer attachments Sends an email that includes files generated through Document Designer. How it works This action depends on the Document Designer feature. It uses Document Designer output as part of the email process, so the workflow can send polished documents without manual export or attachment steps. This is especially useful for proposals, invoices, confirmations, or other formatted business documents. Example When a Quote is approved, email the customer a generated PDF proposal as an attachment. Save Document from Document Designer Creates and saves a document generated by Document Designer. How it works This action generates a document from a Document Designer template and saves it from the workflow. Depending on your setup, that may mean saving it to the record, to attachments, or to a document-related location in Simply CRM. Use this when you want document generation to happen automatically, even if no email needs to be sent. Example When an Invoice moves to Posted, automatically generate and save the official invoice PDF. Dynamic Dropdown Rebuilds a picklist field from values found in another module. How it works This action reads values from a selected source module, using a selected list/filter and a chosen source field. It then: - collects the values - removes duplicates - clears the target dropdown values - inserts the refreshed set of values into the target picklist - applies the selected ordering This is useful when a dropdown should stay in sync with live CRM data. Important Because this action clears and rebuilds the target dropdown, it should be used carefully. Example Build a “City” dropdown in one module based on unique city values found in Account records. Validate URL Checks whether a URL or domain is valid and writes the result to a field. How it works This action reads a source field, attempts to validate the domain, checks DNS/IP resolution, and then tests the URL response. It writes a status message into a target field. Possible outcomes include messages such as: - Valid Domain - Valid IP but page not responding - Domain is not valid If the source value is an email address, the action can use the domain part for validation. Example When a new Lead is created, validate the Website field and write the result into a custom field called Website Check Result. Field Updates Updates fields with a more specialized field-update action. How it works Based on the implementation, this action appears to be a more specialized version of field updating, mainly intended for inventory-style records and line-item-aware updates. It supports field mapping similarly to standard field updates, but is better suited where product, quantity, price, or related inventory values are involved. If you work with Quotes, Sales Orders, Purchase Orders, or Invoices, this action is likely intended for those cases. Example When a Quote is updated, copy or adjust specific inventory-related values such as quantity, price, or item-level custom values. Create Records from Json Creates one or more records by reading JSON stored in a field. How it works This action reads a JSON field on the source record, loops through the entries in that JSON array, and creates a new target record for each item. It can: - map JSON keys into target fields - combine JSON values with normal record values - use expressions - set reference fields back to the source record This is ideal when a single record contains structured imported data that needs to be split into separate CRM records. Example A web form stores an array of submitted attendees in a JSON field. This action creates one Contact record for each attendee. Related Records Update Updates fields on records that are already related through a many-to-many style relationship. How it works This action finds related records in a selected target module and copies a value from the source record into a chosen field on those related records. Unlike Select RelatedRecord, this action does not search for new records to relate. Instead, it updates records that are already related. Example When a Campaign’s custom event code changes, update the same code field on all related Product records. Query Task Runs a database query against an external MySQL-compatible database and uses the result in Simply CRM. How it works This action connects to an external database using the configured host, port, username, password, and database name. It then runs the configured query, which can include values from the current CRM record. The result can then be used to: - update the current record - create new records - update matching records based on a lookup field This is a powerful integration action, but it should be used carefully because it directly depends on external database access and valid SQL. Example When an Account is saved, query a legacy customer database for the credit rating and update the CRM record with the returned score. AI workflow action Uses AI on the record. Choose one of three actions: - Custom prompt: write a prompt and insert field values with $$fieldname$$. The answer is written to a field on the record or on a related record. - Translate: translates a field or a fixed text into the chosen language and writes it to a field. - Run AI agent: runs the agent chosen in the record's AI agent field (see the article “AI Agents: let AI work on your tickets”). On a comment, for example “@ai ...”, it runs the agent of the record the comment is on. The agent runs in the background, so saving a record is never slowed down. AI provider and key You use your own AI account: OpenAI, Anthropic or any OpenAI-compatible service (for example Mistral, Gemini, Azure or a local model). Set it up under Settings > Global variables: - global_openai_api_key or global_anthropic_api_key, or global_ai_base_url + global_ai_api_key for an OpenAI-compatible service - global_ai_provider (openai, anthropic or openai_compatible) and global_ai_model: the defaults. With no provider set, the first provider that has a key is used. Each action can also choose its own provider and model. If the AI call fails or gives no answer, the target field is left unchanged. Let AI decide in a workflow AI is not a condition itself. Let the action write its answer to a field, and use that field in normal conditions: 1. Workflow 1: when a reply arrives, Custom prompt “Is this reply positive? Answer only Yes or No: $$your reply field$$” → field Positive reply. 2. Workflow 2: when Positive reply is Yes, create a task for a salesperson. You can also use the field in filters and reports, and you can always see what the AI decided. Examples - When a support request is received in Danish, translate the message into English and store it in an internal field for the support team. - Generate a short AI summary of a long case description. - When a ticket is created, run the ticket's AI agent so a reply draft is ready. Ask user (Button popup) Opens the popup of a Button for the user who just saved the record. How it works Choose an active Button in the same module. When the workflow runs after a user saves a record in Simply CRM, the Button's popup opens. OK saves the popup fields and runs the Button's silent update and workflows, as a click on the Button does. Cancel does nothing. If the Button has no popup fields, the user is asked to confirm first. Only the user who saves the record in Simply CRM is asked. Import, API calls and records saved by other workflows do not open a popup. The popup opens after the record is saved, and the user can close it, so use it for optional questions. See the article “Buttons: one-click actions on records” for how to set up the Button. Example When a Contact is created without an email address, open a popup with the Email field so the user can fill it in. Choosing the right action Here is a practical way to decide which action to use: - Use Update Fields when you want to change values on the current record. - Use Create Record when the workflow should generate a new CRM record. - Use Send Mail or Send email from template when the workflow should contact someone automatically. - Use Add WebHook or Query Task when the workflow needs to interact with an external system. - Use Select RelatedRecord, Select Related Module, Update Relations (One To Many), or Related Records Update when the workflow should work with related records. - Use Document Designer actions when the workflow should generate or send documents. - Use AI workflow action when the workflow should write, translate or assess text, or start an AI agent. - Use Ask user (Button popup) when the workflow should ask the person who saved the record a question. Best practices Test with a sample record first Before enabling a workflow for all users, test it on a record that clearly matches the workflow conditions. Keep related-record logic simple If a workflow both creates relations and updates related records, start with one action first. Complex relation logic is easier to troubleshoot in smaller steps. Be careful with Dynamic Dropdown This action rebuilds the target dropdown values. That makes it powerful, but it also means it can replace the full list of options. Use templates for reusable emails If the email should always follow the same branding or wording, use Send email from template instead of building the email directly in the workflow. Watch for looping behavior Actions like Update Fields, Create Record, and some relation-based actions can trigger additional workflows depending on your setup. Review workflow conditions carefully to avoid unintended recursion. Summary Simply CRM’s workflow actions cover four main automation needs: - updating data - creating or linking records - communicating by email or document - connecting to outside systems Used well, they can remove a lot of manual work and make your processes more consistent.

Last updated on Nov 07, 2026

Buttons: one-click actions on records

Buttons let you add your own one-click actions to records in Simply CRM, for example "Close ticket" or "Mark as won". A button can update fields, open a short form, create a related record or start a workflow. Tasks that normally take several steps are done with one click, and the button only appears when it is relevant. Your team saves time, makes fewer mistakes and follows the same process every time. Administrators set up the buttons. Users just click them. What a button can do - Update fields in a popup: the user fills in selected fields and clicks Save. You can make some of the fields required. - Set a field automatically (silent field update): sets a dropdown or checkbox field to a fixed value. - Create a record in another module: for example a ticket from an organization. - Run workflows: for example to send an email or calculate dates from what the user entered in the popup. A button can combine these. Where a button is shown - Detail: on the record page. - List: in the list view of the module. - Related list: on each row of a related list tab. For example, a button on membership lines is shown on every membership line under a contact. The button runs on that row, not on the contact. - Summary widget: on each row of a "Related module" widget on the summary view (Custom Widgets), in its own column at the end of the row. It runs on that row, and only the widget refreshes afterwards. It is independent of Related list: a button can be in the widget without being in the tab. - Summary widget header: in the header of one chosen widget on the summary view (Custom Widgets), for example "Copy water volumes" in a water volume widget on a company. It runs on the record itself (the company), and only that widget refreshes afterwards. Choose the widget under Widget. A button can be shown in several places at once. A workflow can also open a button's popup by itself right after a record is saved, see "Ask the user in a popup after a save" below. Create a button The Buttons app is active by default. You can deactivate it under Settings > App Management > Apps if you do not want to use it. 1. Go to Settings > Other Settings > Buttons. 2. Click New Button. 3. Select the Module first. The other options depend on it. For a related list or summary widget row button, choose the module of the rows (for example Membership lines), not the module of the page. For a summary widget header button, choose the module of the page (for example Organizations). 4. Fill in the settings below and click Save. Basic settings | Setting | Description | |---|---| | Module | The module that gets the button. | | Button Title | The button text. | | Select View | Detail, List, Related list (row action), Summary widget (row action) and/or Summary widget header. Choose one or more. | | Widget | For Summary widget header: the Custom Widgets widget whose header shows the button. The list shows the widgets of all modules; pick one on the button's module. | | Icon/Label, Button Color | Icon, color and style (Solid or Border). | | Sequence | Button order. Lowest number first. If empty, buttons are shown in the order they were created. | | Active | Turns the button on or off. | | Popup Window Title, Popup Text | Title and help text in the popup. | | Save button text, Cancel button text | The texts on the popup's buttons, for example "Cancel membership" instead of Save. Default Save and Cancel. A known text (Save, Cancel, Add Contact …) is translated into the user's language; other texts are shown as written. | Modal Popup: update this record - Fields on Popup: fields the user fills in. Leave empty for a one-click update. - Required fields on popup: popup fields that must be filled in. The popup cannot be saved while they are empty, and the silent update and workflows do not run. - Silent Field Update: a dropdown or checkbox field and its new value. Set on click, or on Save if the popup has fields. - Workflows: run after saving, in the chosen order, and can use the values entered in the popup. Only active, manually triggered workflows in the same module. - Activate RichText for TextAreas: allows text formatting in the popup. Module Popup: create a record - Select Module: where the new record is created. - Fields on Popup: fields for the new record. - Popup Width %: width of the popup. Conditions (optional) Show the button only on records that match, for example when Status is not Cancelled. Choose whether all or any conditions must be met. Without conditions, the button is shown on all records. On a related list or summary widget, the conditions are checked for each row; in a widget header, on the record itself. Mobile app - Used in browser / Used in Mobile: where the button is available. - Mobile Function: call, SMS, email, map or quick create. - Mobile Location: top or bottom of the screen. Example: cancel a line from the related list A button "Cancel" on membership lines, shown in Related list: 1. Fields on Popup: End date. Required fields on popup: End date. 2. Save button text: Cancel membership. 3. Conditions: Status is not Cancelled, so the button disappears when the line is cancelled. 4. Workflows: a manual workflow that copies the end date to the cancellation date and sets today's date as the date the cancellation was received. The user opens a contact, clicks Cancel on the line, picks a date and clicks Cancel membership. The line is updated and the list refreshes. Select Summary widget as well (or instead) to offer the same button in a membership widget on the summary view. Ask the user in a popup after a save A workflow can open a button's popup for the user right after they save a record. Use it for optional questions, for example "Do you want to send a welcome email?" when a contact is created without an email address. 1. Create the button as described above: the fields on the popup, required fields, silent update and workflows. 2. Create a workflow in the same module. Choose when it runs: Only on the first save, Every time the record is saved or Every time a record is modified. Add conditions to limit it, for example "Email is empty", or "has changed" on a field. 3. Add the task Ask user (Button popup) and select the button. When a user saves a record that matches the workflow, the button's popup opens. OK saves the popup fields and runs the button's silent update and workflows, as a click on the button does. Cancel does nothing. If the button has no popup fields, the user is asked to confirm first. A save opens at most three popups, one after the other. Good to know: - Only the user who saves the record in Simply CRM is asked. Import, API calls and records saved by other workflows do not open a popup. - The popup opens after the record is saved. It cannot stop the save. - The user can close the popup. Use it for optional questions. Something that must always happen belongs in a normal workflow, or in a required field. - It works in both the new and the classic interface. Use a button - On a record: open the record and click the button. - On a related list row: in the classic interface, click the button on the row. In the new interface, open the row's actions menu and choose the button. - On a summary widget row: click the button at the end of the row (classic interface). - In a summary widget header: click the button in the widget's header (classic interface). If a popup opens, fill it in and click the save button. Troubleshooting Buttons missing in Settings? The app has been deactivated. Activate it under Settings > App Management > Apps. Button not shown? Check that it is active, set up for the right module and view, that the record matches the conditions, and that the user can edit the record. Button not shown on related list or widget rows? Select Related list or Summary widget under Select View, and make sure the button is set up on the module of the rows. Buttons that only run JavaScript are not shown on rows. In the new interface, buttons that create a record in another module are not shown on rows yet, and summary widgets are not supported yet. Button not shown in a widget header? Select Summary widget header and the right Widget, and set up the button on the module of the page, not of the widget's rows. Buttons that only run JavaScript are not shown there. Button cut off in a summary widget? The widget is too narrow. In the widget's settings (Custom Widgets), choose Wrap, show everything under Long rows, show fewer columns, or move the widget to a wider column. Popup cannot be saved? A required field is empty. Save or Cancel text not translated? Only known texts are translated. Your own text is shown as written in every language. Cannot choose fields? Select the Module first. Workflow not in the list? It must be active, in the same module and set to run manually. Field not available for silent update? Only dropdown and checkbox fields are supported. Popup does not open after a save? Check that the workflow is active and that the saved record matches its conditions, that the task points to an active button in the same module, that the button's own conditions match the record, and that the user can edit the record. Records saved by import, API or another workflow never open a popup.

Last updated on Nov 07, 2026

AI Agents: let AI work on your tickets

AI Agents let an AI model work on your records, for example tickets. The agent reads the record, its emails and comments, can use tools you give it, and writes an internal note and a reply draft. A person always decides what is sent. Set up an agent Open AI Agents (Tools menu; an administrator activates the module in Module Manager) and create an agent: - Name and Chat name: the chat name is what the agent is called in comments, for example "Claude support". - Instructions: what the agent should do and how it should write. Tip: ask for informal, short replies and for "only state what you have checked". You can also tell it how to sort requests (e.g. bug, wish, question) and what to do with each kind. - Description: what the agent does and how other agents hand work to it (see "Hand work to another agent"). - Provider and model: Anthropic, OpenAI or any OpenAI-compatible service. Empty uses the CRM's default AI settings. You use your own API key. - Tools (optional): a JSON list of MCP servers the agent may use, for example [{"mcp": "gitlab", "tools": ["search"]}, {"mcp": "simply"}]. tools is an optional allowlist. The address and key of each server are stored as global variables global_mcp_<n>_url and global_mcp_<n>_token, never on the agent. - Active: only active agents run. On the record (e.g. a ticket) choose the agent in the AI agent field. Run the agent - Write a comment that starts with @ai followed by what you want, for example "@ai check the error log". Or set AI status to Start. - A workflow can also start it with the action AI workflow action > Run AI agent. To run it on every new customer email, see Set up automatic support with AI. - The agent runs in the background and usually answers within a minute or two. - Steer it by writing new comments: it always follows your latest instructions. AI status | Status | Meaning | |---|---| | Start | The agent will run. | | Running | The agent is working. | | Waiting for user | The agent needs an answer from you, or has handed the next step to someone else (see its note). | | Waiting for approval | A tool needs a person's approval first, e.g. temporary access to a system. The agent starts again by itself after the decision. | | Done | The agent has finished. | | Error | Something went wrong; the reason is in the agent's comment. | What the agent writes - Internal note: short, at most a few lines. The first line always says who acts next (see below). Shown in the comments with the agent's chat name, a robot icon and an "AI" label. Comments addressed to the agent show "to AI". - Reply draft: in the Email tab you see "Agent has a reply draft ready". Click Show to read it, or Insert in email to put it in the email, edit and send as usual. When you send it, the draft is marked as used: a comment notes whether it was sent unchanged, edited or translated, and the draft disappears. Who acts next The note starts with Next: <who> - <what to do>. Who is one of: - a CRM group, e.g. DevOps or Support. The agent sees your groups that have active users, and the group's description tells it what the group handles. Tip: describe your groups under Settings > Groups. - another AI agent (see below) - a named colleague - Customer: only the customer or their supplier can act - None: the reply is ready to send When someone other than Customer or None is named, the status becomes Waiting for user. Hand work to another agent Other active agents that have a Description are part of the agent's team. Write in the description what the agent does and how to hand work to it, for example "Fixes code bugs. Hand over by creating a GitLab issue with the steps to reproduce." The agent first does what its own tools can do, then hands the work over the way the description says and names that agent as Next. Built-in CRM tools Agents can look up the customer's other tickets, emails and comments in the CRM themselves, read-only, to see if a request belongs to an ongoing matter: - customer_overview: the record's organization and contact, and their latest tickets and emails - search_records: search records in the allowed modules - get_record: read one record, an email's text or a record's comments They only return records the agent's assigned user may see. They are on by default for agents working on tickets. In Tools you can choose them with {"crm": ["customer_overview", "search_records", "get_record"]}, add "modules": [...] to change which modules can be read, or turn them off with {"crm": false}. Translate comments Every comment has Translate at the right end of its header line. It translates into your language on demand only, and Show original switches back. Tools and screenshots With tools, the agent can look things up itself (code, records, logs). Tools that return pictures, such as screenshots, are shown to the agent as images, so it can see what a page looks like.

Last updated on Nov 07, 2026

Set up automatic support with AI

With an AI agent on your tickets, every new customer email is read by AI before anyone on your team opens it. The agent finds the customer's context, works out what is needed, writes an internal note that says who acts next, and prepares a reply draft. A person always checks and sends the reply. This guide sets it up step by step. The agent itself is described in AI Agents: let AI work on your tickets. 1. Create the support agent Open AI Agents (Tools menu) and create an agent, for example "Support". Choose provider and model (or leave empty for your default AI settings) and set it to Active. Keep Autonomy at Drafts only. 2. Write its instructions The instructions are where the agent learns your business. Write them as you would brief a new colleague: - What you sell and who your customers are. - How to reply: language, tone, length, signature. Tip: "Only state what you have checked." - How to sort requests and what to do with each kind. Use your own categories, for example: - Software company: Bug (something that should work does not: find the cause), Improvement (a new wish: note it for a decision, promise nothing), Question (answer it). - Kitchen company: Complaint (book a service visit), New order (prepare a quote), Question. - Association: Membership, Event, Board matter. Ask the agent to write the category on the second line of its note, e.g. "Type: Complaint". 3. Describe your team The agent's note starts with Next: <who> - <what to do>, so it needs to know who does what: - Groups: under Settings > Groups, give each group with active users a short description of what it handles, e.g. "Installers: assembly and service visits". - Other AI agents (optional): an active agent with a Description can receive work from the support agent. Write in the description what it does and how to hand work to it. 4. Choose which customers get AI Use the field Incoming Message Automation on the organization (contacts get the organization's value when theirs is empty): | Value | Meaning | |---|---| | Automatic | The agent runs on every new email from this customer. | | Manual review | The agent also runs; use it for customers you want to watch more closely. | | Block | Never automatically, e.g. spam or customers you do not want AI on. | | Empty | Not automatically. | Tip: set Automatic for customers you have already had a real dialog with; they are hardly spam. 5. Start the agent on new email Create a workflow on Tickets, "Every time the record is saved": - Conditions (all): Last Email At has changed, Waiting for answer from is Support, AI status is not Running. - Conditions (any): the organization's Incoming Message Automation is Automatic or Manual review, or the contact's is. - Action: Update fields: AI agent = your support agent and AI status = Start. Or use AI workflow action > Run AI agent. You can always start the agent by hand with a comment that starts with @ai, also on customers set to Block. 6. Daily use 1. Open the ticket and read the agent's note. The first line says who acts next. 2. Click Insert in email on the reply draft, adjust it and send it. 3. To steer the agent, write a comment starting with @ai, e.g. "@ai the customer is on the old plan, check that first". Good to know - The agent never sends anything to the customer itself. - It only sees records its assigned user may see. - Access to other systems (e.g. a customer's own system) needs a person's approval first. - Each run uses your own AI provider's key and is billed by them.

Last updated on Nov 07, 2026

AI Copilot: ask AI about your records

AI Copilot is a chat assistant in Simply CRM. Click the round robot button at the bottom right to open it. Turn it on An administrator turns it on under Settings > Configuration Editor > AI Copilot > Simply Copilot. Copilot uses the CRM's own AI setup (your own API key for Anthropic, OpenAI or an OpenAI-compatible service). What it can do - Knows the record you have open. On a ticket, deal, contact etc. it gets the record's fields, latest comments, linked emails and an overview of the customer's other tickets and emails. "This", "it" and "the ticket" mean that record. - Looks up more data itself in every module you have access to, custom modules included: - searches records, also by any field, "assigned to me" and a date range, for example "my tasks and meetings this week" - counts and totals, for example "open tickets per owner" or "pipeline per sales stage with total amount" - a record's related lists, as shown in the CRM, for example the contacts or documents of a deal - an email's text and a record's comments - a module's fields and dropdown values, as your role sees them, for example "which values can the sales stage have?" - your saved lists (filters): it can list them and run one, for example "run my list Open Tickets: how many are there and which are the newest?" It runs the list exactly like the list view, with the list's conditions. - Can change data, if an administrator allows it: create and update records, add comments and delete records, each shown with a Confirm button first. See AI Copilot: let it change data. By default it only reads. - Only sees and changes what you may. It runs as you, with your permissions and the same sharing rules as the list view. It never sends emails. - Suggested questions match the record you have open, for example "Summarize this ticket" or "Suggest a reply to the customer". - Answers in your language. Click New chat to start over. The conversation is kept while the chat is open. Cost Each question uses AI tokens on your own API key. To keep the cost down, Copilot: - sends a compact version of the record (no bookkeeping fields such as created/modified time, no empty numbers, at most 5 comments and 5 emails) - answers from that context first and only looks up more when needed - counts in the database instead of reading every record, so "how many" questions stay cheap - keeps a module's fields and dropdown values in a cache for 15 minutes - sends the fixed parts first, so the AI provider can reuse them from its prompt cache. Follow-up questions on the same record are much cheaper (about 90% fewer uncached input tokens in our tests).

Last updated on Nov 07, 2026

How to create webforms in Simply CRM

Simply CRM allows you to create personalized webforms to improve your conversion rates and capture leads from your website. Visitors that enter their details in the webforms will automatically be added as leads. Create webforms To create a webform in Simply, open Settings and choose Webforms under Automation. Click on the Add Webform button in the top right corner. In the new window, enter the webform information. If you’re uncertain what each field requires, consult the table below. | Field | Description | |---|---| | Webform Name | Enter a unique webform name (used only for your reference) | | Return URL | Enter the URL to which the user will be sent after submitting the details | | Status | Allows you to choose whether the webform is active or not | | Description | Provide more details about the webform (used only for your reference) | | Module | Select the module in which the new record will be created | | Assigned To | Select the user to whom the record will be assigned | | Captcha | Allows you to prevent spam and bot generated leads (it’s highly recommended to enable this option) | Important: Aside from the default modules, you can also create webforms for custom modules. In the User Assignment block, you can assign the records generated from the webform to users in your instance of Simply using the round robin method. You can select the users from the Round Robin Users List option on the right side. In the Field Information block, you can choose which fields you want to include in your webform. Keep in mind that the fields that you select here will be displayed as part of the webform on your website. Important: Mandatory fields are automatically selected in Simply. Upload documents You can allow your website visitors to upload documents using the File Upload Field. These documents will be attached to the record that is created when the user submits the webform. Simply press on the File Upload Field to enable this option. When you finish configuring all the settings, press Save. Generate ready-to-use webforms in HTML After you create a webform, you will automatically be led to its detailed view. There, you can press on the Show Form button in the top right corner and copy the HTML code to add the webform to your website. Integrate existing webforms In case you already have webforms on your website, you can integrate them with Simply CRM by establishing a relationship between the two entities. Public ID and Post URL, which are configured automatically when you create a webform in Simply, are especially useful here. You can find these two fields in the detailed view of your webforms. - Public ID is used to establish a relation between the existing form and Simply webforms. For example, <input type=”hidden” name=”publicid” value=”Paste Your Public Id Here”>. - Post URL is used to specify the location where the webform information will be submitted. For example, <form name=”Place Your Webform Name Here” action=”Paste Your Post URL Here” method=”post” accept-charset=”utf-8″>. Modify field names in existing fields In case your existing forms have different field names, you will need to change them in accordance with the Webforms Reference Field name. You can find the corresponding values in the detailed view of your webform in Simply CRM. Webforms in the new interface In the new interface, all webforms are on one page. Click Add new to create one, or click a webform to edit it. 1. Enter the Name and choose the Module. Neither can be changed after the webform is created. 2. Choose who the records are Assigned to, or turn on Round robin and choose the users. 3. Under Fields, the module's mandatory fields are added for you. Add more fields with Add field. For each field you can set: - Required: the visitor must fill it in. Mandatory fields are always required. - Hidden: the field is not shown on the form and gets its default value. A hidden field needs a default value. - Default value and Display name (the label on the form). - The order: move a field up or down with the arrows. 4. Click Save. When you open a saved webform, Embed on your website shows the public ID, the post URL, a link to the hosted form and the HTML for your website. Copy them with the copy buttons. File upload fields and return fields are still set up in the classic interface.

Last updated on Nov 07, 2026

Workflow Expressions in Simply CRM

Workflow Expressions in Simply CRM Workflow expressions allow you to build powerful, flexible automations inside Simply CRM. They make it possible to calculate values, manipulate text, work with dates, query other modules, and process structured data — all without writing custom code. Expressions are evaluated when a workflow runs and can be used to: - Update field values - Control workflow conditions - Build dynamic email content - Prepare data for integrations and webhooks Below is the complete reference of all workflow expressions available in Simply CRM, including how they work and practical examples for each. Core operators and conditional logic Arithmetic operators Supported operators: +, -, *, / Examples - amount + 25 - (quantity * listprice) - discount_amount Comparison operators Supported operators: ==, <, >, <=, >= Examples - amount > 1000 - closingdate < get_date('today') if(condition, value_if_true, value_if_false) Evaluates a condition and returns one of two values depending on whether the condition is true or false. Examples - if(amount > 1000, 'High value', 'Normal') - if(str_contains(interests, 'Support'), 'Send support pack', 'Skip') Text & string functions substring(string, start, end) Returns part of a string starting at a given position. If end is omitted, the substring continues to the end of the string. Examples - substring(subject, 0, 10) - substring(email, 0, 3) - substring(accountname, 5) preg_replace_str_only(pattern, replacement, subject) Performs a regular-expression-based replace on a string. If the replacement is [], it is treated as an empty string. Examples - preg_replace_str_only('/\s+/', '', phone) - preg_replace_str_only('/\D+/', '', cf_vat_number) - preg_replace_str_only('/^INV-/', '', invoice_no) split(string, seperator, index) Splits a string by a separator and returns the value at the specified index (0-based). Examples - split(email, '@', 0) - split(email, '@', 1) - split(cf_tags, ',', 2) concat(value1, value2, ...) Joins multiple values together into a single text string. Examples - concat(firstname, ' ', lastname) - concat('Deal: ', potentialname, ' (', amount, ')') - concat('https://example.com/ticket/', ticket_no) changeCase(sourcefield, operation) Changes the case of a string. Supported operations include: upper, lower, ucfirst, ucwords. Multibyte variants are also supported. Examples - changeCase(lastname, 'upper') - changeCase(firstname, 'ucfirst') - changeCase(fullname, 'ucwords') UrlDecode(sourcefield) Decodes URL-encoded text (for example %20 → space). Examples - UrlDecode(cf_url_params) - UrlDecode('Hello%20World%21') - Decode webhook payload fragments stored in a field Date & time functions get_date('today' | 'tomorrow' | 'yesterday') Returns a date value relative to the current day. Examples - get_date('today') - add_days(get_date('tomorrow'), 7) - if(closingdate < get_date('yesterday'), 'Overdue', 'OK') add_days(datefield, number_of_days) Adds days to a date or datetime value. Examples - add_days(createdtime, 7) - add_days(duedate, 1) - add_days(get_date('today'), 14) sub_days(datefield, number_of_days) Subtracts days from a date or datetime value. Examples - sub_days(duedate, 3) - sub_days(closingdate, 30) - sub_days(get_date('today'), 1) add_months(datefield, number_of_months) Adds months to a date or datetime value. Examples - add_months(createdtime, 1) - add_months(closingdate, 3) - add_months(get_date('today'), 12) sub_months(datefield, number_of_months) Subtracts months from a date or datetime value. Examples - sub_months(closingdate, 1) - sub_months(get_date('today'), 6) - sub_months(contract_end_date, 2) add_time(timefield, minutes) Adds minutes to a time or datetime value. Examples - add_time(meeting_start, 30) - add_time(createdtime, 15) - add_time(get_date('today'), 60) sub_time(timefield, minutes) Subtracts minutes from a time or datetime value. Examples - sub_time(meeting_start, 10) - sub_time(deadline, 60) - sub_time(modifiedtime, 5) time_diff(date1, date2) Returns the time difference between two date/time values. If only one parameter is provided, the difference is calculated against the current time. Examples - time_diff(modifiedtime, createdtime) - time_diff(closingdate) - if(time_diff(closingdate) < 0, 'Overdue', 'On time') time_diffdays(date1, date2) Returns the difference between two dates in days. If only one parameter is provided, it compares against the current date. Examples - time_diffdays(closingdate, createdtime) - time_diffdays(duedate) - if(time_diffdays(duedate) > 30, 'Long lead', 'Normal') getDateValue(datefield, format) Formats a date or datetime value using a PHP-style date format. Examples - getDateValue(createdtime, 'Y-m-d') - getDateValue(duedate, 'd/m/Y') - concat('Due: ', getDateValue(duedate, 'd/m/Y')) Numeric functions power(base, exponent) Raises a number to a given power. Examples - power(2, 3) - power(probability, 2) - power(amount, 0.5) GetTime(decimal_hours) Converts a decimal hour value into HH:MM format. Examples - GetTime(1.5) - GetTime(cf_estimated_hours) - concat('Duration: ', GetTime(cf_duration_decimal)) Multi-select & list handling str_contains(value1, value2) Checks whether two pipe-separated (|##|) lists share at least one common value. Designed for multi-select picklist fields. Examples - str_contains(interests, 'Support') - str_contains(interests, 'Support|##|Renewals') - if(str_contains(cf_regions, 'EMEA'), 'EU team', 'Other') Cross-module & advanced functions GetFieldValue(field_reference) Returns the value of a field from the current record or from a referenced record. Examples - GetFieldValue(email) - GetFieldValue((contact_id : (Contacts) firstname)) - GetFieldValue((account_id : (Accounts) accountname)) related(path) Returns a field value by following reference fields from the current record to related records. Use system field names, not field labels. Example: related("invoice_id.account_id.economic_acc_number") This starts from the current record, follows invoice_id to the related Invoice, then follows account_id to the related Organization/Account, and returns the value from economic_acc_number. Example use case: On a Card Transactions workflow, copy the Economic Account Number from the Organization linked through the related Invoice. Path: CardTransactions.invoice_id → Invoice.account_id → Accounts.economic_acc_number If any reference in the path is empty or missing, the function returns an empty value. searchModule(module, field, operator, value, returnFields) Searches another module and returns matching records as JSON. Supported operators: equal, contains, notequal. Examples - searchModule('Contacts','lastname','contains','Smith','[id,email]') - searchModule('Accounts','accountname','equal','[Acme,Globex]','[id,accountname]') - searchModule('Users','email1','contains','@example.com','[id,user_name]') json_get(fieldname, path) Extracts a value from a JSON object using dot notation. Examples - json_get(cf_payload, 'customer.name') - json_get(cf_payload, 'items[0].sku') - json_get(cf_payload, 'meta.version\\.raw') json_set(fieldname, path, value) Sets or updates a value inside a JSON object using dot notation. Examples - json_set(cf_payload, 'customer.name', 'Alice') - json_set(cf_payload, 'items[0].qty', 3) - json_set(cf_payload, 'meta.lastUpdated', get_date('today')) jsonArrayMerge(value1, value2) Merges two JSON objects or arrays into one. Examples - jsonArrayMerge('{"a":1}', '{"b":2}') - jsonArrayMerge(cf_jsondata, '{"status":"new"}') - Merge two integration payloads into a single object json_get_line_items(recordId) Returns inventory line items (Products & Services) as JSON. If no record ID is provided, the current record is used. Examples - json_get_line_items(id) - retrieves the line items of the current record (just referenced as id) - Store line items in a custom JSON field - Extract totals or quantities from returned line item data RecurrenceRuleAsDates(rule, format, endDate, startDate) Expands a recurrence rule into a list of dates within a given range. Examples - RecurrenceRuleAsDates(recurrence_rule, 'd/m/Y', '31/12/2026', '01/01/2026') - Generate scheduled dates from repeating events - Use recurrence output to drive task or event creation

Last updated on Nov 07, 2026

AI Copilot: let it change data

An administrator decides whether AI Copilot may change data, and whether it asks first. Where Settings > Configuration Editor, section AI Copilot (below the switch that turns Copilot on). What Copilot may do - Only read (default): Copilot reads and answers, but never changes data. - Read and edit: Copilot may also create and update records and add comments. - Read, edit and delete: Copilot may also delete records (they go to the recycle bin). Ask for confirmation before changes On by default. Copilot then shows each change as a card in the chat, for example "Update Mobil Testlead deal – Sales stage: Contacted → Meeting agreed", with Confirm and Cancel. Nothing changes until the user clicks Confirm. Deleting always asks for confirmation, whatever this setting says. Safety - Copilot always works as the logged-in user, with their permissions. It can only change what the user could change themselves. - Changes are made like a normal save: workflows run, and the change is kept in the record's history under the user's name. - Copilot never sends emails. It can write a draft for the user to send. - Only Copilot in the app can change data. AI agents in workflows cannot. Tips - Say clearly what to change, for example "Set the sales stage on this deal to Meeting agreed" or "Create a task for me tomorrow at 10:00 linked to this ticket". - If a required field is missing, Copilot asks for it. - The open record is not reloaded after a change; refresh the page to see it.

Last updated on Nov 07, 2026

Workflow schedules: run at different intervals by time of day

Scheduled workflows can run on a schedule instead of one fixed interval. For example: every 5 minutes on weekdays between 08:00 and 18:00, every 15 minutes the rest of the time, and once a year on 1 January. Set it up 1. Open the workflow and click the trigger (When …). 2. Choose Schedule, then Schedule rules under Schedule. 3. Add your time rules. Each rule reads as a sentence, e.g. Run every 5 minute between 08:00 and 18:00 on Mon–Fri. 4. Under The rest of the time, choose how often it runs outside your rules, or Don't run. 5. Click Save. Time rules - Minute / hour: runs every N minutes or hours inside a time span on the chosen days. - Day / week / month / year: runs once at a fixed time, e.g. every night at 02:00, the first weekday of the month at 07:00, or 1 January at 06:00. - If two time spans overlap, the first rule that matches is used. Use the arrow to move a rule up. - Templates add common rules in one click: Working hours, Every night, First weekday of the month, Yearly. Runs are aligned to the clock (08:00, 08:05, 08:10 …) in the CRM's time zone. Exceptions - Don't run on Danish public holidays skips those days. - Add date/period skips your own dates, e.g. 24–31 December. Exceptions apply to the intervals. Fixed times (e.g. 1 January at 06:00) always run. Check before saving Next runs shows the next five runs and which rule each comes from. Advanced: show as RRULE shows the schedule in the standard calendar format.

Last updated on Nov 07, 2026