Examples
This guide is tailored to readers who prefer to learn by example. It covers all sections of the product and provides a wide variety of examples to help you get started using the API, configuring data models, managing permissions and much more.
System API
Any operation doable via the front-end application is doable via the API; either a single endpoint or a combination of. |
The system API is responsible for core system resources such as users and roles. It is also responsible for core operations such as authentication.
Whenever an operation affects the system and is not specific to any of our applications, you will most likely need to use the system API |
We omit most of the data returned by these endpoints.
We replace the important data with variables, such as |
-
URL path:
/system
, -
alias:
$SystemAPI
,
Authenticating users
To authenticate the user with their login credentials (email - $USER_EMAIL
; password - $USER_PASSWORD
), we use the POST $SystemAPI/auth/internal/login
endpoint.
The response is the following JSON object:
{
"jwt": "$JWT",
"user": {
"userID": "$USER_ID",
"name": "$USER_NAME",
"email": "$USER_EMAIL",
"username": "$USER_USERNAME",
"handle": "$USER_HANDLE"
}
}
The received |
The |
Compose API
Any operation doable via the front-end application is doable via the API; either a single endpoint or a combination of. |
The compose API is responsible for Corteza Low Code related resources such as modules, records and charts.
Whenever an operation affects Compose, you will most likely need to use the compose API. |
We omit most of the data returned by these endpoints.
We replace the important data with variables, such as |
-
URL path:
/compose
, -
alias:
$ComposeAPI
,
Sending emails
To send an email to a recipient or a set of, call the POST $ComposeAPI/notification/email/send
endpoint.
Refer to the API reference to find all the available parameters. |
Make sure that you’ve properly configured your environment with the SMTP credentials. |
Record listing
Record listing provides you with a list of records that conform to the given constraints. Use this when you wish to show some sort of list of available records, such as a record list. |
To list records stored under a specific module, use the GET $ComposeAPI/namespace/$NAMESPACE_ID/module/$MODULE_ID/record
endpoint.
Using filters
If you don’t need filtering simply omit this. |
When filtering over records, use module field names as |
Filters allow you to define…
- Filter by data
-
Use the
query=…
query property to specify what items should be included in the response.
We provide a SQL-like query language in the form of |
- Sorting
-
Use the
sort=…
query property to specify how to the response items should be sorted.
We provide a SQL-like sorting language in the form of |
- Pagination
-
Use the
page=…
andperPage=…
query properties to specify the pagination properties of the response.
Pagination is 1-based, meaning the first page index is 1. |
If you wish to list all items, define |
Example request
curl "$ComposeAPI/namespace/$NAMESPACE_ID/module/$MODULE_ID/record?filter=$FIELD1+LIKE+'%25$VALUE1%25'+AND+$FIELD2+LIKE+'%25$VALUE2%25'&sort=$SORT_FIELD+$SORT_DIR&page=$PAGE&perPage=$PER_PAGE" \
-H "Authorization: Bearer $JWT";
Example response
{
"response": {
"filter": {
"moduleID": "$MODULE_ID",
"namespaceID": "$NAMESPACE_ID",
"query": "$FIELD1 LIKE '%$VALUE1%' AND $FIELD2 LIKE '%$VALUE2%'",
"sort": "$SORT_FIELD $SORT_DIR",
"page": $PAGE,
"perPage": $PER_PAGE,
"count": 1(1)
},
"set": [{
"recordID": "$RECORD_ID",
"moduleID": "$MODULE_ID",
"namespaceID": "$NAMESPACE_ID",
"values": [
{ "name": "fieldName", "value": "fieldValue" }
...
]
}]
}
}
1 | The total number of records that match the provided filter. |
Record reading
Record reading provides you a single record that you wish to get the details for. Use this when you wish to show a specific record, for example when clicking on a specific record in a record list. |
To get a specific record stored under a specific module, use the GET $ComposeAPI/namespace/$NAMESPACE_ID/module/$MODULE_ID/record/$RECORD_ID
endpoint.
If you wish to read multiple records at the same time, instead of making N requests, simply use Record listing with the query of |
Creating a record
To create a record for a specific module, use the POST $ComposeAPI/namespace/$NAMESPACE_ID/module/$MODULE_ID/record
endpoint.
Updating a record
To update a specific record for a specific module, use the POST $ComposeAPI/namespace/$NAMESPACE_ID/module/$MODULE_ID/record/$RECORD_ID
endpoint.
The new record values will be as provided in the update request. The values that are omitted in the update request will be removed from the given record. |
Example request
curl "$ComposeAPI/namespace/$NAMESPACE_ID/module/$MODULE_ID/record/$RECORD_ID" \
-H "Authorization: Bearer $JWT" \
-H 'Content-Type: application/json' \
--data-binary "{
\"values\": [
{ \"name\": \"$FIELD1\", \"value\": \"$VALUE1\" },
{ \"name\": \"$FIELD2\", \"value\": \"$VALUE2\" }
]
}";
Deleting a record
To delete a specific record for a specific module, use the DELETE $ComposeAPI/namespace/$NAMESPACE_ID/module/$MODULE_ID/record/$RECORD_ID
endpoint.
Download attachment
Attachments are protected resources and require you to generate a signature in order to access them. |
To download the attachment you must perform the following:
Obtain a signed download URL
When fetching a specific attachment via the GET $ComposeAPI/namespace/$NAMESPACE_ID/attachment/record/$ATTACHMENT_ID
or listing attachments via the GET $ComposeAPI/namespace/$NAMESPACE_ID/attachment/record
you will receive the following JSON object:
{
"attachmentID": "$ATTACHMENT_ID",
"ownerID": "$USER_ID",
"url": "$ATTACHMENT_ORIGINAL_URL",(1)
"previewUrl": "$ATTACHMENT_PREVIEW_URL",(2)
"name": "$FILENAME_ORIGINAL",
"meta": {...},
"namespaceID": "$NAMESPACE_ID"
}
1 | url contains a signed URL path to the attachment. |
2 | previewUrl contains a signed URL path to the preview version of the attachment, when available. |
Example request
curl "$ComposeAPI/namespace/$NAMESPACE_ID/attachment/record/$ATTACHMENT_ID" \
-H "Authorization: Bearer $JWT";
Example response
{
"response": {
"attachmentID": "$ATTACHMENT_ID",
"ownerID": "$USER_ID",
"url": "$ATTACHMENT_ORIGINAL_URL",
"previewUrl": "$ATTACHMENT_PREVIEW_URL",
"name": "$FILENAME_ORIGINAL",
"meta": {...},
"namespaceID": "$NAMESPACE_ID"
}
}
Download the attachment
Use the attachments response.url
property to get the path of the downloadable attachment.
For example, /namespace/$NAMESPACE_ID/attachment/record/$ATTACHMENT_ID/original/$ATTACHMENT_NAME.$ATTACHMENT_EXT?sign=$ATTACHMENT_SIGNATURE&userID=$SIGNATURE_OWNER
.
Get the full path by joining the compose API base URL and the provided attachment path.
For example: $composeAPI/$ATTACHMENT_ORIGINAL_URL
.
You can then use any approach you wish to either display or download the attachment, such as using the <a href="…">…</a>
element, using Axios or any other client.
Server scripts
Automation scripts allow you to implement custom business logic that is required for your needs. Server scripts are executed in the Corteza Corredor. Refer to integrator guide/extensions for more details.
Since they are executed on the server, you can’t manipulate the user interface. Use client scripts if this is needed. |
Send an email to the contact
The example script sends an email to the contact it was invoked for.
Make sure that your SMTP configuration is working. |
export default {
label: "Script label",
description: 'Script description',
* triggers ({ on }) {
// This script myst be invoked manually (explicitly)
yield on('manual')
// for a record
.for('compose:record')
// if the record belongs to the Quote module
.where('module', 'Contact')
// and the module belongs to the crm namespace -- this is the slug
.where('namespace', 'crm')
// visible in the compose application
.uiProp('app', 'compose')
},
// Refer to the integrator guide for details on these two parameters
async exec ({ $record }, { Compose }) {
let emailContent
let emailSubject
// Determine the email content and subject.
// You could also do other bits inhere
if (!$record.values.Email) {
// This will stop the script's execution
return false
}
await Compose.sendMail(
$record.values.Email,
emailSubject,
{ html: emailContent }
)
}
}
Notify owner about the update
The example fetches the lead owner and sends them an email.
Make sure that your SMTP configuration is working. |
export default {
label: "Script label",
description: 'Script description',
* triggers ({ after }) {
// This script myst be invoked after the record is updated (implicitly)
yield after('update')
// for a record
.for('compose:record')
// if the record belongs to the Lead module
.where('module', 'Lead')
// and the module belongs to the crm namespace -- this is the slug
.where('namespace', 'crm')
},
// Refer to the integrator guide for details on these two parameters
async exec ({ $record }, { Compose, System }) {
let emailContent
let emailSubject
if (!$record.ownedBy) {
// This will stop the script's execution
return false
}
// Lets get the owner
const owner = await System.findUserByID($record.ownedBy)
// Determine the email content and subject.
// You could also do other bits inhere
await Compose.sendMail(
owner.email,
emailSubject,
{ html: emailContent }
)
}
}
Calculate the lead cost
The example calculates the lead cost when it is created or updated.
export default {
label: "Script label",
description: 'Script description',
* triggers ({ before }) {
// This script myst be invoked before the record is created or updated (implicitly)
yield before('create', 'update')
// for a record
.for('compose:record')
// if the record belongs to the Lead module
.where('module', 'Lead')
// and the module belongs to the crm namespace -- this is the slug
.where('namespace', 'crm')
},
// Refer to the integrator guide for details on these two parameters
async exec ({ $record }, { Compose }) {
if (!$record.values.LeadSource) {
// This will use the original record, since no changes are required.
// You could also use return false to stop the execution
return $record
}
switch ($record.values.LeadSource) {
case 'source-a':
$record.values.LeadCost = 10
break
case 'source-b':
$record.values.LeadCost = 20
break
default:
$record.values.LeadCost = 30
break
}
// Returning $record in a before script will automatically update the record.
// IMPORTANT: This is not the same for after scripts -- they need to be explicitly updated.
return $record
}
}
Client scripts
Automation scripts allow you to implement custom business logic that is required for your needs. Client scripts are executed in the client’s browser. Refer to integrator guide/extensions for more details.
Prompt notification
This example prompts the user to enter a value and then displays it as a notification.
export default {
label: "Script label",
description: 'Script description',
* triggers ({ on }) {
// This script myst be invoked manually (explicitly)
yield on('manual')
// for a record
.for('compose:record')
// if the record belongs to the Quote module
.where('module', 'Contact')
// and the module belongs to the crm namespace -- this is the slug
.where('namespace', 'crm')
// visible in the compose application
.uiProp('app', 'compose')
},
// Refer to the integrator guide for details on these two parameters
async exec ({ $record }, { Compose, ComposeUI }) {
const value = window.prompt('Please insert a value')
if (!value) {
ComposeUI.warning('No value provided')
return false
}
// Do something with the inserted value
// ...
ComposeUI.success(`Hi! You've entered ${value}!`)
}
}
Prefill values
This example prefills some record values in case they are not provided.
This can also be done with the module field default value setting. |
export default {
label: "Script label",
description: 'Script description',
* triggers ({ before }) {
// This script myst be invoked manually (explicitly)
yield before('formSubmit')
// for a record
.for('compose:record')
// if the record belongs to the Request module
.where('module', 'Request')
// and the module belongs to the crm namespace -- this is the slug
.where('namespace', 'crm')
},
// Refer to the integrator guide for details on these two parameters
async exec ({ $record, $module }, { Compose }) {
// Lets get the defaults from a Default module.
// This allows some more flexibility
const defaults = await Compose.findFirstRecord('Defaults')
for (const k in $record.values) {
if (!$record.values[k]) {
$record.values[k] = defaults.values[k]
}
}
// IMPORTANT: client-scripts work with references, so you don't need to
// explicitly return the $record -- this is already applied when we
// assigned a new value above.
return $record
}
}