---
title: Limitations
slug: api/limitations
description: This document provides important limitations, guidelines, and fair use policies for using an API. It outlines the maximum number of API calls allowed per minute, hour, and month, as well as the maximum traffic and records per API call. It emphasizes the r
createdAt: 2022-03-11T09:42:47.000Z
---

- Max 60 API calls per minute
- Max. 1,000 API calls per hour
- Max. 24.000 API calls per day
- Max. 5 parallel calls
- Max. 10 GB traffic per month
- Max. 500 records per API call
- Max. 4,000 characters in the filter of an API call

# Fair Use Policy

1. To ensure that server performance is not affected by overuse of individual users, access to the API for such users can be restricted.
2. Prohibited: The API may not be used for any illegal, unethical, or malicious activity. Including but not limited to hacking, spamming or spreading malware.
3. Liability: The API owner is not responsible for any damage or loss resulting from the use of the API. Users assume full responsibility for their use of the API and any consequences thereof.
4. These guidelines and limitations may be updated at any time. It is the user's responsibility to stay informed of changes.

# Remarks

1. regarding the limits - programmatically always try to work per bulk request, i.e. programmatically collect/aggregate the data sets and generate a full API query instead of per determined data set (saves calls and is more performant).
2. With SaveAll the DataId and EntityId of the created record can be delivered as 200 HTTP code including ReturnText. These can be written back (for orders, any master data, etc.) in order to make direct calls/matches. Accordingly consider the documentation!
3. Listing of all entities and their properties can be queried via "GetGenericEntities" and "GetGenericProperties". Only entities with **AllowExternalApi set&#x20;**&#x74;o true are available to other APIs. In general all data get be called by api. If u need other access please contact your consultant. for security reasions this is resctricted like this
   Your consultant can explain the relationships between the entities.&#x20;
4. Loops with included API calls (general multiple calls) should be avoided.
5. The API user may not have rights for most entities. Your consultant needs to know what kind of entities you want to manage via the API so that the correct rights/roles can be set up!

# Example

This example creates an API token, retrieves a record, and writes a record including LookupProperty to a table.&#x20;

:::CodeblockTabs
Common (Pyhthon)

```python
import requests
import sys

## URIs (more URIs: https://test.engine4.io/externalApiDocs/)
endpoint                        = "https://test.engine4.io" 
endpoint_token                  = endpoint + "/token"
endpoint_get                    = endpoint + "/webapi/external/get"
endpoint_fetch                  = endpoint + "/webapi/external/fetch"
endpoint_saveall                = endpoint + "/webapi/external/saveAll"

## Auth settings
auth_clientid   = "XXX"
auth_user       = "XXX@mobile-function.com"
auth_pass       = "XXX"

######## /Token-Request
head            = {"Content-Type" : "application/x-www-form-urlencoded"}
body            = {"client_id" : auth_clientid, "grant_type": "password", "username"  : auth_user , "password"  : auth_pass}

# Every request is put in a try-except block to handle connection issues
try:
    response = requests.post(endpoint_token, headers=head, data=body)  
except requests.RequestException as e:
    sys.exit("Error: {0}".format(e))

# Every request is expected to be successfull (200), handling errors on others. 
response_code = response.status_code  
if (response_code==200):
    try:
        data = response.json()
    except requests.JSONDecodeError as e:
        sys.exit("Error: {0}".format(e))
else:
    sys.exit("ErrorCode: " + str(response_code) + " - ErrorMessage: " + response.text)
        
# Retrieve auth data
access_token  = data['access_token']
expires_in    = data['expires_in'] 
token_type    = data['token_type']
refresh_token = data['refresh_token'] 
scope         = data['scope']

# Generate auth token for further requests
auth_token = token_type + " " + access_token

##############################################################################
#### Example: (GET) -Get an object from an entity with a already known DataId
entityid        = "XXX"
dataid          = "XXX"
head            = {"Authorization": auth_token}
body            = {"entityid" : entityid, "dataid": dataid}

try:
    response = requests.get(endpoint_get, headers=head, data=body)  
except requests.RequestException as e:
    sys.exit("Error: {0}".format(e))
 
response_code = response.status_code 
if (response_code==200):
    try:
        data = response.json()
    except requests.JSONDecodeError as e:
        sys.exit("Error: {0}".format(e))
else:
    sys.exit("ErrorCode: " + str(response_code) + " - ErrorMessage: " + response.text)

#print(data)

##############################################################################
#### Example: (POST) Save a new item including referenced field
## Get a referenced object first
entityid        = "XXX" 
head            = {"Authorization": auth_token, "content-type":"application/json"}
body            = {"EntityId":entityid,"Take":1,"Skip":0,"Filter":{"GenericName":"Custom_001","CompareOperator":"CONTAINS","Value":"XXX"},"IsActive":1,"Sortings":[]}

try:
    response = requests.post(endpoint_fetch, headers=head, json=body)  
except requests.RequestException as e:
    sys.exit("Error: {0}".format(e))

response_code = response.status_code 
if (response_code==200):
    try:
        data = response.json()
    except requests.JSONDecodeError as e:
        sys.exit("Error: {0}".format(e))
else:
    sys.exit("ErrorCode: " + str(response_code) + " - ErrorMessage: " + response.text)

#print(data)

try:
    data = response.json()
except requests.JSONDecodeError as e:
    sys.exit("Error: {0}".format(e))

referencedObject        = data[0]['DataId']

## Create new entry with referenced object and main object
entityid        = "XXX"
head            = {"Authorization": auth_token, "content-type":"application/json"}
body            = {"items" : [{"entityid": entityid,"Custom_001": "API  Test #1", "Custom_004": referencedObject}], "returnType": "dataId"}

try:
    response = requests.post(endpoint_saveall, headers=head, json=body)  
except requests.RequestException as e:
    sys.exit("Error: {0}".format(e))

response_code = response.status_code 
if (response_code==200):
    try:
        data = response.json()
    except requests.JSONDecodeError as e:
        sys.exit("Error: {0}".format(e))
else:
    sys.exit("ErrorCode: " + str(response_code) + " - ErrorMessage: " + response.text)

#print(data)

## This is the End.
quit()
```

