Custom API
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.
- REST APIs
- 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 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.
##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.
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.
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.
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>
Get Deals or Multiple Field Conditions in the Where Clause
Retrieve all deals (Potentials) associated with a specific contact or account, based on either the contact's mobile number or the account's phone number, ensuring that records are returned if either condition is met.
<?xml version="1.0"?>
<api method="get">
<select module="Potentials">
<record>
<field name="potentialname"></field>
<field name="amount"></field>
<field name="assigned_user_id"></field>
<field name="createdtime"></field>
</record>
<where glue="OR">
<field name="contact_id" module="Contacts">
<select>
<where>
<field name="mobile" condition="eq" value="@mobile" presence="optional"></field>
</where>
</select>
</field>
<field name="related_to" module="Accounts">
<select>
<where>
<field name="phone" condition="eq" value="@phone" presence="optional"></field>
</where>
</select>
</field>
</where>
</select>
</api>
Get Cases With Related Contact And UserDetails using Select node
Fetches case records along with the contact's first name, last name, and mobile number, as well as the assigned user's full name and the group's name. This reduces the number of API calls needed to gather related information, streamlining your workflow.
<?xml version="1.0"?>
<api method="get">
<select module="Cases">
<record>
<field name="title"></field>
<field name="casestatus"></field>
<field name="assigned_user_id"></field>
<field name="createdtime"></field>
<field name="case_no"></field>
<field name="assigned_user_id" module="Users">
<select>
<field name="first_name"></field>
<field name="last_name"></field>
<field name="userlabel"></field>
</select>
</field>
<field name="contact_id" module="Contacts">
<select>
<field name="firstname"></field>
<field name="lastname"></field>
<field name="mobile"></field>
</select>
</field>
<field name="group_id" module="Groups">
<select>
<field name="groupname"></field>
</select>
</field>
</record>
<where>
<field name="contact_id" module="Contacts">
<select>
<where>
<field name="lastname" value="@name"></field>
</where>
</select>
</field>
</where>
</select>
</api>
Bulk Create
Bulk create can be done using the key bulk.
<?xml version="1.0"?>
<api method="post">
<create module="Potentials" bulk="true" data='@data'>
<record>
<field name="potentialname" value="@dealName"></field>
<field name="closingdate" value="22-06-2024"></field>
</record>
</create>
</api>
Create record and related/link to a parent record
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>
Relate/Link Existing Records
This custom API will help you relate/link existing records. Below is an example for linking cases record to contacts record.
<?xml version="1.0" ?>
<api method="put">
<update module="Cases">
<record>
<field name="id" value="@id"></field>
</record>
<where>
<field name="title" value="@casetitle"></field>
</where>
<link label="Cases">
<select module="Contacts">
<where>
<field name="email" value="@emailaddress"></field>
</where>
</select>
</link>
<return>
<field name="id"></field>
</return>
</update>
</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>
Bulk Update
Bulk update can be done using the key bulk.
<?xml version="1.0" ?>
<api method="put">
<update module="Contacts" bulk="true" data="@data">
<record>
<field name="firstname" value="@firstname"></field>
</record>
<where>
<field name="lastname" condition="eq" value="@lastname"></field>
</where>
<return>
<field name="url"></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>
Bulk Upsert
Bulk is supported in upsert. It can be used by key word bulk="true" and data="@data"
<?xml version="1.0"?>
<api method="post" module="Contacts">
<upsert bulk="true">
<where>
<field name="mobile" condition="eq" value="@mobile"></field>
</where>
<update>
<record>
<field name="mobile" value="@mobile"></field>
<field name="email" value="@email" presence="optional"></field>
<field name="lastname" value="@lastname" presence="optional"></field>
</record>
</update>
<create module="Contacts" bulk="true">
<record>
<field name="mobile" value="@mobile"></field>
<field name="email" value="@email" presence="optional"></field>
<field name="lastname" value="@lastname" presence="optional"></field>
</record>
</create>
<return>
<field name="mobile"></field>
<field name="email"></field>
<field name="lastname"></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. Lets see an example to add comment/mention to Contacts Module.
<?xml version="1.0" ?>
<api method="POST">
<update>
<record>
<field name="firstname" value="@firstname" presence="optional"></field>
</record>
<where>
<field name="email" value="@email"></field>
</where>
<mention>
<template>
<![CDATA[
<br>
<table>
<tr>
<td>Last name: %s</td></tr>
<tr>
<td>Email ID: %s</td>
</tr>
</table>
]]>
</template>
<values>
<value name="lastname"></value>
<value name="email"></value>
</values>
<!--<text>-->
<!-- //either use template or text, one of them -->
<!--</text> -->
</mention>
<return>
<field name="id"></field>
<field name="assigned_user_id"></field>
<field name="lastname"></field>
</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
NOTE - All bulk operations have a limit of 50 records. Each record will be considered as a single request and seperate api call when calculating minute and daily limit.