General documentation for the automatic generated REST API for Slingr apps. Security and authentication. Data manipulation.

This API allows to work with your app data, execute actions, check status of jobs, logs, etc., all through a simple REST interface. Everything that can be done from the UI in an app can also be done using these web services.

Slingr API is based on REST recommendations (we don’t follow all of them though) and we use JSON as the main data format.

You can access the API at the following endpoint:

https://<appName>.slingrs.io/<env>/runtime/api

where appName is the name of the app and env is the name of the environment, like dev and prod.

Notice that you always have to use HTTPS. Trying to access out API using HTTP will return an error.

Additionally, all calls should have the following headers:

  • Content-Type: application/json
  • Accept: application/json
  • token: <token received after login>

General error codes

Here are some general error descriptions. Then on each method you will see a better description to some of the errors that can show up.

HTTP Status Code Description

200

Everything went fine. No errors.

400

Request is not valid. This can be due to validation errors in the data you are sending or because the operation you are trying to do is not valid.

401

Unauthorized. You need to log in or the provided token is not valid.

403

Forbidden. You have credentials, but you are trying to access data or execute an operation you don’t have permissions.

404

Not found. The resource you are trying to access does not exist.

409

Optimistic locking exception. This happens when two users tries to update the same record at the same time. The once that enters in the second place will get this error.

500

Internal error. This happens when something went wrong and was not expected. If you get this type of errors please contact support.

503

Service unavailable. This is when the application is under maintenance.

Authentication

Before being able to use the API, you need to log in and get a valid token. The URL to get the token is the following:

POST /auth/login

This method has no parameters and the body should have the following form:

{
  "email": "user@test.com",
  "password": "abcdefgh"
}

The response will be something like this:

{
  "app": "appname",
  "adminUserEmail": null,
  "ip": "::ffff:10.240.0.38",
  "userEmail": "user@test.com",
  "userName": "User Test",
  "userId": "57fce0c3e4b0ce322b0c06b2",
  "token": "eLJjYSjLUPLlIEe8lfJUOmzsVNvSRpOv"
}
HTTP Status Code Description

app

Code of the app the token belongs to.

adminUserEmail

This field is used when impersonating another user. Please read more on the following section.

ip

The IP the user logged in from.

userEmail

The email of the user you have logged in with.

userName

The full name of the user you have logged in with.

userId

The ID of the user you have logged in with.

token

This is the most important field and contains the token you will need to use in any further call to the API. This token might expire, so you need to keep that in mind when coding your integration.

Once you have the token, you have to send it over the header of every request. For example:

GET /data/companies
> Accept: application/json
> token: eLJjYSjLUPLlIEe8lfJUOmzsVNvSRpOv

When the token expires (usually after 8 hours of inactivity, but could be less due to maintenance or other internal tasks) you will get a 401 error and you need to login again.

Impersonating other users

Developer users or users with the flag to manage groups have the ability to impersonate other users. In order to do that, when logging in the following body should be sent:

{
  "email": "manager@test.com",
  "password": "manager_password",
  "emailImpersonatedUser": "employee@test.com"
}

The response will be something like this:

{
  "app": "appname",
  "adminUserEmail": "manager@test.com",
  "ip": "::ffff:10.240.0.39",
  "userEmail": "employee@test.com",
  "userName": "Employee Test",
  "userId": "57fe52ade4b0ce322b0cea32",
  "token": "NE8lUuA2Yi9K6gL9EaQaTLIQLvYIhIyv"
}

You can notice that the adminUserEmail field contains now the email of the manager user that is impersonating employee@test.com.

Possible errors

Error code HTTP Status Code Description

unauthorized

401

Thrown when credentials are invalid. This can be either the user email does not exist or password does not match.

notFound

404

The user you are trying to impersonate does not exist.

forbidden

403

If credentials are valid but you are not allowed to log in. For example, this can happen when there are IP restrictions. Another case is that you are trying to impersonate a user and you don’t have enough permissions.

badRequest

400

Malformed request. For example, you didn’t provide email and password fields.

applicationUnavailable

503

If the application is suspended or in maintenance mode. Developer users should be able to log in anyway.

App data

For each entity in the app, a set of methods will be automatically created. For example if there is an entity called companies, the following methods will be available:

GET /data/companies
GET /data/companies/{id}
PUT /data/companies/{id}
POST /data/companies
DELETE /data/companies/{ids}

These are the basic operations for each entity that allow to list, read, update, create and delete records.

The content of the data will be dictated by the structure of the fields in the entity. For example getting a company record will return something like this:

{
  "id": "57fd2d65e4b0ce322b0c8665",
  "version": 379,
  "label": "Browsezoom",
  "name": "Browsezoom",
  "state": "pending",
  "type": "a",
  "numberOfEmployees": 95,
  "isCustomer": false,
  "contactInformation": {
    "phoneNumber": "1-702-845-9380",
    "email": "jwoodsrq@spotify.com",
    "id": "58837fdd3b063a0007603547",
    "label": "Contact Information"
  },
  "addresses": [
    {
      "addressLine": "4 Magdeline Place",
      "zipCode": "89145",
      "city": "Las Vegas",
      "state": "NV",
      "id": "57fd45aee4b0ce322b0c86aa",
      "label": "NV - 89145"
    }
  ],
  "homepage": "http://www.browsezoom.com",
  "taxId": "350-KWM",
  "rating": "2.8",
  "notes": "modified notes",
  "lastMeeting": 1429623180000,
  "lastUpdate": 1485012900000
}

There are basically two types of fields:

  • Record fields: these are the fields defined in the entity. The format for them depends on the type of the field. You should check the types documentation.
  • System fields: they are always there. These are:
    • id: the ID of the record.
    • label: this is the label of the record based on the instance label expression defined in the entity.
    • version: the version of the record that will be used for optimistic locking.

Basic operations

Read one record

GET /data/{entityName}/{id}

Reads one record by ID.

Request

GET /data/{entityName}/{id}
> Accept: application/json
> token: token


Parameter Required Default Description

entityName

yes

Name of the entity the record belongs to.

id

yes

ID of the record to fetch.

_fields

no

all

By default all fields will be fetched. If you want to specify which fields you want to fetch, you can pass this parameter. You can specify many fields separating them by commas:

_fields=name,type

System field will always be returned (id, version, etc.).

_format

no

native

The format to use to fetch the fields. There are two options: native and plainText. The first one show the raw value of each field. The second one, plainText, returns the values of the fields converted using the display option of each field.

_relationshipsToFetch

no

A comma-separated list of relationship fields that will be fetched within the record. For example if an entity has relationship fields named company and region, you could fetch those referenced records like this:

_relationshipsToFetch=company,region

Response

The JSON representation of the record is returned. More info about the format can be found here.

GET /data/{entityName}/{id}
< Content-Type: application/json

{
  "id": "57fd2d65e4b0ce322b0c8665",
  "version": 1,
  "label": "label",
  "fieldA": "value",
  "fieldB": "value"
  "fieldC": "value"
}

Possible errors

Error code HTTP Status Code Description

forbidden

403

Provided token does not have permissions to access this record.

notFound

404

Either entity or record ID does not exist.

Samples

fetches one company record

GET /data/companies/57fd2d65e4b0ce322b0c8665
> Accept: application/json
> token: token



GET /data/companies/57fd2d65e4b0ce322b0c8665
< Content-Type: application/json

{
  "id": "57fd2d65e4b0ce322b0c8665",
  "version": 379,
  "label": "Browsezoom",
  "name": "Browsezoom",
  "state": "pending",
  "type": "a",
  "numberOfEmployees": 95,
  "isCustomer": false,
  "contactInformation": {
    "phoneNumber": "1-702-845-9380",
    "email": "jwoodsrq@spotify.com",
    "id": "58837fdd3b063a0007603547",
    "label": "Contact Information"
  },
  "addresses": [
    {
      "addressLine": "4 Magdeline Place",
      "zipCode": "89145",
      "city": "Las Vegas",
      "state": "NV",
      "id": "57fd45aee4b0ce322b0c86aa",
      "label": "NV - 89145"
    }
  ],
  "homepage": "http://www.browsezoom.com",
  "taxId": "350-KWM",
  "rating": "2.8",
  "notes": "modified notes",
  "lastMeeting": 1429623180000,
  "lastUpdate": 1485012900000
}

List records

GET /data/{entityName}

Reads many records from one entity. You can specify filters and other options in the URL.

More information about queries can be found in Query language.

Request

GET /data/{entityName}
> Accept: application/json
> token: token


Parameter Required Default Description

entityName

yes

Name of the entity the record belongs to.

query parameters

no

You can find information about other parameters in Query language.

Response

A list of records in JSON representation will be returned.

GET /data/{entityName}
< Content-Type: application/json

{
  "total": 10,
  "offset": "57fd2d65e4b0ce322b0c8565",
  "items": [
    {
      "id": "57fd2d65e4b0ce322b0c8665",
      "version": 1,
      "label": "label",
      "fieldA": "value",
      "fieldB": "value"
    },
    {
      "id": "57fd2d65e4b0ce322b0c8565",
      "version": 1,
      "label": "label",
      "fieldA": "value",
      "fieldB": "value"
    }
  ]
}

Path Description

total

The total number of records matched. If there are more than the records returned, you should use pagination to fetch more records. See Limit size and Skip records.

offset

The offset to pass to get more records. Please see Skip records.

items

This is the list of records fetched. For more information about the format of records, please go here.

Possible errors

Error code HTTP Status Code Description

badRequest

400

Query is not valid.

forbidden

403

Provided token does not have permissions to access this entity or some of the fields you are querying by.

notFound

404

If entity name does not exist.

Samples

fetches fields name and type of two companies in pending status

GET /data/companies?state=pending&_fields=name,type&_size=2
> Accept: application/json
> token: token



GET /data/companies?state=pending&_fields=name,type&_size=2
< Content-Type: application/json

{
  "total": 135,
  "offset": "57fd2d65e4b0ce322b0c8565",
  "items": [
    {
      "id": "57fd2d65e4b0ce322b0c8665",
      "version": 379,
      "label": "Browsezoom",
      "name": "Browsezoom",
      "type": "a"
    },
    {
      "id": "57fd2d65e4b0ce322b0c8565",
      "version": 375,
      "label": "Blogpad",
      "name": "Blogpad",
      "type": "b"
    }
  ]
}

Create record

POST /data/{entityName}

Creates a new record for the given entity.

Data is sent in the body and should be valid according to the entity structure and fields rules.

Request

The body of this request should be a record in JSON format based on the entity structure.

All fields you are sending have to be present in the entity definition and values have to match the format required by the type (see Types). Also, there might be validation rules you have to take into account.

POST /data/{entityName}
> Content-Type: application/json
> Accept: application/json
> token: token

{
  "fieldA": "value",
  "fieldB": "value"
  "fieldC": 10,
  "nestedFields": [
    {
      "innerA": "value",
      "innerB": "value"
    },
    {
      "innerA": "value",
      "innerB": "value"
    }
  ]
}

Parameter Required Default Description

entityName

yes

Name of the entity the record will be added to.

Response

The response is the same as if you do a GET /data/companies/{id}, which means that you will be able to get the ID and label of the created record, as well as other calculated/default fields the entity might have.

You can find more information about the JSON format of a record here.

POST /data/{entityName}
< Content-Type: application/json

{
  "id": "588775f63b063a0007604f4c",
  "version": 0,
  "label": "label",
  "fieldA": "value",
  "fieldB": "value"
  "fieldC": 10,
  "nestedFields": [
    {
      "id": "588775f63b063a0007604f4c",
      "label": "label",
      "innerA": "value",
      "innerB": "value"
    },
    {
      "id": "588775f63b063a0007604f8a",
      "label": "label",
      "innerA": "value",
      "innerB": "value"
    }
  ],
  "calculatedField": "value"
}

Possible errors

Error code HTTP Status Code Description

validationErrors

400

If there are validations errors, the response will look like this:

{
  "code": "validationErrors",
  "message": "There are validation errors",
  "errors": [
    {
      "field": "name",
      "fieldLabel": "Name",
      "code": "required",
      "message": "This field is required",
      "additionalInfo": null
    },
    {
      "field": "state",
      "fieldLabel": "State",
      "code": "invalid",
      "message": "Not a valid choice",
      "additionalInfo": {
        "rejectedValue": "sdfsdfsd"
      }
    }
  ]
}

