Build REST APIs

What is API Designer

API Designer allows application developers to build custom web service APIs. You can define your own custom service endpoints and query parameters. These APIs can be used to interact with CRM data, integrate with external apps and also expose these data to VTAP Javascript APIs to be used within custom pages or widgets in Vtiger UI.

API Designer lets you add two types of APIs.

  1. REST APIs
  2. Incoming Webhook

REST APIs provides you the ability to access CRM data through HTTP/HTTPS protocol. You can perform create, update, retrieve or delete operations on any CRM record information. Apart from this it will also allows you to store extension specific data, user specific configuration data, or connect to external applications using the stored extension specific data. All these data can be accessed using basic authorization passing username and accesskey.

Incoming Webhook allows any external applications to post data to CRM, these are subsets of REST APIs but they do come with additional security. Each incoming webhook needs to be accessed using unique security token which can be configured when create webhook api. It also provides you to control accesses to webhook coming from specific IP addresses.

APIs can be created using Vtiger Application Design Language (VADL), this is loosely based on XML syntax to enable administrators or developers to be able to define API without needing deep programming skills. This is essential to create any custom APIs, good understanding on it will help in creating APIs quickly.

REST URI format

REST APIs follows standard REST API protocol, and each customer can define their endpoints.

For REST API endpoints, it follows the below format: https://instance.odx.vtiger.com/restapi/vtap/api/YOUR_CUSTOM_API_PATH

For Incoming webhook end point, the format is: https://instance.odx.vtiger.com/restapi/vtap/webhook/YOUR_CUSTOM_WEBHOOK_PATH

Supported HTTP request method

For REST API end points, below HTTP request methods are supported:

  • GET
  • POST
  • PUT
  • DELETE

For Incoming Webhook, below HTTP request methods are supported:

  • GET
  • POST

How to create REST APIs?

From the main menu, access Platform > API Designer module, you will see Add API button, clicking on gives two options. REST_CREATE

Build REST APIs to access CRM data

To access CRM data we have enabled read, write, update and delete operations to CRM records. Every API is identified with its name and it has to be unique since it is used in the endpoints.

In the below screen, to create API you need to select module, unique name(only characters and numbers) and checkmark it to enable. ADD_REST_API

Read data from CRM

After you add API, you will see in-built IDE where you need to use VADL to define APIs. For retrieving CRM data we will use select xml node, below is an example with api name "top_organizations" to show top 5 Organizations(internally called as "Accounts") with highest annual revenue. You will see select node used here with module attribute

    
<?xml version="1.0"?>
    <api method="get">
        <select module="Accounts">
            <record>
                <field name="accountname"></field>
                <field name="annual_revenue"></field>
            </record>
            <sort>
                <field name="annual_revenue" order="descending"></field>
            </sort>
            <limit max="5" page="@page"></limit>
        </select>
    </api>
    

Below is the list of VADL nodes that can be used for select.

Name Description Example
select This will retrieve data from the crm identified with module attribute. This will define other how the data will be read, conditions, sorting and number of records. <select module='Contacts'></select>
record This will have all the fields which needs to be retrieved and is placed inside select node. <record><field name="firstname"></field><field name="lastname"></field></record>
where Use this when you want to filer the records, you can pass multiple fields. Use glue attribute(OR, AND) to decide if all or any fields should match the conditions. <where glue="OR"><field name="firstname" value="@first"></field><field name="lastname" value="@last" condition="like"></field></record>
sort This will have fields that will sort the data, with order attribute defining descending or ascending. <sort><field name="annual_revenue" order="descending"></field></sort>
limit By default we return 100 records, but you can pass max attribute to limit records. If there are more records, you can pass page parameter in the request get specific page records. <limit max="5" page="@page"></limit>
Conditions

Where clause supports different type of conditions and their details are:

Condition Description
eq Equals (=), defaults if not passed
neq Not Equals (!=)
gt Greater Than (>)
lt Less Than (<)
gte Greater Than OR Equal To (>=)
lte Less Than OR Equal To (>=)
in Select in Multiple VALUES (IN)
like Like (%VALUE%)

You can access this API from external applications through exposed endpoints, in the above example you can access it below endpoint. https://instance.odx.vtiger.com/restapi/vtap/api/top_organizations.

Each of these endpoints expects username and accesskey to be passed in the request headers as basic authorization. Postman screenshot of the above API is shown below. POSTMAN_SELECT

All custom REST API's built in API Designer can also be accessed using VTAP Javascript APIs, these data can be used to show as a list in custom page or use it for a bar chart etc.

        
    VTAP.CustomAPI.Get("get_organization", {}, (error, response) => {
        if(response) {
            //use response to show in the list or in the widget.
        }
    });
    


Read data using value-binding

