Skip to main content
Skip table of contents

API Generic query API


The Generic API, is a Restful API created to provide uniform access to any model entity.

It defines generic endpoints, so the API can survive future changes in the model without any upgrade of the API code.

Please beware !

  • Generic API bypasses all functional rules, it is thus required to use with precaution. Recommended usage is to only read data, we will not provide support if used in write mode.

  • Generic API doesn’t support spaces in custom field codes as space is used to separate field name and operators.

Available entities


Basically speaking, all Opencell entities can be queried using Generic API.

You can download the list of these entities on the Functional data model page or by querying the “entities” generic API (see below).

Available generic endpoints


HTTP Verb

Resource Path

Payload

Description

Response code

GET

https://{host}/opencell/api/rest/v2/generic/openapi.json

none

returns the open api documentation of the api

  • 200

GET

https://{host}/opencell/api/rest/v2/version

none

returns a list of the Opencell Entreprise Edition component versions

  • 200

GET

https://{host}/opencell/api/rest/v2/generic/entities

As URL parameters

  • onlyBusinessEntities: boolean, to fetch only business entities

  • withFullName: boolean, to return fully qualified class names

returns a list of entities.

These entities are accessible through generic API using their short names (see below).

  • 200

POST

https://{host}/opencell/api/rest/v2/generic/count/{modelName}

  • {}

  • JSON
    {
        "filters": {}
    }

counts all {modelName} instances

  • https://{host}/opencell/api/rest/v2/generic/all/billingaccount

  • https://{host}/opencell/api/rest/v2/generic/all/walletoperation

  • 200

  • 400

POST

https://{host}/opencell/api/rest/v2/generic/all/{modelName}

  • {}

  • JSON
    {
        "joinType": "LEFT",
        "filters": {},
        "genericFields": [],
        "nestedEntities": [],
        "sortBy": "id",
        "sortOrder": "DESCENDING",
        "limit": 1
    }

returns all {modelName} instances

e.g.

  • https://{host}/opencell/api/rest/v2/generic/all/seller

  • https://{host}/opencell/api/rest/v2/generic/all/subscription

  • 200

  • 400

POST

https://{host}/opencell/api/rest/v2/generic/{modelName}/{ID}

  • {}

  • JSON
    {
        "genericFields": [],
        "nestedEntities": []
    }

returns the {modelName} instance with ID equal to {ID}

e.g.

  • https://{host}/opencell/api/rest/v2/generic/seller/12

  • https://{host}/opencell/api/rest/v2/generic/subscription/2

  • 200

  • 400

  • 404

POST

https://{host}/opencell/api/rest/v2/generic/{modelName}

JSON
{
    "code" : "instance_code"
    "description":"description ..."
}

create a new the instance of {modelName}

e.g.

  • https://{host}/opencell/api/rest/v2/generic/seller

  • https://{host}/opencell/api/rest/v2/generic/subscription

  • 200

  • 404

PUT

https://{host}/opencell/api/rest/v2/generic/{modelName}/{ID}

JSON
{
    "code" : "new_instance_code"
    "description":"new description ..."
}

update the {modelName} instance with ID equal to {ID}

e.g.

  • https://{host}/opencell/api/rest/v2/generic/seller/12

  • https://{host}/opencell/api/rest/v2/generic/subscription/2

  • 200

  • 400

  • 404

DELETE

https://{host}/opencell/api/rest/v2/generic/{modelName}/{ID}

none

delete the {modelName} instance with ID equal to {ID}

e.g.

  • https://{host}/opencell/api/rest/v2/generic/seller/12

  • https://{host}/opencell/api/rest/v2/generic/subscription/2

  • 200

  • 400

  • 404

Response customization


The following options allow to customize fields returned by the API nested entities depth.

Payload JSON object attributes

Description

Example

CODE
genericFields

The list of the model attributes you want to exclusively include in the response.

Please, note that you can include sub-fields when you have sub-models included in your response, by mentioning there path, separated by a dot, into genericFields list

e.g

"genericFields": ["id", "code", "customerCategory", "customerCategory.exoneratedFromTaxes"]

by this payload, you can load customer’s id and code, in addition to it’s referenced sub-model customerCategory’s exoneratedFromTaxes.

For this to work you need to fully load the customerCategory using nestedEntities

Payload

JSON
"genericFields": ["id", "code", "description"]

The response will then include the instance(s) id, code and description even if the model has other attributes.

Response

JSON
{
    "id": 1,
    "code": "MAIN_SELLER",
    "description": "Demo Distributor"
}

Payload

JSON
"genericFields": []

Response will then include all non null instance(s) attributes.

Response

JSON
{
    "id": 1,
    "auditable": {
        "created": 1426723459913
    },
    "code": "MAIN_SELLER",
    "description": "Demo Distributor",
    "defaultLevel": true,
    "accountType": "ACCT_S",
    "tradingCurrency": -1,
    "tradingLanguage": -1
}

CODE
excluding

A list of fields to be excluded from response.