In this case you will get details information about the field having issues, the error code and a human readable description of the error. Additional information might be added depending on the type of error, for example the rejected value.

forbidden

403

Provided token does not have permissions to create records on this entity.

notFound

404

If entity name does not exist.

Samples

creates a new company

POST /data/companies
> Content-Type: application/json
> Accept: application/json
> token: token

{
  "name": "Test 1",
  "state": "pending",
  "type": "a",
  "numberOfEmployees": 95,
  "isCustomer": false,
  "contactInformation": {
    "phoneNumber": "1-702-845-9380",
    "email": "jwoodsrq@spotify.com"
  },
  "addresses": [
    {
      "addressLine": "4 Magdeline Place",
      "zipCode": "89145",
      "city": "Las Vegas",
      "state": "NV"
    }
  ],
  "homepage": "http://www.browsezoom.com",
  "taxId": "350-KWM",
  "rating": "2.8",
  "notes": "test notes",
  "lastMeeting": 1429623180000
}


POST /data/companies
< Content-Type: application/json

{
  "id": "588775f63b063a0007604f4c",
  "version": 0,
  "label": "Test 1",
  "name": "Test 1",
  "state": "pending",
  "type": "a",
  "numberOfEmployees": 95,
  "isCustomer": false,
  "contactInformation": {
    "phoneNumber": "1-702-845-9380",
    "email": "jwoodsrq@spotify.com",
    "id": "588775f63b063a0007604f4a",
    "label": "Contact Information"
  },
  "addresses": [
    {
      "addressLine": "4 Magdeline Place",
      "zipCode": "89145",
      "city": "Las Vegas",
      "state": "NV",
      "id": "588775f63b063a0007604f4b",
      "label": "NV - 89145"
    }
  ],
  "homepage": "http://www.browsezoom.com",
  "taxId": "350-KWM",
  "rating": "2.8",
  "notes": "test notes",
  "lastMeeting": 1429623180000,
  "lastUpdate": 1485272566096
}

Update record

PUT /data/{entityName}/{id}

Updates a record data.

Data is sent in the body and should be valid according to the entity structure and fields rules.

Request

The body of this request should be a record in JSON format based on the entity structure.

All fields you are sending have to be present in the entity definition and values have to match the format required by the type (see Types). Also, there might be validation rules you have to take into account.

You can specify only the fields you want to set. Fields that are not included won’t be modified (if you want to clear a field value, set them to null explicitly).

One important thing to mention here is the field version, which indicates the version of the record you are updating. This is to handle concurrency issues when two users try to update the same record at the same time (read the optimistic locking section below). If you don’t provide the version field then you will always write the data, no matter if you are overriding other user’s data.

PUT /data/{entityName}/{id}
> Content-Type: application/json
> Accept: application/json
> token: token

{
  "version": 1,
  "fieldA": "newValue",
  "fieldB": "newValue",
  "nestedFields": [
    {
      "id": "588775f63b063a0007604f4c",
      "innerA": "newValue"
    },
    {
      "id": "588775f63b063a0007604f8a",
      "innerB": "newValue"
    }
  ]
}

Parameter Required Default Description

entityName

yes

Name of the entity the record belongs to.

id

yes

The ID of the record to update. If you provide the ID on the body it will be discarded and the ID sent in the URL parameter will be used.

Response

The response is the same as if you do a GET /data/companies/{id}, which means that you will be able to get the ID and label of the updated record, as well as other calculated/default fields the entity might have.

PUT /data/{entityName}/{id}
< Content-Type: application/json

{
  "id": "588775f63b063a0007604ab2",
  "version": 0,
  "label": "label",
  "fieldA": "newValue",
  "fieldB": "newValue"
  "fieldC": 10,
  "nestedFields": [
    {
      "id": "588775f63b063a0007604f4c",
      "label": "label",
      "innerA": "newValue",
      "innerB": "value"
    },
    {
      "id": "588775f63b063a0007604f8a",
      "label": "label",
      "innerA": "value",
      "innerB": "newValue"
    }
  ],
  "calculatedField": "value"
}

Possible errors

Error code HTTP Status Code Description

validationErrors

400

If there are validations errors, the response will look like this:

{
  "code": "validationErrors",
  "message": "There are validation errors",
  "errors": [
    {
      "field": "name",
      "fieldLabel": "Name",
      "code": "required",
      "message": "This field is required",
      "additionalInfo": null
    },
    {
      "field": "state",
      "fieldLabel": "State",
      "code": "invalid",
      "message": "Not a valid choice",
      "additionalInfo": {
        "rejectedValue": "sdfsdfsd"
      }
    }
  ]
}

In this case you will get details information about the field having issues, the error code and a human readable description of the error. Additional information might be added depending on the type of error, for example the rejected value.

forbidden

403

Provided token does not have permissions to edit records on this entity or you don’t have permissions to edit this particular record.

notFound

404

If entity name or record ID does not exist.

optimisticLocking

409

If another user modified the data in the middle. This can be determined only if you provide the version field.

Samples

updates a few fields in a company record

PUT /data/companies/588775f63b063a0007604f4c
> Content-Type: application/json
> Accept: application/json
> token: token

{
  "version": 1,
  "state": "active",
  "type": "b",
  "numberOfEmployees": 100
}


PUT /data/companies/588775f63b063a0007604f4c
< Content-Type: application/json

{
  "id": "588775f63b063a0007604f4c",
  "version": 2,
  "label": "Test 1",
  "name": "Test 1",
  "state": "active",
  "type": "b",
  "numberOfEmployees": 100,
  "isCustomer": false,
  "contactInformation": {
    "phoneNumber": "1-702-845-9380",
    "email": "jwoodsrq@spotify.com",
    "id": "588775f63b063a0007604f4a",
    "label": "Contact Information"
  },
  "addresses": [
    {
      "addressLine": "4 Magdeline Place",
      "zipCode": "89145",
      "city": "Las Vegas",
      "state": "NV",
      "id": "588775f63b063a0007604f4b",
      "label": "NV - 89145"
    }
  ],
  "homepage": "http://www.browsezoom.com",
  "taxId": "350-KWM",
  "rating": "2.8",
  "notes": "test notes",
  "lastMeeting": 1429623180000,
  "lastUpdate": 1485288240000
}

Delete one record

DELETE /data/{entityName}/{id}

Deletes a record from the database. You won’t be able to recover the deleted record (except that you have enabled history for that entity).

Request

DELETE /data/{entityName}/{id}
> Accept: application/json
> token: token


Parameter Required Default Description

entityName

yes

Name of the entity the record belongs to.

id

yes

ID of the record to delete.

async

no

Indicates if the delete has to be executed in the background, which is needed if the execution is going to take more than 30 seconds.

When setting this parameter to true the response of this method will be a reference to the job in charge of executing the deletion.

Response

The response will be different based on the parameter async. There are two possible responses:

  • Record: if the async parameter is false, then the deleted record is returned by this method.
  • Job reference: if the async parameter is true, the method will return a reference to the job in charge of the execution of the delete process. Once the job is completed you will find the response of the process in the results of the job.

You can find samples for each type of response below.

Possible errors

Error code HTTP Status Code Description

forbidden

403

Provided token does not have permissions to delete this record.

notFound

404

Either entity or record ID does not exist.

Samples

deletes one company

DELETE /data/companies/588775f63b063a0007604f4c
> Accept: application/json
> token: token



DELETE /data/companies/588775f63b063a0007604f4c
< Content-Type: application/json

{
  "id": "588775f63b063a0007604f4c",
  "version": 10,
  "label": "Test 1",
  "name": "Test 1",
  "state": "active",
  "type": "b",
  "numberOfEmployees": 100,
  "isCustomer": false,
  "contactInformation": {
    "phoneNumber": "1-702-845-9380",
    "email": "jwoodsrq@spotify.com",
    "id": "588775f63b063a0007604f4a",
    "label": "Contact Information"
  },
  "addresses": [
    {
      "addressLine": "4 Magdeline Place",
      "zipCode": "89145",
      "city": "Las Vegas",
      "state": "NV",
      "id": "588775f63b063a0007604f4b",
      "label": "NV - 89145"
    }
  ],
  "homepage": "http://www.browsezoom.com",
  "taxId": "350-KWM",
  "rating": "2.8",
  "notes": "test notes",
  "lastMeeting": 1429623180000,
  "lastUpdate": 1485288240000
}

deletes one company in the background

DELETE /data/companies/588775f63b063a0007604f4c?_async=true
> Accept: application/json
> token: token



DELETE /data/companies/588775f63b063a0007604f4c?_async=true
< Content-Type: application/json

{
  "jobLink": "/api/status/jobs/5887b6f23b063a0007604fa8",
  "jobId": "5887b6f23b063a0007604fa8"
}

Delete many records

DELETE /data/{entityName}/{ids}

Deletes many records from the database. You won’t be able to recover deleted records (except that you have enabled history for that entity).

This method will return immediately but a job will be created to delete the records in the background. You can check the status of the job to verify when it finishes.

Request

DELETE /data/{entityName}/{ids}
> Accept: application/json
> token: token


Parameter Required Default Description

entityName

yes

Name of the entity records belongs to.

ids

yes

IDs of records to delete separated by commas.

_async

no

Indicates if the delete has to be executed in the background, which is needed if the execution is going to take more than 30 seconds or you want to delete more than 1,000 records.

When setting this parameter to true the response of this method will be a reference to the job in charge of executing the deletion.

Response

The response will be different based on the parameter _async. There are two possible responses:

  • A map with records: if the _async parameter is false, then the result will be a map with the ID of the record as the key and the value will be a map with the fields status and response (the deleted record as a JSON) or errorMessage if there was an error.
  • Job reference: if the _async parameter is true, the method will return a reference to the job in charge of the execution of the delete process. Once the job is completed you will find the response of the process in the results of the job.

You can find samples for each type of response below.

Possible errors

Error code HTTP Status Code Description

forbidden

403

Provided token does not have permissions to delete records on this entity.

notFound

404

If the entity name does not exist.

Samples

deletes two companies

DELETE /data/companies/57fd2d65e4b0ce322b0c8665,57fd2d65e4b0ce322b0c8565
> Accept: application/json
> token: token



DELETE /data/companies/57fd2d65e4b0ce322b0c8665,57fd2d65e4b0ce322b0c8565
< Content-Type: application/json

{
  "57fd2d65e4b0ce322b0c8665": {
    "status": "ok",
    "response": {
      "id": "57fd2d65e4b0ce322b0c8665",
      "version": 381,
      "label": "Browsezoom",
      "entity": {
        "id": "57fce228e4b0f6600fdfb836",
        "name": "Companies"
      },
      "name": "Browsezoom",
      "state": "pending",
      "type": "a",
      "numberOfEmployees": 95,
      "isCustomer": false,
      "contactInformation": {
        "id": "58837fdd3b063a0007603547",
        "label": "Contact Information"
        "phoneNumber": "1-702-845-9380",
        "email": "jwoodsrq@spotify.com"
      },
      "addresses": [
        {
          "id": "57fd45aee4b0ce322b0c86aa",
          "label": "NV - 89145",
          "addressLine": "4 Magdeline Place",
          "zipCode": "89145",
          "city": "Las Vegas",
          "state": "NV"
        }
      ],
      "homepage": "http://www.browsezoom.com",
      "taxId": "350-KWM",
      "rating": "2.8",
      "notes": "modified notes",
      "lastMeeting": 1429623180000,
      "lastUpdate": 1485292080000
    }
  },
  "57fd2d65e4b0ce322b0c8565": {
    "status": "ok",
    "response": {
      "id": "57fd2d65e4b0ce322b0c8565",
      "version": 377,
      "label": "Blogpad",
      "name": "Blogpad",
      "state": "pending",
      "type": "b",
      "numberOfEmployees": 534,
      "isCustomer": false,
      "contactInformation": {
        "id": "581224c8e4b0285870237cc5",
        "label": "Contact Information",
        "phoneNumber": "1-405-298-5885",
        "email": "molsonre@rakuten.co.jp"
      },
      "addresses": [
        {
          "id": "57fd45aee4b0ce322b0c86ac",
          "label": "OK - 73157",
          "addressLine": "4 Crownhardt Plaza",
          "zipCode": "73157",
          "city": "Oklahoma City",
          "state": "OK"
        }
      ],
      "homepage": "http://www.blogpad.com",
      "taxId": "123-ABC",
      "rating": "3.3",
      "notes": "Aenean fermentum. Donec ut mauris eget massa tempor convallis. Nulla neque libero, convallis eget, eleifend luctus, ultricies eu, nibh.",
      "lastMeeting": 1422111300000,
      "lastUpdate": 1485292500000
    }
  }
}