Consider a case when you want to expose an API which wants to know Contact's first name and last name based on email address. Here email address is dynamic value, identified with '@' in the value attribute which will be passed as part of request parameter. To achieve I have created an API with name "search_contacts_with_email" this we will write xml as below.

    
<?xml version="1.0"?>
    <api method="get">
        <select module="Contacts">
            <record> 
                <field name="firstname"> </field>
               <field name="lastname"> </field>
               <field name="id"> </field>
               <field name="department"> </field>
            </record>
            <where glue="OR">
                <field name="email" condition="eq" value="@emailaddress"> </field>   
                <field name="phone" condition="eq" value="@phone"> </field>   
            </where>
        </select>
    </api>
    

Note : notice the glue attribute in where node, it is used to check if one of the condition in the where clause will match.

Accessing the same API via postman by passing emailaddress in the request parameter. REST_API_READ_DYNAMIC_BINDING

Create records in CRM

To create record you need to use create node, with method attribute as "post" in api node. Lets create a Contact record and link it to an existing organization record. For account_id field you can see it will first search company and if not found then it will create it.

    
<?xml version="1.0" ?>
    <api method="post">
        <create module="Contacts">
            <record>
                <field name="firstname" value="@firstname"> </field>
                <field name="lastname" value="@lastname"> </field>
                <field name="email" value="@email"> </field>
                <field name="contacttype" value="@type" default="Lead" presence="optional"> </field>
                <field name="account_id" module="Accounts">
                    <select>
                        <where>
                            <field name="accountname" value="@company"></field>
                        </where>
                    </select>
                    <create>
                        <record>
                            <field name="accountname" value="@company"></field>
                        </record>
                    </create>
                </field>
            </record>
            <return>
                <field name="id"> </field>
            </return>
        </create>
    </api>
    


You can create a record and also link it parent record using link node. In the below example you will see label in link node, this is the relationship name(label you see in related list in summary page) between newly created and parent record. If you are not sure then you can leave it skip mentioning it.

Here we are creating Documents record and relating to a Contact with an email address.

    
<?xml version="1.0"?>
    <api method="post">
        <create module="Documents">
            <record>
                <field name="notes_title" value="@notes_title"></field>
                <field name="notecontent" value="@notecontent" presence="optional"></field>
                <field name="filelocationtype" value="I"></field>
                <field name="fileversion" value="@fileversion" presence="optional"></field> 
                <field name="filestatus" value="1"></field>
                <field name="folderid" value="22x1"></field>
                <field name="document_source" value="Vtiger"></field>
                <field name="document_type" value="Public"></field>
            </record>

            <link label="Documents">
                <select module="Contacts">
                    <where>
                        <field name="email" value="@emailaddress"></field>     
                    </where>
                </select>
            </link>

            <return>
                <field name="id"></field>
            </return>
        </create>    
    </api>
    


Update Record

To replace email field value with incoming parameter (new_email) on all Contacts record matching incoming parameter (old_email) and respond back with record ID of changed records.

    
<?xml version="1.0" ?>
    <api method="put">
        <update module="Contacts">
            <record>
                <field name="email" value="@new_email"></field>
            </record>
            <where>
                <field name="email" condition="eq" value="@old_email"></field>
            </where>
            <return>
                <field name="id"></field>
            </return>
        </update>
    </api>
    


Update if exists else create a record, upsert

You can update and create in one single api call using upsert node. It has 2 parts one is update and other create node inside upsert node. They follow the same conventions to create and update record, just like in the previous examples.

    
<?xml version="1.0"?>
    <api method="post" module="Contacts">
        <upsert>
            <where>
                <field name="id" condition="eq" value="@CRMID"></field>  
            </where>
            <sort>
                <field name="id" order="desc"></field>
            </sort>
            <limit max="1"></limit>
            <update>
               <record>
                   <field name="email" value="@email" presence="optional"></field>
                   <field name="cardnumber" value="@card" presence="optional"></field>
               </record>
            </update>
            <create>
                <record>
                   <field name="firstname" value="@firstname" presence="optional"></field>
                   <field name="lastname" value="@lastname" presence="optional"></field>
               <field name="email" value="@email" presence="optional"></field>
                   <field name="account_id" module="Accounts" presence="optional">
                       <select>
                           <where>
                               <field name="website" value="@website"></field>
                           </where>
                           <sort>
                               <field name="domain" order="descending"></field>
                           </sort>
                        </select>
                    </field>
               </record>
            </create>
            <return>
                <field name="id"></field>
               <field name="lastname"></field>
               <field name="account_id"></field>
            </return>
        </upsert>
    </api>
    


Update a record and add a comment/mention

You can add a mention when you perform create, update and upsert operations.