PowerBi (Python)

```python
# Check this Microsoft documention: https://learn.microsoft.com/de-de/power-bi/connect-data/desktop-python-scripts

import sys
import requests
import pandas as pd

endpoint            = "https://test.engine4.io" 
endpoint_token      = endpoint + "/token"
endpoint_fetchNamed = endpoint + "/webapi/external/fetchNamed"
auth_clientid       = "xxx" # Additional factor
auth_user           = "xxx@mobile-function.com"
auth_pass           = "xxx"

################################## Authenticate ############################################
head = {"Content-Type" : "application/x-www-form-urlencoded"}
body = {"client_id" : auth_clientid, "grant_type": "password", "username"  : auth_user , "password"  : auth_pass}

# Every request is put in a try-except block to handle connection issues
try:
    response = requests.post(endpoint_token, headers=head, data=body)  
except requests.RequestException as e:
    sys.exit("Error: {0}".format(e))

# Every request expect to be successfull (200), handling errors on others. 
response_code = response.status_code  
if (response_code==200):
    # Every json parsing part is try/excepted.
    try:
        data = response.json()
    except requests.JSONDecodeError as e:
        sys.exit("Error: {0}".format(e))
else:
    sys.exit("ErrorCode: " + str(response_code) + " - ErrorMessage: " + response.text)
        
# Retrieve auth data
access_token  = data['access_token']
expires_in    = data['expires_in'] 
token_type    = data['token_type']
refresh_token = data['refresh_token'] 
scope         = data['scope']

# Generate auth token for further requests
auth_token = token_type + " " + access_token

################################## Get entity 1 ############################################
head = {"Authorization": auth_token, "content-type":"application/json"}
body = {"Identifier":"XXX","Take":100,"Skip":0,"IsActive":1,"Sortings":[]}

# Every request is put in a try-except block to handle connection issues
try:
    response = requests.post(endpoint_fetchNamed, headers=head, json=body)  
except requests.RequestException as e:
    sys.exit("Error: {0}".format(e))

# Every request expect to be successfull (200), handling errors on others. 
response_code = response.status_code 
if (response_code==200):
    try:
        data = response.json()
    except requests.JSONDecodeError as e:
        sys.exit("Error: {0}".format(e))
else:
    sys.exit("ErrorCode: " + str(response_code) + " - ErrorMessage: " + response.text)

# We need to know the column names which we're getting from the REST API. These has to be in the DataFrame command. Only flat tables allowed!
# The name of the variable will be the table name in PowerBi
# ColumnName1 and 2 will be the name of the columns in PowerBi
TableName1 = pd.DataFrame(data,columns=['ColumnName1','ColumnName2'],dtype=object) 
print(TableName1)

################################## Entity 2 ############################################
head = {"Authorization": auth_token, "content-type":"application/json"}
body = {"Identifier":"XXX","Take":100,"Skip":0,"IsActive":1,"Sortings":[]}

try:
    response = requests.post(endpoint_fetchNamed, headers=head, json=body) 
except requests.RequestException as e:
    sys.exit("Error: {0}".format(e))

response_code = response.status_code  
if (response_code==200):
    try:
        data = response.json()
    except requests.JSONDecodeError as e:
        sys.exit("Error: {0}".format(e))
else:
    sys.exit("ErrorCode: " + str(response_code) + " - ErrorMessage: " + response.text)

TableName2 = pd.DataFrame(data,columns=['ColumnName1'],dtype=object)
print(TableName2)

################################## End  ############################################
quit()
```
:::