deletes two companies in the background

DELETE /data/companies/588775f63b063a0007604f4c,588775f63b063a0007604f8b?_async=true
> Accept: application/json
> token: token



DELETE /data/companies/588775f63b063a0007604f4c,588775f63b063a0007604f8b?_async=true
< Content-Type: application/json

{
  "jobLink": "/api/status/jobs/5887b6f23b063a0007604fa8",
  "jobId": "5887b6f23b063a0007604fa8"
}

Delete records over query

DELETE /data/{entityName}

Deletes all records matched by a query. You won’t be able to recover deleted records (except that you have enabled history for that entity).

This method will return immediately but a job will be created to delete the records in the background. You can check the status of the job to verify when it finishes.

Request

DELETE /data/{entityName}
> Accept: application/json
> token: token


Parameter Required Default Description

entityName

yes

Name of the entity records belongs to.

query parameters

no

These are the query parameters. See Query language for more information.

_async

no

Indicates if the delete has to be executed in the background, which is needed if the execution is going to take more than 30 seconds or you want to delete more than 1,000 records.

When setting this parameter to true the response of this method will be a reference to the job in charge of executing the deletion.

_lowPriority

no

Sets job as low priority will make the deletion only happen when there are no many jobs running.

_triggerEvents

no

true

If false events of deletion won’t be triggered.

_cascadeOperations

no

true

If false cascade update to update relationship fields or aggregate fields won’t be executed.

Response

The response will be different based on the parameter _async. There are two possible responses:

  • A map with records: if the _async parameter is false, then the result will be a map with the ID of the record as the key and the value will be a map with the fields status and response (the deleted record as a JSON) or errorMessage if there was an error.
  • Job reference: if the _async parameter is true, the method will return a reference to the job in charge of the execution of the delete process. Once the job is completed you will find the response of the process in the results of the job.

You can find samples for each type of response below.

Possible errors

Error code HTTP Status Code Description

forbidden

403

Provided token does not have permissions to delete records on this entity.

notFound

404

If the entity name does not exist.

Samples

deletes companies with type 'a'

DELETE /data/companies?type=a
> Accept: application/json
> token: token



DELETE /data/companies?type=a
< Content-Type: application/json

{
  "57fd2d65e4b0ce322b0c8665": {
    "status": "ok",
    "response": {
      "id": "57fd2d65e4b0ce322b0c8665",
      "version": 381,
      "label": "Browsezoom",
      "entity": {
        "id": "57fce228e4b0f6600fdfb836",
        "name": "Companies"
      },
      "name": "Browsezoom",
      "state": "pending",
      "type": "a",
      "numberOfEmployees": 95,
      "isCustomer": false,
      "contactInformation": {
        "id": "58837fdd3b063a0007603547",
        "label": "Contact Information"
        "phoneNumber": "1-702-845-9380",
        "email": "jwoodsrq@spotify.com"
      },
      "addresses": [
        {
          "id": "57fd45aee4b0ce322b0c86aa",
          "label": "NV - 89145",
          "addressLine": "4 Magdeline Place",
          "zipCode": "89145",
          "city": "Las Vegas",
          "state": "NV"
        }
      ],
      "homepage": "http://www.browsezoom.com",
      "taxId": "350-KWM",
      "rating": "2.8",
      "notes": "modified notes",
      "lastMeeting": 1429623180000,
      "lastUpdate": 1485292080000
    }
  }
}

deletes companies with type 'a' in the background

DELETE /data/companies?_async=true&type=a
> Accept: application/json
> token: token



DELETE /data/companies?_async=true&type=a
< Content-Type: application/json

{
  "jobLink": "/api/status/jobs/5887b6f23b063a0007604fa8",
  "jobId": "5887b6f23b063a0007604fa8"
}

Optimistic locking

Optimistic locking is a feature that helps to avoid overwriting changes made by other users in a record. To do that it uses the record version, which is a number that increases every time there is a change in a record.

When updating a record, if you send the field version as part of the body, and that version doesn’t match the version of the record in the server, a 409 error will be returned. This prevents changes made by other users to be overwritten.

If the field version is not sent, then no version control will be done and you might end up overwriting changes from other users, so it is strongly recommended to use it when updating records.

Aggregate queries

PUT /data/{entityName}/aggregate

You can perform aggregation operations like count, sum or average.

For detailed documentation please check Aggregate queries.

Request

The request’s body contains the chain of operations to execute over the entity records. For more information please check documentation for Aggregate queries.

PUT /data/{entityName}/aggregate
> Content-Type: application/json
> Accept: application/json
> token: token

[
  {"operation1": "settings"},
  {"operation2": "settings"},
  {"operationN": "settings"}
]

Parameter Required Default Description

entityName

yes

Name of the entity the record belongs to.

Response

The result of the aggregation is returned. The format is specific to the aggregation done, so please check the documentation for Aggregate queries.

Possible errors

Error code HTTP Status Code Description

badRequest

400

Aggregation query is not valid.

forbidden

403

You are trying to aggregate data you don’t have permissions to read. This applies at the entity level, record level and field level.

Samples

counts the number of skills per company

PUT /data/contacts/aggregate
> Content-Type: application/json
> Accept: application/json
> token: token

[
  {"project": "company,numberOfSkills"},
  {"group": {"by": "company", "totalSkills": "sum(numberOfSkills)"}}
]


PUT /data/contacts/aggregate
< Content-Type: application/json

{
  "total": 6,
  "items": [
    {
      "company": "Trudoo",
      "totalSkills": 1
    },
    {
      "company": "Riffwire",
      "totalSkills": 3
    },
    {
      "company": "Snaptags",
      "totalSkills": 2
    },
    {
      "company": "Edgeify",
      "totalSkills": 0
    },
    {
      "company": "Flipopia",
      "totalSkills": 3
    },
    {
      "company": "Rooxo",
      "totalSkills": 4
    }
  }
]

Actions

Execute action over one record

PUT /data/{entityName}/{id}/{actionName}

Execute an action over one record.

Request

If the action contains parameters, you can send them in the body. The format is the same as when you create or update records, but instead of fields you should send parameters of the action.

If the action doesn’t have parameters you can leave the body empty.

PUT /data/{entityName}/{id}/{actionName}
> Content-Type: application/json
> Accept: application/json
> token: token

{
  "param1": "value",
  "param2": value
}

Parameter Required Default Description

entityName

yes

Name of the entity the record belongs to.

id

yes

ID of the record to execute the action on.

actionName

yes

The name of the action that has to be executed.

_async

no

Indicates if the action has to be executed in the background, which is needed if the execution is going to take more than 30 seconds.

When setting this parameter to true the response of this method will be a reference to the job in charge of executing the action.

This parameter will override the default configured in the action.

Response

The response will be different based on the type of action and the parameter _async. There are three possible responses:

  • Record: if the _async parameter is false and the action doesn’t return any custom response, then the updated record is returned by this method. This only applies for actions of type One record.
  • Custom action’s response: if the _async parameter is false and the action returns a custom response, then that response is returned. Keep in mind that actions of type Many records should always return a custom response. If they don’t return anything, an empty response will be returned.
  • Job reference: if the _async parameter is true, the method will return a reference to the job in charge of the execution of the action. Once the action is completed you will find the response of the action in the results of the job.

You can find samples for each type of response below.

Possible errors

Error code HTTP Status Code Description

badRequest

400

If request is not allowed. For example, pre-conditions in the actions are not met.

forbidden

403

You don’t have permissions to execute the action or you don’t have permissions for the record.

notFound

404

The entity name or the record does not exist.

Samples

executes a simple action over a company record, no custom response

PUT /data/companies/57fd2d65e4b0ce322b0c8665/logSomething
> Content-Type: application/json
> Accept: application/json
> token: token

{
    "param1": "a",
    "param2": "b"
}


PUT /data/companies/57fd2d65e4b0ce322b0c8665/logSomething
< Content-Type: application/json

{
  "id": "57fd2d65e4b0ce322b0c8665",
  "version": 381,
  "label": "Browsezoom",
  "name": "Browsezoom",
  "state": "pending",
  "type": "a",
  "numberOfEmployees": 95,
  "isCustomer": false,
  "contactInformation": {
    "id": "58837fdd3b063a0007603547",
    "label": "Contact Information",
    "phoneNumber": "1-702-845-9380",
    "email": "jwoodsrq@spotify.com",
  },
  "addresses": [
    {
      "id": "57fd45aee4b0ce322b0c86aa",
      "label": "NV - 89145",
      "addressLine": "4 Magdeline Place",
      "zipCode": "89145",
      "city": "Las Vegas",
      "state": "NV"
    }
  ],
  "homepage": "http://www.browsezoom.com",
  "taxId": "350-KWM",
  "rating": "2.8",
  "notes": "modified notes",
  "lastMeeting": 1429623180000,
  "lastUpdate": 1485292080000
}

executes a simple action over a company record in the background, no custom response

PUT /data/companies/57fd2d65e4b0ce322b0c8665/logSomething?_async=true
> Content-Type: application/json
> Accept: application/json
> token: token

{
    "param1": "a",
    "param2": "b"
}


PUT /data/companies/57fd2d65e4b0ce322b0c8665/logSomething?_async=true
< Content-Type: application/json

{
  "jobLink": "/api/status/jobs/588f3e65b45fc9000bc1baa7",
  "jobId": "588f3e65b45fc9000bc1baa7"
}

executes an action that works with many records and returns a custom response

PUT /data/companies/57fd2d65e4b0ce322b0c8665/countEmployees
> Content-Type: application/json
> Accept: application/json
> token: token



PUT /data/companies/57fd2d65e4b0ce322b0c8665/countEmployees
< Content-Type: application/json

{
    "numberOfEmployees": 95
}

Execute action over many records

PUT /data/{entityName}/{ids}/{actionName}

Execute an action over many records. The action will be executed in each record one by one if the action is of type One record.

Request

If the action contains parameters, you can send them in the body. The format is the same as when you create or update records, but instead of fields you should send parameters of the action.

If the action doesn’t have parameters you can leave the body empty.

PUT /data/{entityName}/{ids}/{actionName}
> Content-Type: application/json
> Accept: application/json
> token: token

{
  "param1": "value",
  "param2": value
}

Parameter Required Default Description

entityName

yes

Name of the entity the records belongs to.

ids

yes

IDs of records to execute the action on separated by commas.

actionName

yes

The name of the action that has to be executed.

_async

no

Indicates if the action has to be executed in the background, which is needed if the execution is going to take more than 30 seconds or if it is applied over more than 1,000 records.

When setting this parameter to true the response of this method will be a reference to the job in charge of executing the action.

This parameter will override the default configured in the action.

Response

The response will be different based on the type of action and the parameter _async. There are three possible responses:

  • A map with records: if the _async parameter is false and the action doesn’t return any custom response, then the result will be a map with the ID of the record as the key and the value will be a map with the fields status and response (the record as a JSON) or errorMessage if there was an error. This only applies for actions of type One record.
  • Custom action’s responses: if the _async parameter is false and the action returns a custom response, then a map with the ID of the record (for each record) as key and a map with the status (“ok” or “error”) and response with the custom response will be returned. Keep in mind that actions of type Many records should always return a custom response. If they don’t return anything, an empty response will be returned.
  • Job reference: if the _async parameter is true, the method will return a reference to the job in charge of the execution of the action. Once the action is completed you will find the response of the action in the results of the job.

You can find samples for each type of response below.

Possible errors

Error code HTTP Status Code Description

forbidden

403

You don’t have permissions to execute the action.

notFound

404

If the entity name does not exist.

Samples

executes a simple action over two company records, no custom response

PUT /data/companies/57fd2d65e4b0ce322b0c8665,57fd2d65e4b0ce322b0c8565/logSomething
> Content-Type: application/json
> Accept: application/json
> token: token

{
    "param1": "a",
    "param2": "b"
}


PUT /data/companies/57fd2d65e4b0ce322b0c8665,57fd2d65e4b0ce322b0c8565/logSomething
< Content-Type: application/json