<?xml version="1.0" ?>
    <api method="POST">
        <update>
            <record>
                <field name="leadsource" value="Facebook" presence="optional"></field>
            </record>      
            <where>
                <field name="status" value="Active"></field>
            </where>
            <return>
                <field name="id"></field>
            </return>
            <mention>
                <template>
                    <![CDATA[
                        <br>
                        <table>
                            <tr>
                                <td>Marketing Channel: %s</td></tr>
                            <tr>
                                <td>New lead created from Facebook: %s</td>
                             </tr>
                        </table>
                    ]]>                
                </template>
                <values>
                    <value name="fld_marketingchannel"></value>
                    <value name="email"></value>
                </values>
                <text>
                    //either use template or text, one of them.
                </text> 
            </mention>
            <return>
                <value name="assigned_user_id"></value> 
                <value name="fld_marketingchannel"></value>
                <value name="email"></value>
            </return>
        </update>
    </api>
    

List below different mention node definitions:

Name Description Example
mention wrapper node to define the syntax for mentions/comments <mention></mention>
text this contains text message <mention><text>testing comments</text></mention>
template this contains template message where placeholder %s is to be used to merge values <mention><template>A Lead is created with email address: %s</template></mention>
values if template is used then %s are replaced with names present in values node <values><value name="email"></value></values>


Delete records

You can delete multiple records at once, by defining the filter conditions.


<?xml version="1.0"?>
    <api method="delete">
        <delete module="Contacts">
            <where>
                    <field name="contacttype" value="@type"></field>
            </where>
        </delete>
    </api>


Create multiple records in one API call

You can combine and create mulitple records in one API call, for example you can create a Deal(Potential) record along with Contact and Organization(Accounts). If Contact and Organization record exists then link it to Deal record. Below is an example

    
<?xml version="1.0" ?>
    <api method="post">
        <create module="Potentials">
            <record>
                <field name="potentialname" value="@potentialname"></field>
                <field name="closingdate" value="@closingdate"></field>
                <field name="pipeline" value="@pipeline"></field>
                <field name="sales_stage" value="@sales_stage"></field>
                <field name="amount" value="@amount"></field>
                <field name="assigned_user_id" value="19x1"></field>
                <field name="related_to" module="Accounts">
                    <select>
                        <where>
                            <field name="accountname" value="@company"></field>
                        </where>
                    </select>
                    <create>
                        <record>
                            <field name="accountname" value="@company"></field>
                            <field name="assigned_user_id" value="19x1"></field>
                        </record>
                    </create>
                </field>
                <field name="contact_id" module="Contacts">
                    <select>
                        <where>
                            <field name="email" value="@email"></field>
                        </where>
                    </select>
                    <create>
                        <record>
                            <field name="firstname" value="@firstname"></field>
                            <field name="lastname" value="@lastname"></field>
                            <field name="email" value="@email"></field>
                            <field name="contacttype" value="@contacttype"></field>
                            <field name="assigned_user_id" value="19x1"></field>
                            <field name="related_to" module="Accounts">
                                <select>
                                    <where>
                                        <field name="accountname" value="@company"></field>
                                    </where>
                                </select>
                                <create>
                                    <record>
                                        <field name="accountname" value="@company"></field>
                                        <field name="assigned_user_id" value="19x1"></field>
                                    </record>
                                </create>
                            </field>
                        </record>
                    </create>
                </field>
            </record>
            <return>
                <field name="id"> </field>
            </return>
        </create>
    </api>
    
Create_Potentials_With_Account_And_Contacts

<?xml version="1.0"?>
<api method="post">
    <create module="Potentials">
        <record>
            <field name="potentialname" value="@potentialname"></field>
            <field name="closingdate" value="@closingdate"></field>
            <field name="pipeline" value="Standard"></field>
            <field name="related_to" module="Accounts">
                <select>
                    <where>
                        <field name="accountname" value="@company"></field>
                    </where>
                </select>
                <create>
                    <record>
                        <field name="accountname" value="@company"></field>
                    </record>
                </create>
            </field>
            <field name="contact_id" module="Contacts">
                <select>
                    <where>
                        <field name="email" value="@email"></field>
                    </where>
                </select>
                <create>
                    <record>
                        <field name="lastname" value="@lastname"></field>
                        <field name="contacttype" value="Lead"></field>
                        <field name="account_id" module="Accounts">
                            <select>
                                <where>
                                    <field name="accountname" value="@company"></field>
                                </where>
                            </select>
                        </field>
                    </record>
                </create>
            </field>
        </record>
    </create>
</api>
    

You can create a deal record with related records to accounts and conatcts in the same api.
Using select and where nodes.

  • select will help in selecting the record where the given condition is satisfied.
  • if the record is not found a record is created using create node and then linked to the deal or potential