API Reference
The Propeller REST API is based on resource-oriented URL's, returns JSON-encoded responses and uses standard HTTP response codes, authentication and HTTP methods. The main goal of the REST API is efficiently importing/exporting large amounts of data in/out of the Propeller platform.
HTTP methods
Propeller REST API supports POST, GET, PATCH, and DELETE HTTP methods.
Authentication
The REST API uses the oAuth 2.0 client credentials grant type for authentication, every API requests needs a valid access token.
Request an access token
- Request an access token by executing a POST request to the token endpoint. This POST request should include the Client Id and Client Secret.
- A successful access token request will return the following result:
{
"refresh_token_expires_in": "0",
"api_product_list": "[Propeller REST APIs]",
"api_product_list_json": [
"Propeller REST APIs"
],
"organization_name": "propeller-platform-prod",
"developer.email": "developer@propel.us",
"token_type": "BearerToken",
"issued_at": "1646873717224",
"client_id": "veNqlG9u5JAce1AccAnuiqxFL1NvVMHS0H8Qu8omHBW7ykjT",
"access_token": "ARAo4GjuI1bGSyenSKx5oYfFGuFQ",
"application_name": "a1ca275a-2abb-4bd3-82b0-3ae699d75e40",
"scope": "",
"expires_in": "1899",
"refresh_count": "0",
"status": "approved"
}
-
Parse the
access_token
value from this result and use it as a bearer token in subsequent API requests. -
After 30 minutes the requested
access_token
expires and a new token needs to be requested.
Lookup keys
The REST API offers multiple ways to identify resources. In Propeller terminology these are called lookup keys. For example: a product can be identified by its Propellor internal id
but also by an sku.
A sku
however, is not guaranteed to be unique in the catalogue, as multiple products
with the same sku
can exist. If multiple resources are found based on the lookup key / value combination the result of the request will be an error. In case of multiple products
with the same sku
a GET or PATCH request to this product will result in an error.
Lookup Key | Description |
---|---|
id | Unique Propeller id of an object |
externalId | Unique external id |
sourceId/source | External system unique id to a Propeller resource. sourceId always needs to be combined with a source . Source is typically the name of a supplier or ERP system the data originates from. |
sku | Stock-keeping unit code referencing a product |
supplierCode/supplier | Code of a supplier referencing a product |
code | Code referencing any other resource (e.g. a pricesheet) |
Source Id/ Source lookup key is most commonly used in Bulk endpoints. If you're creating/ updating products from an external system, the name of that system would typically be the source
and sourceId
would be the product's id or code in that system. This id should be unique in that system and the combination source/sourceId is unique in Propeller. When using the GET, DELETE, UPDATE endpoints with lookup key sourceId
you can use it without source
, but if multiple resources are found you will get an error. In that case use source
as well.
Supplier code / supplier is another common way of looking up products. The difference between the sourceId is that the combination does not have to be unique. When it's not and you try to use the GET, UPDATE, DELETE endpoints you will get an error that multiple resources have been found.
Expanding resources
Some resources allow to request additional information as an expanded resource by using the expands
request parameter. This parameter is available on all GET REST API requests and applies to the response of that request only.
In many cases, an object contains a related object in its response properties. For example, an Orderitem
may have an associated Product
id. Those objects can be expanded inline with the expands
request parameter.
Expand parameter | Description |
---|---|
orderItems | expands the order resource with orderItems |
orderItems.product | expands the orderItems resource with the product resource |
translation | expands translated fields for all available languages. |
inventoryBalance | expands all inventory resources for a product |
defaultProduct | expand the cluster or option resource with the default product resource |
Pagination
Querying resources and especially retrieving a lot of data can be potentially really expensive. Therefor, endpoints that retrieve a lot of results are paginated. Use page
and offset
query parameters to request a certain page of the result in GET endpoints. When using search endpoints (POST HTTP method), page
and offset
are part of the payload.
Page
You can request a certain page of the result using the page
query/ payload parameter.
Offset
You can set the maximum number of results to return using the offset
query/ payload parameter. The minimum value is 1
and the maximum can differ per API. This is specified in more details in endpoints that support pagination. The default offset
on most endpoints is 12
.
Response
This response retrieves 2 results in the data, the number of results per page is 2 and page requested is 1. total
is the number of records for the page requested, while itemsFound
is the total number of results.
{
"data": [
{
id: 56897
},
{
id: 36975
}
],
"messages": [
"Completed"
],
"start": 1,
"pages": 20,
"total": 2,
"offset": 2,
"itemsFound": 35,
"end": 2,
"page": 1
}
Errors
This section describes error codes used in the Propeller platform REST APIs and their meaning. For details about the API-specific error-codes, consult the documentation dedicated to that API.
Code | Error Type | Status Code | Message | Reason |
---|---|---|---|---|
10005 | InvalidJSONPayload | 400 | Invalid JSON Payload | JSON provided in payload is not valid |
10006 | InvalidLookupKey | 400 | Invalid lookup key | Lookup key is not supported in the specific API. Check API specific lookup keys |
10007 | SchemaValidationException | 400 | Schema Validation Error | JSON schema validation. Response contains the details of the issue |
10008 | NotFound | 404 | Resource not found | Resource deleted, non-existing or insufficient permissions |
10015 | PaginatedResponseException | 400 | Pagination not properly initialized | offset or page are not initialized properly. These should be positive integers. Possible maximum limit exceeded on offset |
10016 | LookupKeyNotFound | 400 | Lookup key not found in payload | Bulk endpoints by a certain lookup key require that the lookup key is provided in the payload |
10017 | PayloadValidationError | 400 | Payload validation error | Server side validation of the payload. Response contains the details of the issue |
10018 | TranslationNotFound | 404 | Translation not found | Resource deleted, non-existing or insufficient permissions |
10019 | WarehouseNotFound | 404 | Warehouse not found | Resource deleted, non-existing or insufficient permissions |
10020 | WarehouseInvalidConfiguration | 400 | Warehouse invalid configuration | Warehouse not properly configured, e.g. not a pick up location |
Error Response
When an API call results in an error, the response contains the error
property which is an object with the following properties:
Property | Type | Description |
---|---|---|
code | string | Error code. Generic error codes are listed here, while API specific error codes are listed in each API |
status | integer | Status code |
type | string | Error type. Generic error types are listed here, while API specific error types are listed in each API |
messages | array[string] | An array of error messages |
moreInfo | string | URL to a page containing details about the error (under construction) |
Example error response:
{
"error": {
"code": 80006,
"status": 404,
"type": "ProductNotFound",
"messages": [
"Product with id [481189] not found"
],
"moreInfo": "https://www.propel.us/docs/errors/80006"
}
}
Localized String
A localized string is a JSON object used for fields that are translatable. A localized string has two properties: to indicate the language as per ISO 639-1 and the value of the translated field in that language.
{
"language": "EN",
"value": ""
}
Bulk endpoints
Bulk endpoints allow for an efficient way of importing/updating large amounts of data with just a single API call. Traditional REST API functionality would allow for a single resource (e.g. a product
or user
) to be created and a second API request to update this resource. Creating and/or updating multiple resources would mean executing multiple API requests. Working with larger number of resources means this approach would generate a significant number of API calls resulting in inefficient use of resources and import processes taking a lot of time.
The Propeller REST API offers "bulk" functionality to efficiently import/update resources. A bulk request typically contains a payload of multiple resources of a single type (e.g. product, user, category or inventory). Based on the lookupKey Propeller will decide if a resource needs to be created or updated.
Bulk endpoints take away the need for multiple API calls to determine if a resource needs to be created or updated and allow for creating/updating multiple resources in on API request.
Directives
Directives are a powerful Propeller REST APIs concept only used in bulk endpoints. Use directives for actions that are otherwise only doable via a lot of single endpoint API requests. Directives concept is easiest to understand via use cases.
- Let's assume a large number of products is being created/ updated using the Product Bulk endpoint and Propeller's back office is used to maintain some of the data, e.g. product names. When products are created via the bulk endpoint they should not be created with an empty product name. That name can later be changed and we don't want to overwrite it. If it were a single resource endpoint, the GET endpoint could be used to check if the product exists, find the name, compare it, etc. That is not really efficient on a large scale. This is where
skipIfNotEmpty
directive comes handy. Use this directive when you only want to set a field with the value from the payload if it's current value is an empty string. - Another use case is using Propeller to move resources in a different parent container that the one they were originally created in. Let's assume you have a list of products that belong in certain categories and those products are created via the Bulk endpoints. If you decide to maintain the catalogue structure from within Propeller you would typically move products around manually or via Propeller's rule engine. To avoid a Bulk endpoint would move them back to their original endpoint, use the
skipMoveOnUpdate
directive. - When creating categories/ product translations you typically have a list of all the active translations you want the resource to be translated in. When using a single resource endpoint you can delete translations one by one, but in the Bulk endpoints use
mergeTranslationsOnUpdate
to reset i.e. delete the ones that are not in the payload.
Name | Description | Fields |
---|---|---|
skipIfNotEmpty | On update, skip updating fields of an existing resource that are not empty | array of field names, API specific e.g. for products : names , descriptions , etc. |
skipMoveOnUpdate | On update, skip moving an existing resource in the parent resource provided | empty array |
mergeTranslationsOnUpdate | On update, delete all translation for a resource that are not provided in the payload | empty array |
skipCreate | Skip creating new, only update existing resources | empty array |
Use Cases
Usergroups - users bulk import
The user rest api is typically used in a B2B environment where a predefined set of customers is allowed access to a webshop / portal. Typically those customers are managed in an ERP and/or CRM system and in order for these customers to have access to the webshop, they need to have an account in Propeller meaning these customers need to be imported into Propeller.
A common way for an ERP/CRM system to handle the concept of customers is to have an entity called customer/debtor or relation and within this entity there are one or multiple contacts. The customer/debtor in this case is a company/organization and has a unique debtorId
. The contacts are typically persons within the organization with each their own e-mail address/telephone number and multiple different invoice, delivery and visiting addresses.
A typical way to get the ERP / CRM customers into Propeller is to create a Propeller usergroup for each customer and within this usergroup
, for each contact, a Propeller user
.
Most of the time the number of customers/contacts which need to be imported will be multiple thousands (if not more). In these cases it is important to use the user and usergroup bulk endpoints, these make sure creating/updating the usergroups / users / addresses / attributes is done in efficiently.
To create the usergroups
and users
in Propellor two different bulk endpoints need to be used:
Via the usergroup bulk endpoint multiple usergroups representing companies will be created:
{
"usergroups": [
{
"sourceId": "x-123",
"source": "MBC",
"language": "EN",
"parent": {
"sourceId": 999112000
"source": "MBC"
},
"name": "Company X"
},
{
"sourceId": "y-456",
"source": "MBC",
"language": "EN",
"parent": {
"sourceId": 999112000
"source": "MBC"
},
"name": "Company Y"
},
{
"sourceId": "z-789",
"source": "MBC",
"language": "EN",
"parent": {
"sourceId": 999112000
"source": "MBC"
},
"name": "Company Z"
}
]
}
The above usergroup bulk endpoint will create or update three usergroups. In this case we use the sourceId / source combination as lookupKey / lookupValue combination. When using the sourceId / source combination as lookup key, it's possible to identify resources in Propeller based on keys / identifiers from the ERP / CRM system. In the usergroup example, the source
of the data is Microsoft Business Central (MBC) and the sourceId
is a unique id / code for a certain customer / organization in Microsoft business central. The combination of the source
and sourceId
field will make sure there is only one resource found when referencing a usergroup based on these lookup values.
In advanced setup's its possible to import resources (e.g. customers / contacts) from multiple sources, If usergroups / users would also be imported from a second ERP / CMS system there is a change the sourceId
would not be available anymore since it is used already by the first import. Because Propeller uses the combination of sourceId
/ source
to uniquely identify a resource it is possible to import data from multiple different sources using the same sourceId's. A second usergroup import from e.g. Exact Globe could look like this:
{
"usergroups": [
{
"sourceId": "x-123",
"source": "EXACTGLOBE",
"language": "EN",
"parent": {
"sourceId": "999112000"
"source": "EXACTGLOBE"
},
"name": "Company XX"
},
{
"sourceId": "y-456",
"source": "EXACTGLOBE",
"language": "EN",
"parent": {
"sourceId": "999112000"
"source": "EXACTGLOBE"
},
"name": "Company YY"
},
{
"sourceId": "z-789",
"source": "EXACTGLOBE",
"language": "EN",
"parent": {
"sourceId": "999112000"
"source": "EXACTGLOBE"
},
"name": "Company ZZ"
}
]
}
In this case the sourceId's from MBC and Exact Globe are the same but because Propeller uses the additional field source
to identify a resource it is possible to keep using the identifiers generated by the ERP / CRM.
Once the usergroups
are created the users can be created via the user bulk endpoint. To make sure a user
is created inside the correct usergroup
within the user
resource a parent object is added pointing to the usergroup
using the source
/ sourceId
of the usergroup
{
"users": [
{
"source": "MBC",
"sourceId": "3002196",
"language": "NL",
"parent": {
"sourceId": "x-123",
"source" : "MBC"
},
"firstName": "Miles",
"middleName": "",
"lastName": "McCoy",
"debtorId": 12345,
"login" : "miles@xx.com"
"company" : "Company X"
"email": "miles@xx.com",
"mobile": "001445888",
"phone": "001445888",
"title": "Mr.",
"gender": "M"
},
{
"source": "MBC",
"sourceId": "3002197",
"language": "NL",
"parent": {
"sourceId": "x-123",
"source" : "MBC"
},
"firstName": "Bernie",
"middleName": "",
"lastName": "Sawer",
"debtorId": 12345,
"login" : "bernie@xx.com"
"company": "Company X",
"email": "bernie@xx.com",
"mobile": "001445888",
"phone": "001445888",
"title": "Mr.",
"gender": "M"
},
{
"source": "MBC",
"sourceId": "3002200",
"language": "NL",
"parent": {
"sourceId": "x-456",
"source" : "MBC"
},
"firstName": "Delia",
"middleName": "Ferdi",
"lastName": "Finney",
"debtorId": 67890,
"login" : "Delia@yy.com"
"company": "Company Y",
"email": "bernie@yy.com",
"mobile": "001445888",
"phone": "001445888",
"title": "Ms.",
"gender": "F"
}
]
}
A user / usergroup import is something which needs to be executed frequently since changes in the ERP / CRM should be made available in Propeller, new customers need to get access to the webshop and in certain situations access to the webshop needs to be revoked. Using the bulk endpoints, the payload only needs to be defined once without any logic.
Order export
Order searching is typically used in combination with exporting orders to ERP/financial/other external systems. Within the Propeller order workflow there will be the need to export orders at a certain point. Most of the times the need to export an order is when the order transitions to a certain status (e.g. CONFIRMED). Via the order search api it is possible to retrieve a list of orders which are in status CONFIRMED and have not been exported yet (using the fields below)
{
"status": "CONFIRMED",
"exported": false
}
Once the orders have been exported it is good practice to update the order and mark it as "exported" field using the order update api. Searching for orders with the above payload will then only result in an list of orders without the previously exported orders.
Authentication
- HTTP: Basic Auth
- HTTP: Bearer Auth
- OAuth 2.0: OAuth2
Security Scheme Type: | http |
---|---|
HTTP Authorization Scheme: | basic |
Security Scheme Type: | http |
---|---|
HTTP Authorization Scheme: | bearer |
OAuth2 Authorization
Security Scheme Type: | oauth2 |
---|---|
OAuth Flow (clientCredentials): | Token URL: https://api.helice.cloud/oauth2/token/ Scopes: |