{
  "57fd2d65e4b0ce322b0c8665": {
    "status": "ok",
    "response": {
      "id": "57fd2d65e4b0ce322b0c8665",
      "version": 381,
      "label": "Browsezoom",
      "entity": {
        "id": "57fce228e4b0f6600fdfb836",
        "name": "Companies"
      },
      "name": "Browsezoom",
      "state": "pending",
      "type": "a",
      "numberOfEmployees": 95,
      "isCustomer": false,
      "contactInformation": {
        "id": "58837fdd3b063a0007603547",
        "label": "Contact Information"
        "phoneNumber": "1-702-845-9380",
        "email": "jwoodsrq@spotify.com"
      },
      "addresses": [
        {
          "id": "57fd45aee4b0ce322b0c86aa",
          "label": "NV - 89145",
          "addressLine": "4 Magdeline Place",
          "zipCode": "89145",
          "city": "Las Vegas",
          "state": "NV"
        }
      ],
      "homepage": "http://www.browsezoom.com",
      "taxId": "350-KWM",
      "rating": "2.8",
      "notes": "modified notes",
      "lastMeeting": 1429623180000,
      "lastUpdate": 1485292080000
    }
  },
  "57fd2d65e4b0ce322b0c8565": {
    "status": "ok",
    "response": {
      "id": "57fd2d65e4b0ce322b0c8565",
      "version": 377,
      "label": "Blogpad",
      "name": "Blogpad",
      "state": "pending",
      "type": "b",
      "numberOfEmployees": 534,
      "isCustomer": false,
      "contactInformation": {
        "id": "581224c8e4b0285870237cc5",
        "label": "Contact Information",
        "phoneNumber": "1-405-298-5885",
        "email": "molsonre@rakuten.co.jp"
      },
      "addresses": [
        {
          "id": "57fd45aee4b0ce322b0c86ac",
          "label": "OK - 73157",
          "addressLine": "4 Crownhardt Plaza",
          "zipCode": "73157",
          "city": "Oklahoma City",
          "state": "OK"
        }
      ],
      "homepage": "http://www.blogpad.com",
      "taxId": "123-ABC",
      "rating": "3.3",
      "notes": "Aenean fermentum. Donec ut mauris eget massa tempor convallis. Nulla neque libero, convallis eget, eleifend luctus, ultricies eu, nibh.",
      "lastMeeting": 1422111300000,
      "lastUpdate": 1485292500000
    }
  }
}

executes a simple action over two company records with custom response

PUT /data/companies/57fd2d65e4b0ce322b0c8665,57fd2d65e4b0ce322b0c8565/customResponse
> Content-Type: application/json
> Accept: application/json
> token: token



PUT /data/companies/57fd2d65e4b0ce322b0c8665,57fd2d65e4b0ce322b0c8565/customResponse
< Content-Type: application/json

{
  "57fd2d65e4b0ce322b0c8665": {
      "status": "ok",
      "response": "This is a custom response"
  },
  "57fd2d65e4b0ce322b0c8565": {
      "status": "ok",
      "response": "This is a custom response"
  }
}

executes a simple action over two company records in the background

PUT /data/companies/57fd2d65e4b0ce322b0c8665,57fd2d65e4b0ce322b0c8565/logSomething?_async=true
> Content-Type: application/json
> Accept: application/json
> token: token

{
    "param1": "a",
    "param2": "b"
}


PUT /data/companies/57fd2d65e4b0ce322b0c8665,57fd2d65e4b0ce322b0c8565/logSomething?_async=true
< Content-Type: application/json

{
  "jobLink": "/api/status/jobs/588f45e2b45fc9000bc1bd1f",
  "jobId": "588f45e2b45fc9000bc1bd1f"
}

executes an action that works with many records over two records and returns a custom response

PUT /data/companies/57fd2d65e4b0ce322b0c8665,57fd2d65e4b0ce322b0c8565/countEmployees
> Content-Type: application/json
> Accept: application/json
> token: token



PUT /data/companies/57fd2d65e4b0ce322b0c8665,57fd2d65e4b0ce322b0c8565/countEmployees
< Content-Type: application/json

{
    "numberOfEmployees": 629
}

Execute action over query

PUT /data/{entityName}/{actionName}

Execute an action over records matched by a query.

Request

If the action contains parameters, you can send them in the body. The format is the same as when you create or update records, but instead of fields you should send parameters of the action.

If the action doesn’t have parameters you can leave the body empty.

PUT /data/{entityName}/{actionName}
> Content-Type: application/json
> Accept: application/json
> token: token

{
  "param1": "value",
  "param2": value
}

Parameter Required Default Description

entityName

yes

Name of the entity the records belongs to.

ids

yes

IDs of records to execute the action on separated by commas.

actionName

yes

The name of the action that has to be executed.

_async

no

Indicates if the action has to be executed in the background, which is needed if the execution is going to take more than 30 seconds or if it is applied over more than 1,000 records.

When setting this parameter to true the response of this method will be a reference to the job in charge of executing the action.

This parameter will override the default configured in the action.

query parameters

no

These are the query parameters. See Query language for more information.

Response

The response will be different based on the type of action and the parameter _async. There are three possible responses:

  • A map with records: if the _async parameter is false and the action doesn’t return any custom response, then a map with the ID of the records as key and the JSON of the records as value will be returned. This only applies for actions of type One record.
  • Custom action’s responses: if the _async parameter is false and the action returns a custom response, then a map with the ID of the record (for each record) as key and a map with the status (“ok” or “error”) and response with the custom response will be returned. Keep in mind that actions of type Many records should always return a custom response. If they don’t return anything, an empty response will be returned.
  • Job reference: if the _async parameter is true, the method will return a reference to the job in charge of the execution of the action. Once the action is completed you will find the response of the action in the results of the job.

You can find samples for each type of response below.

Possible errors

Error code HTTP Status Code Description

forbidden

403

You don’t have permissions to execute the action.

notFound

404

If the entity name does not exist.

Samples

executes a simple action over two company records, no custom response

PUT /data/companies/logSomething?id=57fd2d65e4b0ce322b0c8665,57fd2d65e4b0ce322b0c8565
> Content-Type: application/json
> Accept: application/json
> token: token

{
    "param1": "a",
    "param2": "b"
}


PUT /data/companies/logSomething?id=57fd2d65e4b0ce322b0c8665,57fd2d65e4b0ce322b0c8565
< Content-Type: application/json

{
  "57fd2d65e4b0ce322b0c8665": {
    "status": "ok",
    "response": {
      "id": "57fd2d65e4b0ce322b0c8665",
      "version": 381,
      "label": "Browsezoom",
      "entity": {
        "id": "57fce228e4b0f6600fdfb836",
        "name": "Companies"
      },
      "name": "Browsezoom",
      "state": "pending",
      "type": "a",
      "numberOfEmployees": 95,
      "isCustomer": false,
      "contactInformation": {
        "phoneNumber": "1-702-845-9380",
        "email": "jwoodsrq@spotify.com",
        "id": "58837fdd3b063a0007603547",
        "label": "Contact Information"
      },
      "addresses": [
        {
          "addressLine": "4 Magdeline Place",
          "zipCode": "89145",
          "city": "Las Vegas",
          "state": "NV",
          "id": "57fd45aee4b0ce322b0c86aa",
          "label": "NV - 89145"
        }
      ],
      "homepage": "http://www.browsezoom.com",
      "taxId": "350-KWM",
      "rating": "2.8",
      "notes": "modified notes",
      "lastMeeting": 1429623180000,
      "lastUpdate": 1485292080000
    }
  },
  "57fd2d65e4b0ce322b0c8565": {
    "status": "ok",
    "response": {
      "id": "57fd2d65e4b0ce322b0c8565",
      "version": 377,
      "label": "Blogpad",
      "name": "Blogpad",
      "state": "pending",
      "type": "b",
      "numberOfEmployees": 534,
      "isCustomer": false,
      "contactInformation": {
        "phoneNumber": "1-405-298-5885",
        "email": "molsonre@rakuten.co.jp",
        "id": "581224c8e4b0285870237cc5",
        "label": "Contact Information"
      },
      "addresses": [
        {
          "addressLine": "4 Crownhardt Plaza",
          "zipCode": "73157",
          "city": "Oklahoma City",
          "state": "OK",
          "id": "57fd45aee4b0ce322b0c86ac",
          "label": "OK - 73157"
        }
      ],
      "homepage": "http://www.blogpad.com",
      "taxId": "123-ABC",
      "rating": "3.3",
      "notes": "Aenean fermentum. Donec ut mauris eget massa tempor convallis. Nulla neque libero, convallis eget, eleifend luctus, ultricies eu, nibh.",
      "lastMeeting": 1422111300000,
      "lastUpdate": 1485292500000
    }
  }
}

executes a simple action over two company records with custom response

PUT /data/companies/customResponse?id=57fd2d65e4b0ce322b0c8665,57fd2d65e4b0ce322b0c8565
> Content-Type: application/json
> Accept: application/json
> token: token



PUT /data/companies/customResponse?id=57fd2d65e4b0ce322b0c8665,57fd2d65e4b0ce322b0c8565
< Content-Type: application/json

{
  "57fd2d65e4b0ce322b0c8665": {
      "status": "ok",
      "response": "This is a custom response"
  },
  "57fd2d65e4b0ce322b0c8565": {
      "status": "ok",
      "response": "This is a custom response"
  }
}

executes a simple action over two company records in the background

PUT /data/companies/logSomething?_async=true&id=57fd2d65e4b0ce322b0c8665,57fd2d65e4b0ce322b0c8565
> Content-Type: application/json
> Accept: application/json
> token: token

{
    "param1": "a",
    "param2": "b"
}


PUT /data/companies/logSomething?_async=true&id=57fd2d65e4b0ce322b0c8665,57fd2d65e4b0ce322b0c8565
< Content-Type: application/json

{
  "jobLink": "/api/status/jobs/588f45e2b45fc9000bc1bd1f",
  "jobId": "588f45e2b45fc9000bc1bd1f"
}

executes an action that works with many records over two records and returns a custom response

PUT /data/companies/countEmployees?id=57fd2d65e4b0ce322b0c8665,57fd2d65e4b0ce322b0c8565
> Content-Type: application/json
> Accept: application/json
> token: token



PUT /data/companies/countEmployees?id=57fd2d65e4b0ce322b0c8665,57fd2d65e4b0ce322b0c8565
< Content-Type: application/json

{
    "numberOfEmployees": 629
}

Import records

POST /data/{entityName}/import

Imports records from a CSV file.

Request

Imports records from a CSV file. The CSV file should follow these rules:

  • Headers: they have to be the path of the field you want to import. For example a field at the root of the entity called name should have name as header. If there is a nested field you should put the full path, like address.state. For multi-valued fields you need to put the index, for example phoneNumbers[0] or phoneNumbers[1].
  • Data format: based on the type of the field you need to use different formats. Please check the documentation for each type.

Usually an easy way to get a template of the CSV file is by exporting existing records using fields’ names instead of labels.

Records will be created if they didn’t exist. If they already exist, they will be updated. In order to determine if the record exists a unique field must be in the headers. If there are many the first one will be used.

It is also possible to import records in related entities as well. For example you have a contacts entity that has a relationship called company that points to the companies entity. Then you could have the following headers in the CSV file:

company.name,company.type,firstName,lastName,email

So headers company.name and company.type are fields in the companies entity. The import process will try to match an existing company by name (assuming name is a unique field) and will update its type field. If there is no match, a new record will be created in companies and will be associated to the record in contacts. In this way you can create records in many entities with just one import.

The import will happen in a background job.

POST /data/{entityName}/import
> Content-Type: multipart/form-data
> Accept: application/json
> token: token


Parameter Required Default Description

entityName

yes

Name of the entity the record belongs to.

file

yes

this is a multi-part with the CSV file to import.

lowPriority

no

The import will be done only when there aren’t many other jobs running at the same time. This is important for big imports if you don’t want to delay other jobs.

updateCalculatedFields

no

true

In order to speed up big imports you can decide to skip calculated fields. This means calculated fields might not have the correct value but you can calculate them later.

This options is only available for developers.

updateRelationships

no

true

If the import updates the label of the record and the record was referenced by another record, a cascade update will be done to update the label in the reference. If you want to speed up big imports you might decide to disable this feature.

This options is only available for developers.

performValidations

no

true

If you send false validations will be skipped. These are type rules validations only. Structure and data format validations will still be done as they are required. For example in an integer field the validation about the max and min value could be skipped, but the value should be a number.

This options is only available for developers.

filterByAccessRules

no

true