This won’t work for nested entities, only for the main queried entity.

Please note, that you should not use both genericFields and excluding as results can be unreliable about whether or not the field will be included in the response.

We want to fetch provider data, except for custom fields:

Payload

CODE
"excluding": ["cfValues"]

Response

Will contain all fields from Provider entity except for the custom fields (cfValues).

CODE
nestedEntities

Represent the list of the model attributes that are also models themselves (sub-models e.g CustomerAccount’s BillingAccounts), you want to fully load and include in the response.

If you did not mention a sub-model in nestedEntities list, only your sub-model ID will be included in the response instead of the whole object.

You should note, that nestedEntities loading list, can go into deeper levels of referencing

e.g

You can load Customer → CustomerAccount → BillingAccount → UserAccount

JSON
"nestedEntities": ["Customer.CustomerAccount.BillingAccount.UserAccount"]

If you use both genericFields and nestedEntities, make sure that the nested entity is also in the queried fields, else it won't show on API response.

Fields from genericFields should not be listed in excluding else they won't show on API response.

You need to fetch all TradingCurrencies, with there referenced/sub-model currency instance, fully loaded.

Payload

JSON
"nestedEntities": ["currency"]

Response will then include all non null sub-model attributes of that sub-model

Response

JSON
{
    "id": -2,
    "auditable": {
        "created": 1426723459216
    },
    "disabled": false,
    "currency": {
        "id": 5,
        "auditable": {
            "created": 1426723440004
        },
        "currencyCode": "EUR",
        "descriptionEn": "Euro",
        "systemCurrency": true
    },
    "prDescription": "Euro",
    "currencyCode": "EUR",
    "active": true
}

The same example without any nested entity to include

Payload

JSON
"nestedEntities": []

Response

JSON
{
    "id": -2,
    "auditable": {
        "created": 1426723459216
    },
    "disabled": false,
    "currency": 5,
    "prDescription": "Euro",
    "currencyCode": "EUR",
    "active": true
}

The response will then include only the ID of any sub-model.

Paging and Filtering


In general, you can use filters to filter out you response, such as returning only instances that meet you filters conditions, the syntax is the following :

JSON
{
...
"filters": {

  "[prefix-condition-keyword] field-Name" : value,
  "[prefix-condition-keyword] field-Name" : value
}
...
}

Prefix condition keywords


Condition keyword

Description

fromRange

  • Field value in between from - to values.

  • Specifies "from" part value: e.g value<=field.value.

  • Applies to date and number type fields.

toRange

  • Field value in between from - to values.

  • Specifies "to" part value: e.g field.value<=value

list

  • Value is in field's list value.

  • Applies to date and number type fields.

inList

  • Field value is in value (list).

  • A comma separated string will be parsed into a list if values.

  • A single value will be considered as a list value of one item

minmaxRange

  • The value is in between two field values.

  • TWO field names must be provided.

  • Applies to date and number type fields.

minmaxOptionalRange

  • Similar to minmaxRange.

  • The value is in between two field values with either them being optional.

  • TWO field names must be specified.

overlapOptionalRange

  • The value range is overlapping two field values with either them being optional.

  • TWO field names must be specified.

  • Value must be an array of two values.

likeCriteria

  • Multiple field names can be specified. Any of the multiple field values match the value (OR criteria).

  • In case value contains *, a like criteria match will be used.

  • In either case case insensitive matching is used.

  • Applies to String type fields.

likeCriteriaOrIgnoreCase

likeCriteria, but case insensitive

wildcardOr

  • Similar to likeCriterias.

  • A wildcard match will always used.

  • A * will be appended to start and end of the value automatically if not present.

  • Applies to String type fields.

wildcardOrIgnoreCase

wildcardOr, but case insensitive

ne

Not equal.

SQL

If everything else fails, you can filter using a JPQL request.

or

useful to match a text with multiple text fields

"filters": {

“or code description firstName label“ : “[text to match with fields (code description firstName label) value]“

}

Nested filters


The example below returns all wallet operation concerning “chairs”, but rated by different charges.

JSON
POST https://{host}/opencell/api/rest/v2/generic/all/walletoperation
{
    "joinType": "INNER",
    "filters": {
        "$operator": "OR",
        "code": "CH_CHAIR",
        "$filter1": {
            "$operator": "AND",
            "code": "CH_MISC",
            "wildcardOrIgnoreCase parameter2": "chair"
        },
        "$filter2": {
            "$operator": "AND",
            "code": "CH_OTHER",
            "wildcardOrIgnoreCase parameter2": "chair"
        }
    }
}

Property

Values

Description

joinType

[RIGHT, INNER, LEFT]

Define the join type for nested entities.

INNER: returns rows when there is a match in both tables.
LEFT: returns all rows from the left table, even if there are no matches in the right table.
RIGHT: returns all rows from the right table, even if there are no matches in the left table.

default: INNER

$operator

[OR, AND]

Defines how individual items in the filter are combined.

default: AND

$filterX