Indicates if fields should be filtered by access rules. If disabled all fields will be imported no matter if they are accessible or not. Disabling this feature might have a slight performance improvement during imports.

This options is only available for developers.

performSecurityChecks

no

true

If set to false, permissions will be skipped. This could help to improve performance or avoid some issues during imports.

This options is only available for developers.

triggerEvents

no

true

There could be listeners for events associated to the creation or update of records. If this flag is set to false those listeners won’t be executed.

This options is only available for developers.

setDefaultValues

no

true

If set to false, default values won’t be calculated for fields, which could help to improve performance on big imports.

This options is only available for developers.

supportTransientFields

no

true

If set to false transiente fields won’t be managed as transient. This could help to improve performance on big imports.

This options is only available for developers.

cascadeOperations

no

true

Updating or creating records through imports could trigger many cascade operation to update copied fields, aggregate fields, etc. If you don’t want it to happen you can set this to false.

This options is only available for developers.

skipRecordsWithInvalidFields

no

true

Normally records with invalid fields (validation errors) won’t be created/updated. However, if this flag is set to false, records will be created/updated with errors that will need to be fixed later.

This options is only available for developers.

Response

A reference to the job in charge of perform the import.

POST /data/{entityName}/import
< Content-Type: application/json

{
  "jobLink": "/api/status/jobs/588f8357b45fc9000bc1bd2a",
  "jobId": "588f8357b45fc9000bc1bd2a"
}

Possible errors

Error code HTTP Status Code Description

forbidden

403

You don’t have permissions to import records on this entity.

notFound

404

The entity name does not exist.

Samples

imports a few companies from a CSV file

POST /data/companies/import
> Content-Type: multipart/form-data
> Accept: application/json
> token: token

name,type
test1,a
test2,b
test3,c


POST /data/companies/import
< Content-Type: application/json

{
  "jobLink": "/api/status/jobs/588f3e65b45fc9000bc1baa7",
  "jobId": "588f3e65b45fc9000bc1baa7"
}

Export records

PUT /data/{entityName}/export

Exports records to a CSV file. It is possible to filter records to export using a query and just export some of the fields.

You can use the _fields parameter to indicate which fields should be included in the export. It works very similar as in queries, however there are a few differences:

  • You can put related fields, that is fields that are in the entities pointed by relationship fields. For example if you have a relationship field company pointing to the companies entity, you could specify the field company.type to be included in the CSV file. If you just put company only the label will be exported.
  • If you don’t specify anything in _fields, all fields will be included, except related ones.
  • System fields (id, label and version) aren’t included.

Request

PUT /data/{entityName}/export
> Content-Type: application/json
> Accept: application/json
> token: token


Parameter Required Default Description

entityName

yes

Name of the entity the record belongs to.

_useFieldNames

no

This flag modifies how headers are generated. If it is set to true it will use the name instead of the label to build the headers. Otherwise the label will be used, which is the default.

query parameters

no

These are the query parameters. See Query language for more information.

Response

A reference to the job in charge of perform the import. To actually fetch the file you need to check when the job is finished and look into the results of the job, where you’ll find something like this:

{
  ...
  "hasErrors": false,
  "results": {
    "fileLink": "https://docs.slingrs.io/dev/runtime/api/files/588f864eb45fc9000bc1bd5c",
    "fileId": "588f864eb45fc9000bc1bd5c",
    "recordsExported": 283
  },
  "status": "FINISHED"
}

The field results.fileLink contains the URL to download the file. You need to pass the token in the headers when fetching the file or the token needs to be set in cookies.

PUT /data/{entityName}/export
< Content-Type: application/json

{
  "jobLink": "/api/status/jobs/588f8357b45fc9000bc1bd2a",
  "jobId": "588f8357b45fc9000bc1bd2a"
}

Possible errors

Error code HTTP Status Code Description

badRequest

400

If you are trying to export more than 1,000,000 records or if query is invalid.

forbidden

403

You don’t have permissions to export records on this entity.

notFound

404

The entity name does not exist.

Samples

exports companies with type 'b', with a maxium of 50 records

PUT /data/companies/export?type=b&_size=50
> Content-Type: application/json
> Accept: application/json
> token: token



PUT /data/companies/export?type=b&_size=50
< Content-Type: application/json

{
  "jobLink": "/api/status/jobs/588f3e65b45fc9000bc1baa7",
  "jobId": "588f3e65b45fc9000bc1baa7"
}

exports companies with type 'b', with a maxium of 50 records but only the fields name, address->state and mainContact->email.

PUT /data/companies/export?type=b&_size=50&_fields=name,address.state,mainContact.email
> Content-Type: application/json
> Accept: application/json
> token: token



PUT /data/companies/export?type=b&_size=50&_fields=name,address.state,mainContact.email
< Content-Type: application/json

{
  "jobLink": "/api/status/jobs/588f3e65b45fc9000bc1baa8",
  "jobId": "588f3e65b45fc9000bc1baa8"
}

History

History for one record

GET /data/{entityName}/{id}/history

Returns the history of a record. The entity needs to have history logs enabled.

Request

GET /data/{entityName}/{id}/history
> Accept: application/json
> token: token


Parameter Required Default Description

entityName

yes

Name of the entity the record belongs to.

id

yes

The ID of the record to get its history.

_size

no

20

The number of history records to fetch. Always the latests logs will be retrieved.

_offset

no

Specifies an ID of a history log to start fetching logs from. This is to allow pagination.

Response

The list of history logs for that record, sorted from the newest to the oldest ones.

GET /data/{entityName}/{id}/history
< Content-Type: application/json

{
  "total": 2,
  "offset": "588f8b99b45fc9000bc1bfc5",
  "items": [
    {
      "id": "588f8ba7b45fc9000bc1bfce",
      "entityId": "57fce228e4b0f6600fdfb836",
      "entityName": "companies",
      "entityVersion": 57,
      "recordId": "588f8b99b45fc9000bc1bfc4",
      "recordName": "test1",
      "user": "dgaviola@slingr.io",
      "timestamp": 1485802407010,
      "ip": "::ffff:10.240.0.15",
      "eventType": "USER_RECORD_CHANGED",
      "eventCategory": "USER",
      "contextPath": "entities.companies.update",
      "recordDeleted": null,
      "deletionDate": null,
      "oldRecord": {
        "type": {
          "json": "a",
          "text": "{type:a}"
        },
        "addresses": {
          "json": null,
          "text": "{}"
        }
      },
      "newRecord": {
        "type": {
          "json": "b",
          "text": "{type:b}"
        },
        "addresses": {
          "json": null,
          "text": "{}"
        }
      }
    },
    {
      "id": "588f8b99b45fc9000bc1bfc5",
      "entityId": "57fce228e4b0f6600fdfb836",
      "entityName": "companies",
      "entityVersion": 57,
      "recordId": "588f8b99b45fc9000bc1bfc4",
      "recordName": "test1",
      "user": "dgaviola@slingr.io",
      "timestamp": 1485802393836,
      "ip": "::ffff:10.240.0.11",
      "eventType": "USER_RECORD_CREATED",
      "eventCategory": "USER",
      "contextPath": "entities.companies.create",
      "recordDeleted": null,
      "deletionDate": null,
      "oldRecord": {},
      "newRecord": {
        "name": "test1",
        "state": "active",
        "type": "a",
        "numberOfEmployees": null,
        "isCustomer": false,
        "contactInformation": {
          "phoneNumber": null,
          "email": null,
          "id": "588f8b99b45fc9000bc1bfc3",
          "label": "Contact Information"
        },
        "homepage": null,
        "taxId": null,
        "rating": null,
        "notes": null,
        "lastMeeting": null,
        "lastUpdate": 1485802380000
      }
    }
  ]
}

Path Description

total

The total number of history logs for the record.

offset

The ID of the latest history log, which needs to be sent in the _offset parameter to get the following records when using pagination.

items

The history logs. Most of the fields are self explanatory. Next we will describe a few ones.

items[].eventCategory

The category of the event. These are the possible values:

  • USER: the change was done by a user using the UI or the REST API.
  • SCRIPT: the change was done by a script.
  • SYSTEM: these are system changes like cascade updates.

items[].eventType

The type of event, which depends on the category. These are the options:

  • USER_RECORD_CREATED
  • USER_RECORD_CHANGED
  • USER_RECORD_DELETED
  • USER_ACTION_PERFORMED
  • SCRIPT_RECORD_CREATED
  • SCRIPT_RECORD_CHANGED
  • SCRIPT_RECORD_DELETED
  • SCRIPT_ACTION_PERFORMED
  • SYSTEM_CASCADE_UPDATE
  • SYSTEM_REFACTORING

items[].contextPath

This is a path that describe where the change was done. For example if it was a script it will say which script made the change.

items[].recordDeleted

Indicates if the record has been deleted or not.

items[].deletionDate

Date when the record was deleted.

items[].oldRecord

Contains the old values of the fields that were modified. On each field it will contain the JSON format as well as a more human-redable format.

items[].newRecord

Contains the new values of the fields that were modified. On each field it will contain the JSON format as well as a more human-redable format.

Possible errors

Error code HTTP Status Code Description

badRequest

400

If record ID is invalid.

forbidden

403

You don’t have permissions to see history of records for the entity.

notFound

404

The entity name does not exist. Keep in mind that this method won’t return this error if the record ID does not exists because you could be asking for a deleted record.

Samples

gets the history of a company record

GET /data/companies/588f8b99b45fc9000bc1bfc4/history
> Accept: application/json
> token: token



GET /data/companies/588f8b99b45fc9000bc1bfc4/history
< Content-Type: application/json

{
  "total": 2,
  "offset": "588f8b99b45fc9000bc1bfc5",
  "items": [
    {
      "id": "588f8ba7b45fc9000bc1bfce",
      "entityId": "57fce228e4b0f6600fdfb836",
      "entityName": "companies",
      "entityVersion": 57,
      "recordId": "588f8b99b45fc9000bc1bfc4",
      "recordName": "test1",
      "user": "dgaviola@slingr.io",
      "timestamp": 1485802407010,
      "ip": "::ffff:10.240.0.15",
      "eventType": "USER_RECORD_CHANGED",
      "eventCategory": "USER",
      "contextPath": "entities.companies.update",
      "recordDeleted": null,
      "deletionDate": null,
      "oldRecord": {
        "type": {
          "json": "a",
          "text": "{type:a}"
        },
        "addresses": {
          "json": null,
          "text": "{}"
        }
      },
      "newRecord": {
        "type": {
          "json": "b",
          "text": "{type:b}"
        },
        "addresses": {
          "json": null,
          "text": "{}"
        }
      }
    },
    {
      "id": "588f8b99b45fc9000bc1bfc5",
      "entityId": "57fce228e4b0f6600fdfb836",
      "entityName": "companies",
      "entityVersion": 57,
      "recordId": "588f8b99b45fc9000bc1bfc4",
      "recordName": "test1",
      "user": "dgaviola@slingr.io",
      "timestamp": 1485802393836,
      "ip": "::ffff:10.240.0.11",
      "eventType": "USER_RECORD_CREATED",
      "eventCategory": "USER",
      "contextPath": "entities.companies.create",
      "recordDeleted": null,
      "deletionDate": null,
      "oldRecord": {},
      "newRecord": {
        "name": "test1",
        "state": "active",
        "type": "a",
        "numberOfEmployees": null,
        "isCustomer": false,
        "contactInformation": {
          "phoneNumber": null,
          "email": null,
          "id": "588f8b99b45fc9000bc1bfc3",
          "nestedFieldLabel": "Contact Information",
          "id": "588f8b99b45fc9000bc1bfc3",
          "label": "Contact Information"
        },
        "homepage": null,
        "taxId": null,
        "rating": null,
        "notes": null,
        "lastMeeting": null,
        "lastUpdate": 1485802380000
      }
    }
  ]
}

History in entity

GET /data/{entityName}/history

Returns the history logs for all records in an entity, which needs to have history logs enabled.

Request

GET /data/{entityName}/history
> Accept: application/json
> token: token


Parameter Required Default Description

entityName

yes

Name of the entity the fetch history logs.

eventTypes

no

Allows to filter by some specific type of events. You can select many separating them by commas. Possible values are:

  • USER_RECORD_CREATED
  • USER_RECORD_CHANGED
  • USER_RECORD_DELETED
  • USER_ACTION_PERFORMED
  • SCRIPT_RECORD_CREATED
  • SCRIPT_RECORD_CHANGED
  • SCRIPT_RECORD_DELETED
  • SCRIPT_ACTION_PERFORMED
  • SYSTEM_CASCADE_UPDATE
  • SYSTEM_REFACTORING

to

no

Allows to filter logs by timestamp. This is the maximum date and you should pass the number of milliseconds since Epoch.

from

no

Allows to filter logs by timestamp. This is the minimum date and you should pass the number of milliseconds since Epoch.

_size

no

20

The number of history records to fetch. Always the latests logs will be retrieved.

_offset

no

Specifies an ID of a history log to start fetching logs from. This is to allow pagination.

Response

The list of history logs, sorted from the newest to the oldest ones.

GET /data/{entityName}/history
< Content-Type: application/json

{
  "total": 3,
  "offset": "588f8ba7b45fc9000bc1bfce",
  "items": [
    {
      "id": "588f9757b45fc9000bc1bfe1",
      "entityId": "57fce228e4b0f6600fdfb836",
      "entityName": "companies",
      "entityVersion": 57,
      "recordId": "588f9757b45fc9000bc1bfe0",
      "recordName": "test2",
      "user": "dgaviola@slingr.io",
      "timestamp": 1485805399966,
      "ip": "::ffff:10.240.0.11",
      "eventType": "USER_RECORD_CREATED",
      "eventCategory": "USER",
      "contextPath": "entities.companies.create",
      "recordDeleted": null,
      "deletionDate": null,
      "oldRecord": {},
      "newRecord": {
        "name": "test2",
        "state": "active",
        "type": "c",
        "color": "#e1e1e1",
        "numberOfEmployees": null,
        "isCustomer": false,
        "contactInformation": {
          "phoneNumber": null,
          "email": null,
          "id": "588f9757b45fc9000bc1bfdf",
          "nestedFieldLabel": "Contact Information",
          "id": "588f9757b45fc9000bc1bfdf",
          "label": "Contact Information"
        },
        "homepage": null,
        "taxId": null,
        "rating": null,
        "notes": null,
        "lastMeeting": null,
        "lastUpdate": 1485805380000
      }
    },
    {
      "id": "588f8ba7b45fc9000bc1bfce",
      "entityId": "57fce228e4b0f6600fdfb836",
      "entityName": "companies",
      "entityVersion": 57,
      "recordId": "588f8b99b45fc9000bc1bfc4",
      "recordName": "test1",
      "user": "dgaviola@slingr.io",
      "timestamp": 1485802407010,
      "ip": "::ffff:10.240.0.15",
      "eventType": "USER_RECORD_CHANGED",
      "eventCategory": "USER",
      "contextPath": "entities.companies.update",
      "recordDeleted": null,
      "deletionDate": null,
      "oldRecord": {
        "type": {
          "json": "a",
          "text": "{type:a}"
        },
        "addresses": {
          "json": null,
          "text": "{}"
        }
      },
      "newRecord": {
        "type": {
          "json": "b",
          "text": "{type:b}"
        },
        "addresses": {
          "json": null,
          "text": "{}"
        }
      }
    }
  ]
}

Path Description

total

The total number of history logs matched by the query.

offset

The ID of the latest history log, which needs to be sent in the _offset parameter to get the following records when using pagination.

items

The history logs. Please check the documentation for History for one record.

Possible errors

Error code HTTP Status Code Description

badRequest

400

If the query is invalid.

forbidden

403

You don’t have permissions to see history of records for the entity.

notFound

404

The entity name does not exist.

Samples

gets the last two history logs in entity 'companies'

GET /data/companies/history?_size=2
> Accept: application/json
> token: token



GET /data/companies/history?_size=2
< Content-Type: application/json

{
  "total": 3,
  "offset": "588f8ba7b45fc9000bc1bfce",
  "items": [
    {
      "id": "588f9757b45fc9000bc1bfe1",
      "entityId": "57fce228e4b0f6600fdfb836",
      "entityName": "companies",
      "entityVersion": 57,
      "recordId": "588f9757b45fc9000bc1bfe0",
      "recordName": "test2",
      "user": "dgaviola@slingr.io",
      "timestamp": 1485805399966,
      "ip": "::ffff:10.240.0.11",
      "eventType": "USER_RECORD_CREATED",
      "eventCategory": "USER",
      "contextPath": "entities.companies.create",
      "recordDeleted": null,
      "deletionDate": null,
      "oldRecord": {},
      "newRecord": {
        "name": "test2",
        "state": "active",
        "type": "c",
        "color": "#e1e1e1",
        "numberOfEmployees": null,
        "isCustomer": false,
        "contactInformation": {
          "phoneNumber": null,
          "email": null,
          "id": "588f9757b45fc9000bc1bfdf",
          "nestedFieldLabel": "Contact Information",
          "id": "588f9757b45fc9000bc1bfdf",
          "label": "Contact Information"
        },
        "homepage": null,
        "taxId": null,
        "rating": null,
        "notes": null,
        "lastMeeting": null,
        "lastUpdate": 1485805380000
      }
    },
    {
      "id": "588f8ba7b45fc9000bc1bfce",
      "entityId": "57fce228e4b0f6600fdfb836",
      "entityName": "companies",
      "entityVersion": 57,
      "recordId": "588f8b99b45fc9000bc1bfc4",
      "recordName": "test1",
      "user": "dgaviola@slingr.io",
      "timestamp": 1485802407010,
      "ip": "::ffff:10.240.0.15",
      "eventType": "USER_RECORD_CHANGED",
      "eventCategory": "USER",
      "contextPath": "entities.companies.update",
      "recordDeleted": null,
      "deletionDate": null,
      "oldRecord": {
        "type": {
          "json": "a",
          "text": "{type:a}"
        },
        "addresses": {
          "json": null,
          "text": "{}"
        }
      },
      "newRecord": {
        "type": {
          "json": "b",
          "text": "{type:b}"
        },
        "addresses": {
          "json": null,
          "text": "{}"
        }
      }
    }
  ]
}

Files handling

Slingr apps can store any kind of files than later can be downloaded, shared or referenced by fields in records.

If you need to reference a file in a record from a file field, you will usually upload the file first and then, once you have the ID of the file, you can set it as the the value of the file field.

If a file isn’t referenced by any record, it will be deleted after a few hours. This means you shouldn’t upload files here if you won’t reference them from records in your app.

Uploading files

POST /files

Uploads a file to the app. It will be stored temporarily until it gets referenced by a record. If no record references the file in 12 hours, the file will be removed.

Request

The file needs to be uploaded as a multi-part. You can upload any type of file.

POST /files
> Content-Type: multipart/form-data
> Accept: application/json
> token: token


Response

The metadata of the uploaded file.

POST /files
< Content-Type: application/json

{
  "fileId": "588f9f1eb45fc9000bc1c010",
  "fileLink": "/files/588f9f1eb45fc9000bc1c010"
}

Path Description

fileId

The ID of the file. You can use this ID to reference the file from file fields in records.

Samples

uploads a file

POST /files
> Content-Type: multipart/form-data
> Accept: application/json
> token: token

test file in multi-part


POST /files
< Content-Type: application/json

{
  "fileId": "588f9f1eb45fc9000bc1c010",
  "fileLink": "/files/588f9f1eb45fc9000bc1c010"
}

Downloading files

GET /files/{id}

Downloads a file. This service is only available for developer and system users.

Request

GET /files/{id}
> token: 
> : token


Parameter Required Default Description

id

yes

The ID of the file to download.

Response

Returns the file to download.

GET /files/{id}
> Content-Type: application/force-download
> Content-Disposition: attachment; filename=file.ext

the content of the file

Possible errors

Error code HTTP Status Code Description

notFound

404

The file doesn’t exist.

Samples

fetches a file

GET /files/588f9f1eb45fc9000bc1c010
> token: 
> : token



GET /files/588f9f1eb45fc9000bc1c010
> Content-Type: application/force-download
> Content-Disposition: attachment; filename=file.ext

this is the content of the file

Downloading record files

GET /data/{entityName}/{recordId}/files/{fileId}

Downloads a file that belongs to a specific record. User permissions check is performed.

Request

GET /data/{entityName}/{recordId}/files/{fileId}
> Accept: application/json
> token: token


Parameter Required Default Description

recordId

yes

ID of the record to fetch file.

fileId

yes

ID of the file to be retrieved.

Response

Returns the record file to download.

GET /data/{entityName}/{recordId}/files/{fileId}
> Content-Type: application/force-download
> Content-Disposition: attachment; filename=file.ext

the content of the file

Possible errors

Error code HTTP Status Code Description

notFound

404

The entity or record or file can no be found.

forbidden

403

Provided token does not have permissions to access specified file.

Samples

fetches a file that belongs to a record

GET /data/companies/57fd2d65e4b0ce322b0c8665/files/588fa383b45fc9000bc1c014
> Accept: application/json
> token: token



GET /data/companies/57fd2d65e4b0ce322b0c8665/files/588fa383b45fc9000bc1c014
> Content-Type: application/force-download
> Content-Disposition: attachment; filename=file.ext

this is the content of the file

Sharing files

PUT /files/{id}/share

Shares a file through a public link. The link will be valid for an hour.

Request

PUT /files/{id}/share
> Content-Type: application/json
> Accept: application/json
> token: token


Parameter Required Default Description

ttl

no

3600000

Time to expire in milliseconds.

Response

The public link to download the file. This link won’t require any permission.

PUT /files/{id}/share
< Content-Type: application/json

{
  "sharedFileId": "588fa383b45fc9000bc1c014",
  "sharedFileLink": "/files/shared/588fa383b45fc9000bc1c014"
}

Path Description

sharedFileId

This is the ID of the shared file.

sharedFileLink

The link to download the file. You should prepend the API endpoint.

Samples

shares a file which will expire in one minute

PUT /files/588f9f1eb45fc9000bc1c010/share?ttl=60000
> Content-Type: application/json
> Accept: application/json
> token: token



PUT /files/588f9f1eb45fc9000bc1c010/share?ttl=60000
< Content-Type: application/json

{
  "sharedFileId": "588fa383b45fc9000bc1c014",
  "sharedFileLink": "/files/shared/588fa383b45fc9000bc1c014"
}

Fetch shared file

GET /files/shared/{id}

Downloads a shared file.

Request

GET /files/shared/{id}
> Accept: application/json
> token: token


Parameter Required Default Description

id

yes

The ID of the shared file to download.

Response

Returns the shared file to download.

GET /files/shared/{id}
> Content-Type: application/force-download
> Content-Disposition: attachment; filename=file.ext

the content of the file

Possible errors

Error code HTTP Status Code Description

notFound

404

The shared file doesn’t exist.

Samples

fetches a shared file

GET /files/shared/588fa383b45fc9000bc1c014
> Accept: application/json
> token: token



GET /files/shared/588fa383b45fc9000bc1c014
> Content-Type: application/force-download
> Content-Disposition: attachment; filename=file.ext

this is the content of the file

Monitoring and troubleshooting

Logs

Logs allow to know what’s going on in the app. The structure of a log is this one:

{
  "id": "57fce0bfe4b0f6600fdfb82c",
  "type": "APP",
  "subType": null,
  "level": "INFO",
  "message": "PUT /api/metadata/clearCache",
  "userEmail": "system@docs.slingrs.io",
  "adminUserEmail": null,
  "timestamp": 1476190399791,
  "ip": "10.64.2.3",
  "additionalInfo": {}
}
Path Description

id

ID of the log.

type

Indicates the type of log. Possible options are:

  • APP: log generated by the app runtime.
  • ENDPOINT: log generated by an endpoint.
  • EXTERNAL: log generated by a special call in the REST API to save logs.

subType

Based on the type there might be additional sub-types. Currently only APP type has sub-types:

  • LOGIN: a user logs into the app.
  • REST_API_RECORD_CREATED: a user created a record.
  • REST_API_RECORD_READ: a user read a record.
  • REST_API_RECORD_UPDATED: a user updated a record.
  • REST_API_RECORD_DELETED: a user deleted a record.
  • REST_API_ACTION_EXECUTED: a user executed an action.
  • SCRIPT: log generated by a script.
  • EVENT_ARRIVED: log generated by an endpoint event.
  • CONFIG_SCRIPT_ARRIVED: log generated by a configuration script execution.
  • FUNCTION_CALLED: log generated by the execution of an endpoint function.

level

Level of the log. It could be INFO, WARN or ERROR.

message

The message of the log.

userEmail