{filter object}

A nested filter. It has the same grammer as any usual filter.
Nested filter can be cascaded (you can have a nested filter in a nested filter).

Filtering examples


Example

Description

JSON
"filters": {
  "code": "C_UA"
}

Here we filter by code field, this request’s response will include only entities with code equal to "C_UA"

JSON
"filters": {
  "likeCriterias name.lastName": "Dupon*"
}

This filter, applied on an account entity (such as Customer) will return all accounts where lastName ​starts with “Dupon”.
So it will return both “Dupont” and “Dupond” (and “Dupon123Whatever” for that matter).

JSON
"filters": {
  "userAccount.code": "C_UA"
}

Here we filter by nested entity userAccount's code field, this request’s response will include only entities with nested user account entity that have code equal to "C_UA"

JSON
"filters": {
  "userAccount.billingAccount.code": "C_UA"
}

Here we filter by nested entity userAccount > billingAccount's code field, this request’s response will include only entities with nested user account, with nested entity billing account, that have code equal to "C_UA"

JSON
"filters": {
  "minmaxRange startDate endDate": 1694988000000
}

Check if provided date is between to dates (this exemple if for wallet operation’s recurring start/end dates)

JSON
"filters": {
  "status": "ACTIVE",
  "code": "C_UA"
}

It is also possible to combine filters.

JSON
"filters": {
  "SQL":"tradingCurrency IN (SELECT b FROM org.model.billing.TradingCurrency b WHERE b.code = XXX)"
}

It is also possible to use SQL filtering like in the example, here we use an SQL sub query

JSON
"filters": {
  "SQL": "(SELECT b FROM org.meveo.model.billing.Invoice b WHERE b.id = 3) in elements(linkedInvoices)"
}

SQL filter to retrieve invoices linked to invoice id=3

JSON
"filters": {
  "cfValues": {
    "ORDER_SERVICE_ID": [ { "value": "DPL228647" } ]    
  }
}

this syntax is used to filter by Custom fields

One thing to note though, is that, filtering by Custom field of complex types, such as list, maps and matrices is not supported.

JSON
"filters": {
  "cfValues": {
      "inList EXTRA_STATUS": [ { "value": "'NEW','ACKNOWLEGED'" } ]
  }
}

To filter on custom field, with a list of values

One thing to note though, is that, filtering by Custom field of complex types, such as list, maps and matrices is not supported.

JSON
"filters": {
  "customerAccount.cfValues": {
    "wildcardOrIgnoreCase CustomerAccount_STRING": [  { "value": "GILD" } ]
  }
}

To filter on custom field in a nested entity using a case-insensitive text search.

GroupBy and Having clauses


Example

Description

"groupBy": ["userAccount.code"]

By using the group by attribute, we can group rows returned that have the same values into summary rows, like "find the sum of amount without tax and amount tax having a same user account" by userAccount.codefield

We can also group the rows by multiples data fields inside of an array as follows :

"groupBy": ["description", "id"]

JSON
{
    "genericFields": ["SUM(amountWithoutTax+amountTax)", "userAccount.code"],
    "groupBy": ["userAccount.code"],
    "having": ["SUM(amountWithoutTax+amountTax) > 250"]
}

The having clause is used to filter the rows and retrieve only those that match the requirement. It is a conditional statement that returns the results for the group created by the group by clause.

Aggregation is allowed for multiple fields.

For example, we want to look for walletOperations group by user account which have sum of amount without tax and amount tax greater than 250.

JSON
{
    "genericFields": [
        "offerTemplate.code",
        "COUNT(a.id)",
        "SUM(a.amountWithoutTax)",
        "AVG(a.amountWithoutTax)",
        "MIN(a.amountWithoutTax)",
        "MAX(a.amountWithoutTax)"
    ],
    "filters": {
        "invoice.status": "VALIDATED"
    },
    "groupBy": [
        "offerTemplate.code"
    ],
    "offset": 0,
    "isFilter": true,
    "sortBy": "offerTemplate.code",
    "sortOrder": "ASCENDING"
}

Available aggregation functions:

  • COUNT

  • SUM

  • MIN

  • MAX

  • AVG

These are the same as typical SQL aggregation functions.

JSON
{
    "limit": "10",
    "offset": 0,
    "sortBy": "id",
    "sortOrder": "DESCENDING",
    "genericFields": ["SUM(id+seller.id)", "description", "id"],
    "groupBy": ["description", "id"],
    "having": ["SUM(id+seller.id) > -8"]
}

We can also combine different other paging and filtering criteria such as limit, offset and sortBy and sortOrder.

And the fields that we want to sort by, we need to add them into genericFields to retrieve them in result

Behaviour adaptation for huge entities


If the entity you are querying is declared as a “huge volume entity”, generic API will not return the total number of records matching the filter (no total property in response).

These greatly improves API response time as a count is a costly operation.

If you really need to know the total number of results, you can use the forceCount parameter:

JSON
{
    "forceCount": true
}

JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.