The email of the current user when the log was generated. It could be the system user.

adminUserEmail

If the user is being impersonated, this is the email of the admin user.

timestamp

Timestamp when the log was generated. It is in milliseconds since Epoch.

ip

additionalInfo

This fields might provide additional info that could be useful when there are issues. Do not use this information to automate any process because it could change without notice.

Get logs

GET /status/logs

Query logs from the app.

Keep in mind that logs rotate and when the maximum size of logs is reached older ones are lost.

Request

GET /status/logs
> Accept: application/json
> token: token


Parameter Required Default Description

userEmail

no

Allows to filter by user email doing a partial match.

period

no

Allows to filter by a span of time. For example you can send 3h 30m and it will query logs in the last 3 hours and a half. The format is the same you can use for Time duration fields, with the only difference that you can also pass today or yesterday.

If this parameter is specified, parameters start and end will be discarded.

from

no

The minimum timestamp in milliseconds since Epoch.

to

no

The maximum timestamp in milliseconds since Epoch.

level

no

The level of logs to find. You can specify many levels separated by commas.

message

no

Allows to filter by the message in the logs. It will do a partial search.

_size

no

200

The maximum number of logs to retrieve.

_offset

no

This is the offset to start getting logs. When you make a query you will get the offset you need to use to get more logs.

Response

A list of logs in JSON format.

GET /status/logs
< Content-Type: application/json

{
  "total": 151
  "items": [
    {
      "id": "58907c10b45fc9000bc1c020",
      "type": "APP",
      "subType": "LOGIN",
      "level": "INFO",
      "message": "POST /login",
      "userEmail": "dgaviola@slingr.io",
      "adminUserEmail": null,
      "timestamp": 1485863952895,
      "ip": null
    },
    {
      "id": "58907c1bb45fc9000bc1c023",
      "type": "APP",
      "subType": null,
      "level": "INFO",
      "message": "GET /api/users/57fce0c3e4b0ce322b0c06b2?appsVersion=true",
      "userEmail": "dgaviola@slingr.io",
      "adminUserEmail": null,
      "timestamp": 1485863963701,
      "ip": "::ffff:10.240.0.11"
    },
    {
      "id": "589085b0b45fc9000bc1c02f",
      "type": "APP",
      "subType": null,
      "level": "INFO",
      "message": "Validation exceptions on record [test]. Error: [file: Content type is required when uploading a file and must be a string]",
      "userEmail": "dgaviola@slingr.io",
      "adminUserEmail": null,
      "timestamp": 1485866416124,
      "ip": null,
      "additionalInfo": {
        "recordLabel": "test",
        "errors": [
          {
            "code": "INVALID",
            "field": "file",
            "message": "Content type is required when uploading a file and must be a string"
          }
        ]
      }
    },
    {
      "id": "589085bdb45fc9000bc1c030",
      "type": "APP",
      "subType": "REST_API_RECORD_UPDATED",
      "level": "INFO",
      "message": "PUT /api/data/files/585aea800d29d300072484a8",
      "userEmail": "dgaviola@slingr.io",
      "adminUserEmail": null,
      "timestamp": 1485866429630,
      "ip": "::ffff:10.240.0.15"
    },
    {
      "id": "589085bfb45fc9000bc1c032",
      "type": "APP",
      "subType": null,
      "level": "INFO",
      "message": "Data record of type [files] with label [test] was changed successfully",
      "userEmail": "dgaviola@slingr.io",
      "adminUserEmail": null,
      "timestamp": 1485866431823,
      "ip": null
    },
  ]
}

Path Description

total

The total number of logs matched by the query.

offset

The offset to use to get more logs.

items

The logs found. Please check the docs for Logs for more information.

Possible errors

Error code HTTP Status Code Description

forbidden

403

If you try to query logs with a user who is not a developer.

Samples

finds two logs for yesterday for one specific user

GET /status/logs?period=yesterday&userEmail=test@slingr.io&_size=2
> Accept: application/json
> token: token



GET /status/logs?period=yesterday&userEmail=test@slingr.io&_size=2
< Content-Type: application/json

{
  "items": [
    {
      "id": "58907c10b45fc9000bc1c020",
      "type": "APP",
      "subType": "LOGIN",
      "level": "INFO",
      "message": "POST /login",
      "userEmail": "test@slingr.io",
      "adminUserEmail": null,
      "timestamp": 1485863952895,
      "ip": null
    },
    {
      "id": "58907c19b45fc9000bc1c021",
      "type": "APP",
      "subType": null,
      "level": "INFO",
      "message": "GET /api/users/current",
      "userEmail": "test@slingr.io",
      "adminUserEmail": null,
      "timestamp": 1485863961326,
      "ip": "::ffff:10.240.0.16"
    }
  ],
  "total": 151
}

Post logs

POST /status/logs

Creates a log. You only need to send the message and the level of log. Other fields will be calculated automatically. An optional additionalInfo object can be send to add extra fields.

Request

POST /status/logs
> Content-Type: application/json
> Accept: application/json
> token: token

{
  "level": "INFO",
  "message": "This is a test log",
  "additionalInfo": {
    "test": "Additional info property"
  }
}

Response

The created log in JSON format.

POST /status/logs
< Content-Type: application/json

{
  "id": "589085bdb45fc9000bc1c030",
  "type": "EXTERNAL",
  "subType": null,
  "level": "INFO",
  "message": "This is a test log",
  "userEmail": "test@slingr.io",
  "adminUserEmail": null,
  "timestamp": 1485866429630,
  "ip": null,
  "additionalInfo": {
    "test": "Additional info property"
  }
}

Possible errors

Error code HTTP Status Code Description

validationErrors

400

If there are validation errors. When this happens you will get the details of the errors in the body:

{
  "code": "validationErrors",
  "message": "There are validation errors",
  "errors": [
    {
      "field": "message",
      "fieldLabel": null,
      "code": "required",
      "message": "Message cannot be empty",
      "additionalInfo": null
    }
  ]
}

forbidden

403

If you try to create a log with a user who is not a developer.

Samples

creates a new log

POST /status/logs
> Content-Type: application/json
> Accept: application/json
> token: token

{
  "level": "INFO",
  "message": "This is a test log",
  "additionalInfo": {
    "test": "Additional info property"
  }
}


POST /status/logs
< Content-Type: application/json

{
  "id": "589085bdb45fc9000bc1c030",
  "type": "EXTERNAL",
  "subType": null,
  "level": "INFO",
  "message": "This is a test log",
  "userEmail": "test@slingr.io",
  "adminUserEmail": null,
  "timestamp": 1485866429630,
  "ip": "::ffff:10.240.0.15",
  "additionalInfo": {
    "test": "Additional info property"
  }
}

Jobs

With the API for jobs it is possible to check status, progress, logs, as well as some additional information to get a good understanding of what’s going on with the of a job.

This is the general structure of a job:

{
  "id": "588a02c13b063a0007605032",
  "label": "Executing action countEmployees on entity companies",
  "type": "EXECUTE_ACTION",
  "runBy": {
    "id": "57fce0c3e4b0ce322b0c06b2",
    "fullName": "Diego Gaviola"
  },
  "parentJob": null,
  "rootJob": null,
  "createDate": 1485439681643,
  "startDate": 1485439681652,
  "endDate": 1485439681807,
  "status": "FINISHED",
  "hasErrors": false,
  "progress": 100,
  "recordsCount": 0,
  "recordsProcessed": 0,
  "childrenJobsCount": 0,
  "childrenJobsProcessed": 0,
  "stoppable": true,
  "lowPriority": false,
  "data": {}
  "results": {}
}
Path Description

id

ID of the job.

label

Name of the jobs. It is a simple description of what the job does. This description might change without notice so don’t use it to take decisions in your code.

type

This is the type of job. There are many types of jobs, however some of them might change without notice. The only job types we support are the following ones:

  • IMPORT_RECORDS
  • EXPORT_RECORDS
  • EXECUTE_ACTION
  • DELETE_RECORDS
  • EXECUTE_LISTENER
  • IMPORT_USERS
  • EXPORT_USERS
  • STOP_APP
  • START_APP
  • DEPLOY_ENDPOINT
  • UNDEPLOY_ENDPOINT

Other jobs are system ones and you shouldn’t base your code on any of them as we might change or remove them.

runBy

It is a map with id and fullName of the user that triggered the job.

parentJob

It is a map with id and label of the parent job.

The parent job is the job that was being executed when the job was created. If the job was not created during the execution of another job, then this field will be null and it means this is a root job.

rootJob

It is a map with id and label of the root job.

A root job is one that doesn’t have a parent. If this field is null it means this is a root job.

createDate

The date the job was created in milliseconds.

startDate

endDate

The date when the execution of the job finished. This can be null if the job hasn’t finished yet.

status

Current status of the job. It could be:

  • PENDING: the job is pending for execution.
  • RUNNING: the job is being executed.
  • FINISHED: the job is completed.
  • STOPPING: the job is stopping. This could take a while until the job can be stopped gracefully.
  • STOPPED: the job has been stopped but can be resumed.
  • CANCELED: the job has been canceled and cannot be resumed.

hasErrors

If true it means that there was at least one error during the execution of the job. You should check the logs and results of the job to see what happened.

progress

This is a number from 0 to 100 that indicates the progress of the job. Keep in mind that some jobs will move directly from 0 to 100 as there is no progress information. Also in cases were progress is updated it might not be consistent, so use it carefully.

recordsCount

If the job needs to do something with records, this number will indicate the number of records involved.

recordsProcessed

If the job needs to do something with records, this number will indicate the number of records that have been processed already.

childrenJobsCount

If other jobs were created during the execution of the job, this counter will increase to show how many children jobs have been created. This number will be 0 at the beginning but could grow over time, so it isn’t fixed.

childrenJobsProcessed

The number of children jobs that are finished.

stoppable

If true it means this job allows to be stopped. Otherwise you won’t be able to stop it and you need to wait for it (except that the job is still pending, case in which you can always stop it).

lowPriority

If true the job will be executed only when there are no many other jobs running.

data

The content of this field depends on the job. Here you will find more information about parameters for the job.

Start app

Path Description

pushChanges

true if changes will be pushed during the starting of the app. false or empty otherwise.

wakingUp

true if the app was sleeping and is waking ap. false otherwise.

Import records

Path Description

fileName

This is the name of the file that will be imported.

entityName

The name of the entity where records will be imported.

Export records

Path Description

entityName

The name of the entity where records will be exported from.

Delete records

Path Description

entityName

The name of the entity where records will be deleted from.

Execute action

Path Description

entityName

The name of the entity the action belongs to.

actionName

The name of the action to be executed.

Execute listener

Path Description

listenerName

The name of the listener to execute.

Import users

Path Description

fileName

This is the name of the file that will be imported.

notifyUsers

true if people will be notified by email when users are created; false otherwise.

Deploy endpoint

Path Description

endpointName

The name of the endpoint to deploy.

Undeploy endpoint

Path Description

endpointName

The name of the endpoint to undeploy.

results

The content of this field depends on the job. Here you will find information about the results of executing the job.

Import records

Path Description

rowsImported

The number of rows that were imported successfully.

rowsWithErrors

The number of rows that couldn’t be imported due to errors.

Export records

Path Description

fileLink

URL to download the CSV file with the exported records. You will need to send the token in the headers in order to be able to download it.

fileId

The ID of the file that was generated.

recordsExported

The number of records that were exported.

Delete records

The result will be a map like this one:

{
  "results": {
    "id1": {
      "status": "ok"
    },
    "id2": {
      "status": "error",
      "errorMessage": "error message"
    }
  }
}

status will indicate if the delete process was executed successfully over that record (ok) or if there were errors (error). The field response will be available only if the action is configured to return the response in the results; otherwise it won’t be there.

One important thing to keep in mind is that the maximum number of responses in this map will be 1,000. If you execute the delete process over more than 1,000 records you might not be able to collect the response for each one.

Execute action

The results of this job depends on the type of action. If the action is of type One record, the result will be a map like this one:

{
  "results": {
    "id1": {
      "status": "ok",
      "response": "response from action"
    },
    "id2": {
      "status": "error",
      "errorMessage": "error message"
    }
  }
}

status will indicate if the action was executed successfully over that record (ok) or if there were errors (error). The field response will be available only if the action is configured to return the response in the results; otherwise it won’t be there. The field errorMessage will be present when there is an error, giving some insight about the problem.

One important thing to keep in mind is that the maximum number of responses in this map will be 1,000. If you execute the action over more than 1,000 records you might not be able to collect the response for each one.

If the action is of type Many records, you will only get a map with fields status and response:

{
  "results": {
    "status": "ok",
    "response": "response from action"
  }
}

Import users

Path Description

Export users

Path Description

fileLink

URL to download the CSV file with the exported users. You will need to send the token in the headers in order to be able to download it.

fileId

The ID of the file that was generated.

usersExported

The number of users that were exported.

Get one job

GET /status/jobs/{id}

Gets one job by ID.

Request

GET /status/jobs/{id}
> Accept: application/json
> token: token


Parameter Required Default Description

id

yes

The ID of the job.

Response

The job in JSON format.

GET /status/jobs/{id}
< Content-Type: application/json

{
  "id": "588a02c13b063a0007605032",
  "label": "Execute action countEmployees from entity companies",
  "type": "EXECUTE_ACTION",
  "runBy": {
    "id": "57fce0c3e4b0ce322b0c06b2",
    "fullName": "Diego Gaviola"
  },
  "parentJob": null,
  "rootJob": null,
  "createDate": 1485439681643,
  "startDate": 1485439681652,
  "endDate": 1485439681807,
  "status": "FINISHED",
  "hasErrors": false,
  "progress": 100,
  "recordsCount": 0,
  "recordsProcessed": 0,
  "childrenJobsCount": 0,
  "childrenJobsProcessed": 0,
  "stoppable": true,
  "lowPriority": false
}

Possible errors

Error code HTTP Status Code Description

notFound

404

The job doesn’t exist

Samples

gets a job by ID

GET /status/jobs/588a02c13b063a0007605032
> Accept: application/json
> token: token



GET /status/jobs/588a02c13b063a0007605032
< Content-Type: application/json

{
  "id": "588a02c13b063a0007605032",
  "label": "Execute action countEmployees from entity companies",
  "type": "EXECUTE_ACTION",
  "runBy": {
    "id": "57fce0c3e4b0ce322b0c06b2",
    "fullName": "Diego Gaviola"
  },
  "parentJob": null,
  "rootJob": null,
  "createDate": 1485439681643,
  "startDate": 1485439681652,
  "endDate": 1485439681807,
  "status": "FINISHED",
  "hasErrors": false,
  "progress": 100,
  "recordsCount": 0,
  "recordsProcessed": 0,
  "childrenJobsCount": 0,
  "childrenJobsProcessed": 0,
  "stoppable": true,
  "lowPriority": false
}

List jobs

GET /status/jobs

Lists jobs in the app.

Request

GET /status/jobs
> Accept: application/json
> token: token


Parameter Required Default Description

type

no

The type of job. Possible values are: IMPORT_RECORDS, EXPORT_RECORDS, EXECUTE_ACTION, DELETE_RECORDS, EXECUTE_LISTENER, IMPORT_USERS, EXPORT_USERS, STOP_APP, START_APP, DEPLOY_ENDPOINT, UNDEPLOY_ENDPOINT .

You can specify many separated by commas.

status

no

The status of the job. Possible values are: PENDING, RUNNING, FINISHED, STOPPING, STOPPED, CANCELING, CANCELED .

You can specify many separated by commas.

hasErrors

no

Allows to filter jobs if they have errors. true if you want only jobs with errors, false if you only want jobs without errors.

startFrom

no

Allows to filter jobs by start date. This is the initial range limit to filter from, it can be used alone or in combination with startTo.

startTo

no

Allows to filter jobs by start date. This is the final range limit to filter to, it can be used alone or in combination with startFrom.

endFrom

no

Allows to filter jobs by end date. This is the initial range limit to filter from, it can be used alone or in combination with endTo.

endTo

no

Allows to filter jobs by end date. This is the final range limit to filter to, it can be used alone or in combination with endFrom.

createFrom

no

Allows to filter jobs by creation date. This is the initial range limit to filter from, it can be used alone or in combination with createTo.

createTo

no

Allows to filter jobs by creation date. This is the final range limit to filter to, it can be used alone or in combination with createFrom.

_size

no

20

The maximum number of jobs to retrieve.

_offset

no

This is the offset to start getting jobs. When you make a query you will get the offset you need to use to get more jobs.

Response

A list of jobs in JSON format.

GET /status/jobs
< Content-Type: application/json

{
  "total": 54,
  "offset": "5890d8ddb45fc9000bc1c2cf",
  "items": [
    {
      "id": "5890d8deb45fc9000bc1c2d3",
      ...
    },
    {
      "id": "5890d8deb45fc9000bc1c2d1",
      ...
    },
    {
      "id": "5890d8ddb45fc9000bc1c2cf",
      ...
  ]
}

Path Description

total

The total number of jobs matched by the query.

offset

The offset to use to get more jobs.

items

The jobs found. Please check the docs for Jobs for more information.

Samples

finds up to three finished jobs

GET /status/jobs?status=FINISHED&_size=3
> Accept: application/json
> token: token



GET /status/jobs?status=FINISHED&_size=3
< Content-Type: application/json

{
  "total": 50,
  "offset": "5890d8ddb45fc9000bc1c2cf",
  "items": [
    {
      "id": "5890d8deb45fc9000bc1c2d3",
      ...
    },
    {
      "id": "5890d8deb45fc9000bc1c2d1",
      ...
    },
    {
      "id": "5890d8ddb45fc9000bc1c2cf",
      ...
  ]
}

Get logs of a job

GET /status/jobs/{id}/logs

Query logs from a job.

Request

GET /status/jobs/{id}/logs
> Accept: application/json
> token: token


Parameter Required Default Description

period

no

Allows to filter by a span of time. For example you can send 3h 30m and it will query logs in the last 3 hours and a half. The format is the same you can use for Time duration fields, with the only difference that you can also pass today or yesterday.

If this parameter is specified, parameters start and end will be discarded.

from

no

The minimum timestamp in milliseconds since Epoch.

to

no

The maximum timestamp in milliseconds since Epoch.

level

no

The level of logs to find. You can specify many levels separated by commas.

Possible values are INFO, WARN and ERROR.

message

no

Allows to filter by the message in the logs. It will do a partial search.

_size

no

200

The maximum number of users to retrieve.

_offset

no

This is the offset to start getting users. When you make a query you will get the offset you need to use to get more users.

Response

A list of logs in JSON format.

GET /status/jobs/{id}/logs
< Content-Type: application/json

{
  "total": 3,
  "items": [
    {
      "timestamp": 1485887710544,
      "level": "INFO",
      "message": "Starting processing"
    },
    {
      "timestamp": 1485887710546,
      "level": "INFO",
      "message": "Cleaning up"
    },
    {
      "timestamp": 1485887710704,
      "level": "INFO",
      "message": "Process completed"
    }
  ]
}

Path Description

total

The total number of logs matched by the query.

offset

The offset to use to get more logs.

items

The logs found that contains three fields:

  • timestamp: the timestamp when the log was created.
  • level: level of the log. Could be INFO, WARN or ERROR.
  • message: the message in the logs.

Possible errors

Error code HTTP Status Code Description

notFound

404

If the job is not found.

Samples

finds logs for one job

GET /status/job/5890d8deb45fc9000bc1c2d3/logs
> Accept: application/json
> token: token



GET /status/job/5890d8deb45fc9000bc1c2d3/logs
< Content-Type: application/json

{
  "total": 3,
  "items": [
    {
      "timestamp": 1485887710544,
      "level": "INFO",
      "message": "Starting processing"
    },
    {
      "timestamp": 1485887710546,
      "level": "INFO",
      "message": "Cleaning up"
    },
    {
      "timestamp": 1485887710704,
      "level": "INFO",
      "message": "Process completed"
    }
  ]
}

Stop job

PUT /status/jobs/{id}/stop

Stops a job. If the job was running it might need some time to stop gracefully. During that time the status will be STOPPING. Once the job has been stopped gracefully the status will change to STOPPED.

Jobs that are stopped can be resumed.

Request

PUT /status/jobs/{id}/stop
> Content-Type: application/json
> Accept: application/json
> token: token


Response

The job in JSON format.

PUT /status/jobs/{id}/stop
< Content-Type: application/json

{
  "id": "588a02c13b063a0007605032",
  ...
  "status": "STOPPING",
  ...
}

Possible errors

Error code HTTP Status Code Description

badRequest

404

If job cannot be stopped. It could be because jobs of this type cannot be stopped or this is not a root job.

forbidden

403

You don’t have permissions to stop this job. If you are not a developer you can only stop jobs you ran.

notFound

404

If job is not found.

Samples

stops a job

PUT /status/jobs/588a02c13b063a0007605032/stop
> Content-Type: application/json
> Accept: application/json
> token: token



PUT /status/jobs/588a02c13b063a0007605032/stop
< Content-Type: application/json

{
  "id": "588a02c13b063a0007605032",
  ...
  "status": "STOPPING",
  ...
}

Force to stop job

PUT /status/jobs/{id}/forceStop

When stopping a job it will try to do it gracefully. If the job keeps running and you need to stop it, you can force it, what will kill the job immediately.

Keep in mind that the processing the job was doing might be interrupted and data might be in a bad state when doing this, so use it only for very special cases.

Request

PUT /status/jobs/{id}/forceStop
> Content-Type: application/json
> Accept: application/json
> token: token


Response

The job in JSON format.

PUT /status/jobs/{id}/forceStop
< Content-Type: application/json

{
  "id": "588a02c13b063a0007605032",
  ...
  "status": "STOPPED",
  ...
}

Possible errors

Error code HTTP Status Code Description

badRequest

400

If job cannot be stopped. It could be because jobs of this type cannot be stopped, this is not a root job or because the status is different from STOPPING.

forbidden

403

You don’t have permissions to stop this job. If you are not a developer you can only stop jobs you ran.

notFound

404

If job is not found.

Samples

force to stop a job

PUT /status/jobs/588a02c13b063a0007605032/forceStop
> Content-Type: application/json
> Accept: application/json
> token: token



PUT /status/jobs/588a02c13b063a0007605032/forceStop
< Content-Type: application/json

{
  "id": "588a02c13b063a0007605032",
  ...
  "status": "STOPPED",
  ...
}

Cancel job

PUT /status/jobs/{id}/cancel

Cancels a job. Only jobs that are in STOPPED can be canceled.

Jobs that are canceled cannot be resumed.

Request

PUT /status/jobs/{id}/cancel
> Content-Type: application/json
> Accept: application/json
> token: token


Response

The job in JSON format.

PUT /status/jobs/{id}/cancel
< Content-Type: application/json

{
  "id": "588a02c13b063a0007605032",
  ...
  "status": "CANCELED",
  ...
}

Possible errors

Error code HTTP Status Code Description

badRequest

404

If job cannot be canceled. It could be because the job is in a bad status or it is not a root job.

forbidden

403

You don’t have permissions to cancel this job. If you are not a developer you can only cancel jobs you ran.

notFound

404

If job is not found.

Samples

cancels a job

PUT /status/jobs/588a02c13b063a0007605032/cancel
> Content-Type: application/json
> Accept: application/json
> token: token



PUT /status/jobs/588a02c13b063a0007605032/cancel
< Content-Type: application/json

{
  "id": "588a02c13b063a0007605032",
  ...
  "status": "CANCELED",
  ...
}

Resume job

PUT /status/jobs/{id}/resume

Resumes a job that is stopped. The job will continue execution where it left. If the job was not started when it was stopped, the status will be set to PENDING instead of RUNNING.

Request

PUT /status/jobs/{id}/resume
> Content-Type: application/json
> Accept: application/json
> token: token


Response

The job in JSON format.

PUT /status/jobs/{id}/resume
< Content-Type: application/json

{
  "id": "588a02c13b063a0007605032",
  ...
  "status": "RUNNING",
  ...
}

Possible errors

Error code HTTP Status Code Description

badRequest

404

If job cannot be resumed. It could be because the job is in a bad status or it is not a root job.

forbidden

403

You don’t have permissions to resume this job. If you are not a developer you can only resume jobs you ran.

notFound

404

If job is not found.

Samples

resumes a job

PUT /status/jobs/588a02c13b063a0007605032/resume
> Content-Type: application/json
> Accept: application/json
> token: token



PUT /status/jobs/588a02c13b063a0007605032/resume
< Content-Type: application/json

{
  "id": "588a02c13b063a0007605032",
  ...
  "status": "RUNNING",
  ...
}

Back to top