Introduction
Welcome to the GPS API documentation.
GPS – the Global Product System from Corporate Rewards Ltd exposes a RESTful JSON API over HTTPS. For information on how RESTful APIs are designed, how they work and what benefits they offer over more traditional styles of API, see https://en.wikipedia.org/wiki/Representational_state_transfer For more information about JSON, what it looks like and how to use it, see http://www.json.org/ or https://en.wikipedia.org/wiki/JSON
There are two principle use-cases for accessing this system using the API, Ordering systems and Supplier systems. Ordering systems consume product information for the purposes of displaying products to an end user. Ordering systems can then place orders for these products through the API. Orders are processed by GPS and passed to suppliers who then fulfil these orders. Updates to orders, their status and related information will come back to Ordering systems over the API.
Endpoint | Use case |
---|---|
GET /api/v2/categories | Orderer |
GET /api/v2/regions | Orderer |
GET /api/v2/catalogues | Orderer |
GET /api/v2/catalogues/{catalogue_id}/products | Orderer |
GET /api/v2/orders | Orderer & Supplier |
POST /api/v2/orders | Orderer |
POST /api/v2/orders/{order_id}/accept | Supplier |
POST /api/v2/orders/{order_id}/reject | Supplier |
POST /api/v2/orders/{order_id}/dispatch | Supplier |
GET api/v2/products | Supplier |
POST api/v2/products | Supplier |
PATCH api/v2/products/{product_id} | Supplier |
PUT api/v2/products/{product_id} | Supplier |
DELETE api/v2/products/{product_id} | Supplier |
Product information can be quite dynamic in that Suppliers can modify the data for a product (such as media/images, prices, availability etc.) at any time. We recommend pulling or refreshing the product data approximately every 24 hours. It is typical for an ordering system to maintain a local store of some sort (cache, database tables etc.) for this product data to allow end users to access this data efficiently.
If a product is made unavailable between the times that data is refreshed, then orders for this product will fail with an appropriate error message indicating why the order failed. Order information can also be pulled through the API to periodically update order information, again, it is recommended that the Ordering system keep some kind of local store of the order information which can be periodically updated (some Ordering systems can poll as much as once an hour to refresh order related information).
There is an additional, optional method for getting updates to orders called “Pingback” which is documented in the ordering section. This method offers “near real-time” order updates for the ordering system that placed the order, that is to say that when an order is updated with GPS a call will be made to the ordering system - this is a prompt for the ordering system to fetch updated order information.
The first thing you will have to find out is the correct API endpoint to use for the right environment.
- Staging: https://greenstone.my-rewards.co.uk
- For production access, please contact your Corporate Rewards representative
A programme can have one or more API keys, each of which will be granted permission to access different functionality from the API. As a standard, we use RESTful json endpoints that will accept either HTML/HTTP form data or json data, HTML/HTTP is preferred.
Authentication
In order to use our API endpoints, you will need to have an API token created and
for this token to be granted the relevant permissions. To authenticate requests we
require you to pass us this token in the form of an HTTP header called
Authorization
with the value of Token token=YOURAPITOKENHERE
.
Failure to supply a recognised key in the correct format will result in a 403 HTTP response code and an error message: HTTP Token: Access denied.
Your API token should have the following format consisting of an API key followed by a API secret, separated with a colon like so: abcdefghijklmnopqrst:uvwxyz1234567890abcdefghijklmnop
Typical process flow
Ordering systems
The typical process flow indicates how to consume information from this API, the order in which it makes sense to do this and some suggestions on how to make efficient use of this service.
Categories are fairly stable and do not change too often. We recommend checking this endpoint and synchronising the information from here to your local store at most once per day and at least once per month. Ordering systems are free to organise the product data however they wish - these categories are provided as suggestions and are actively managed but are not mandatory.
The typical process for fetching product information is to iterate over each available Catalogue, fetching the products for each one. Check to see if you have a local copy of each Product, if the data for the Product is new or has changed since the last sync, store this Product data. If at the end of the list there are local Products you have not seen in the latest sync of Product data, they should be removed from the local store.
In order to find a list of products to show an end user, the ordering system should be able to find products by country. A user should therefore be able to see a list of products available to them in their country. Order information can be synchronised much more frequently, we recommend usage of the since parameter to restrict the volume of data being listed in each call the fetch Order information. The since parameter will filter the Orders endpoint to show only Orders that have been updated since a specified datetime. For instance, if Order information is synced every hour, then the since parameter should be used to request Orders updated in the last hour. An overlap can be used to ensure order updates are not missed.
There is also a pingback capability – to allow for near real-time Order updates. We recommend using a combination of both approaches to allow prompt updates and ensure nothing is missed.
Suppliers
Suppliers will need to fetch order information from the API periodically (polling) and act accordingly. To act on an order one of the documented order actions will be required.
When an order is created, we can send an email notification. This could be used as a prompt to fetch new order information but we would recommend polling be carried out in parallel. If using email notifications for this purpose, an integration would have to take account of the various concurrent requests and actions.
Function overview
Each of the main objects/entities available from GPS are introduced along with recommendations for how to use these in your ordering system.
Categories
Categories are also provided as a service/endpoint, while these are reasonably stable, we do recommend syncing the categories you keep locally against this service every time you go to pull product information. The Products will refer to these categories. You can of course decide to categorise Products in your own way and ignore the Product Categories from GPS – we provide these Categories (as we use them ourselves) for your reference, should you require.
Regions
We supply a list of all the countries rewards are available in by geographical region. The country name, ISO code and the id of this country as used by our system is available from the GPS API. It is possible that not every country available from GPS will have rewards in that you have been allocated on your API key.
Catalogues
Catalogues are the primary dimension along which we organise our products. An API key is granted access to one or more catalogues according to the requirements of the Ordering system and their agreement with Corporate Rewards. Catalogue allocation is also quite stable but we recommend iterating over each Catalogue in order to fetch product information to ensure that you are always getting the correct information.
Products
Once a list of Catalogues is obtained, a list of products should be fetched from this catalogue. Depending on the catalogue there may be hundreds of products so this call may take several seconds to complete. There are parameters provided to manipulate the information coming back from the API - see the Catalogues section later.
When getting Product information, we recommend checking each individual product in the feed (perhaps by hashing or somehow fingerprinting the actual product information) to see if it is new or has changed before adding it to the local store. This can speed up your processing of Products. It is possible that some products will have been removed from the feed, you will need to react to this situation and remove the product from your local store in this case.
Variants and Vouchers
If we take an example case for a product that is available in a variety of colours, this information is stored against a product as a series of one or more variants against a 'base product'. For instance, the Apple iPhone is available by default in black as the base product but can also be ordered in variants of gold or rose gold - therefore there are two elements under the variants key for this product. These variants are chiefly differentiated by their variant SKU and the description of the reason for the variation. This means that we can have one product with a total of three variants as opposed to 3 products - there is one restriction, namely that the price of all these variants must be the same. When ordering you will need to provide the product_id and the SKU of either the product or the chosen variant.
When vouchers were added to the product catalogue, it was decided to use the product variant capability to store denominations for a voucher rather than add a new product for every denomination of a voucher. This does break the rule that all product variants must cost the same, so this lead to the introduction of the voucher flag - a boolean attribute on the product. This is used to indicate that this product is a set of voucher denominations (as opposed to a merchandise type product). The way voucher type products are configured is as follows:
- The lowest denomination voucher details are used to create the product, this also creates a single variant (denomination)
- Subsequent denominations are also added as variants
- The description of the voucher denomination is always recorded as the variant attribute (i.e. $500) and is suitable for displaying to users as a choice
- To reflect the GBP pricing expected of regular products and to allow a similar price calculation by ordering systems, each denomination has
face_value_gbp
andvariant_base_price
attributes which are calculated in GBP with any relevant/agreed markup in place
An ordering system should calculate the cost of a voucher denomination using the variant_base_price
attribute
Price calculation
Products will be available in a set of one or more Countries however the base_price cost of an Product will always be presented in Pounds Sterling to an ordering system. To calculate the cost of an Order to an ordering system, the delivery Country will need to be known. The cost of the Product plus tax is calculated using the base_price field value then adding the sales tax using the Products vat_rate field value. This subtotal needs to be added to the delivery cost for the destination country. To calculate the delivery cost, use the delivery_charge value from the destination country your Order is being delivered to and add in the vat_rate for the delivery charge. This yields:
Product (base_price + vat_rate) + (available_countries{delivery_charge + vat_rate})
Orders
Once your local store of Regions, Catalogues, Categories and Products are up to date, products can be displayed to users for them to order. Ordering systems have to decide if a user is eligible to order a product (has enough points or is over the minimum age) and pass the order information to GPS, if the order can be placed, GPS will respond with the Order information.
An order can only ever be created for one product, referenced primarily by its id. In order to facilitate more flexible ordering of vouchers and prepaid cards, GPS requires orders to be created with one or more line items.
An order for a physical product should have one line item describing the product, it’s variant (SKU) and quantity required. When ordering a voucher or prepaid card, it is possible to order a combination of voucher/top up denominations. For instance, a user may wish to order a certain amount of points worth of credit on a prepaid card such as a £10, £20 and 3 multiples of a £50 credit/top up totalling £180, rather than processing 3 separate orders, a user can (and should be provided with the relevant user interface to do so) place one order for all the required amounts.
In the case of ordering multiple denominations of a voucher product, the product_id is required as an order attribute and each combination of SKU (for the particular denomination) and quantity are supplied in the line_item attributes.
Calculating the cost of an order
In order to calculate to total cost of an order, the following calculations apply, given that:
p = product.base_price * (1 + product.vat_rate)
q = line_item.quantity
c = product.available_countries[order.country]
d = c.delivery_cost * (1 + c.vat_rate)
Then the gross cost of an order for an order of a physical product is:
(p + d) * q
However for voucher products (indicated by product.is_voucher = true
) the calculation is different. A voucher typically has variants which are used as denominations and as such, each denomination will have it's own base_price
(as opposed to the base_price
against the product). Orders for vouchers can have multiple line_items
, each for a different denomination. To calculate the gross cost of an order for one or more vouchers:
For each line item, given that:
v = product.variants[order.line_items.line_item.product_sku]
p = v.variant_base_price * (1 + product.vat_rate)
q = line_item.quantity
s = p * q
then:
t = the sum of s for each line_item
c = product.available_countries[order.country]
d = c.delivery_cost * (1 + c.vat_rate)
So the grand total with the delivery cost is:
t + d
An order for one or more vouchers is only charged one delivery_cost in total
Ordering systems can then charge whatever mark-up on top of the calculated cost of the order they choose as well as converting to whatever local ‘currency’ is used to present orders to the end user. Many ordering systems use ‘Points’ to obscure the true value/cost of a Product. A ratio of points/Pound is typically chosen by the ordering system.
We strongly suggest coupling the charge to an end user with the total cost of the order.
Completed orders
Once and order is complete, the Ordering system should store order information (returned from a successful placement of an order) locally together with information to identify which user this Order information was for. Orders are created with a state (status) of Pending. When a supplier accepts an Order it moves to Processing, when dispatched by a supplier the Order state is set to Dispatched and tracking information is provided when available. If a pingback URL is supplied (when creating the order) that uniquely identifies this order on your system, whenever a change is made to the order in GPS a simple GET request will be made to this URL. This should signal the ordering system to fetch the updated information for this order. This is optional but will provide a near-realtime update for an order including tracking information.
It is possible to request a list of orders made by your programme/API key and it is possible to filter the order using the parameters detailed in the section pursuant to orders below.
We recommend that ordering systems periodically sync order information with GPS to track changes in order status and show this information to end users. Relying solely on the pingback URL mechanism is not recommended as it may result in stale information on the ordering side if the pingback is not successful - a ping back is only sent once
Translations
Some endpoints in V3 of the API have translations available under the translations
key, which is an array of all the translations available for that resource.
Attribute | Description |
---|---|
locale |
The locale code for the set of translations. This is generally an ISO 639-1 code, or where translations are available for the same language across multiple countries or regions, a BCP 47 code is used |
<attribute> |
Each translated attribute has a key - for example, if the name attribute of a resource has translations available, there will be a name attribute in each translation object |
Note that GPS' native locale is British English (en-GB
) and will not be present in any translations
array.
Not all locales may be completed for all resources, but generally all attributes within a locale should be complete.
The following resources have translations available:
Resource | Attributes |
---|---|
Category | name |
An example payload for a fictitious resource is given on the right (below on mobile).
{
"name": "name in British English",
"description": "description in British English",
"translations": [
{
"locale": "es",
"name": "name in Spanish",
"description": "description in Spanish"
},
{
"locale": "fr",
"name": "name in French",
"description": "description in French"
}
...
]
}
Categories
List categories
V2
This endpoint fetches a JSON array of categories. There is a simple parent relationship represented using the parent_id
field. This enables an ordering system that chooses to use the Categories from GPS to re-create the category structure. Product data has a reference to the GPS Category they are in using the category_id
field.
Request
GET /api/v2/categories HTTP/1.1
Authorization: Token token=xxx
Response
HTTP/1.1 200 OK
Content-Type: application/json
[
{
"id" : 1,
"name" : "category name",
"parent_id" : null
},
{
"id" : 2,
"name" : "category name",
"parent_id" : 1
}
...
]
HTTP Request
GET /api/v2/categories
V3
Behaves the same as V2, but includes translations (where available).
Request
GET /api/v3/categories HTTP/1.1
Authorization: Token token=xxx
Response
HTTP/1.1 200 OK
Content-Type: application/json
[
{
"id" : 1,
"name" : "category name",
"parent_id" : null,
"translations": [
{
"locale": "fr",
"name": "category name in French"
},
{
"locale": "es",
"name": "category name in Spanish"
}
]
},
{
"id" : 2,
"name" : "category name",
"parent_id" : 1,
"translations": []
}
...
]
HTTP Request
GET /api/v3/categories
Regions
List all Regions and the Countries within them
This endpoint fetches a JSON array of Regions each with an array of countries in that region. Each region will show a list of the countries in that region as a nested list of objects.
Request
GET /api/v2/regions HTTP/1.1
Authorization: Token token=xxx
Response
HTTP/1.1 200 OK
Content-Type: application/json
[
{
"id" : 1,
"name" : "Western Europe",
"countries" : [
{
"id" : 1,
"name" : "United Kingdom",
"currency_id" : 2,
"vat_rate_id" : 6,
"iso_code" : "UK",
"dialing_code": "+44",
"currency": {
"id": 1,
"title": "Pounds Sterling",
"abbreviation": "GBP",
"sign": "£",
"name": "Pounds Sterling",
"exchange_rate": 1
}
},
{
"id" : 2,
"name" : "France",
"currency_id" : 6,
"vat_rate_id" : 3,
"iso_code" : "FR",
,
"currency": {
"id": 2,
"title": "Euro",
"abbreviation": "EUR",
"sign": "€",
"name": "Euro",
"exchange_rate": 1.23
}
}
]
},
...
]
HTTP Request
GET /api/v2/regions
Catalogues
List all Catalogues
This endpoint fetches a list of all catalogues available for your API key.
Request
GET /api/v2/catalogues HTTP/1.1
Authorization: Token token=xxx
Response
HTTP/1.1 200 OK
Content-Type: application/json
[
{
"id" : 1,
"name" : "Core",
"exclusive": false,
"created_at": "2014-10-27T12:22:26.000Z",
"updated_at": "2014-10-27T12:22:26.000Z"
},
{
"id" : 2,
"name" : "Vouchers",
"exclusive": false,
"created_at": "2014-10-27T12:22:26.000Z",
"updated_at": "2014-10-27T12:22:26.000Z"
},
...
]
HTTP Request
GET /api/v2/catalogues
List all products in a catalogue
V2
This is how ordering systems will access the products available to them. Typically, after fetching a list of catalogues, an ordering system will iterate over each catalogue, fetching the products in each one to add to a local store/cache of products.
Request
GET /api/v2/catalogues/{id}/products HTTP/1.1
Authorization: Token token=xxx
Response
HTTP/1.1 200 OK
Content-Type: application/json
[
{
"id": 357,
"name": "Product Name",
"base_price": 158.27,
"description": "Product Description",
"model_no": "A-123",
"sku": "A-123",
"available": true,
"availability_note": "",
"international_requirements": false,
"minimum_age": null,
"primary_image_id": 337,
"variant": "",
"voucher": null,
"lowest_denomination": null,
"face_value": null,
"supplier_currency_id": 31,
"available_countries": [
{
"id": 140,
"name": "UK",
"vat_rate": "20%",
"delivery_charge": 7.2
},
{
"id": 165,
"name": "Albania",
"vat_rate": "20%",
"delivery_charge": 34.75
},
...
],
"rrp": "159.99",
"supplier": {
"id": 14
},
"vat_rate": {
"name": "20%",
"numeric": 20
},
"status": {
"name": "Approved"
},
"catalogue": {
"id": 8,
"name": "Demo Catalogue",
"exclusive": false
},
"categories": [
{
"id": 62,
"name": "Necklaces",
"parent_id": 59
}
],
"variants": [
{
"id": 529,
"variant": "small",
"sku": "B-123",
"available": true,
"product_sku": "A-123",
"face_value": null,
"product_id": null,
"voucher_status": false,
"variant_base_price": null,
"face_value_gbp": null
},
{
"id": 530,
"variant": "large",
"sku": "B-234",
"available": true,
"product_sku": "A-123",
"face_value": null,
"product_id": null,
"voucher_status": false,
"variant_base_price": null,
"face_value_gbp": null
}
],
"media": [
{
"id": 337,
"url": "https://images.com/123533.jpg"
}
],
"delivery_type": {
"id": 1,
"name": "Physical",
"requires_address": true
},
"currency": {
"title": "Pounds Sterling",
"abbreviation": "GBP",
"sign": "£"
}
},
...
]
HTTP Request
GET /api/v2/catalogues/{id}/products
URL Parameters
Attribute | Type | Info |
---|---|---|
id | integer | primary key for catalogues |
Body Parameters
Attribute | Type | Info |
---|---|---|
status | string | ordering systems will only see products with a status of approved - this is largely functionless for ordering systems |
minimum_age | integer | when present only products suitable for a minimum age of this value will be shown - for instance a value of 18 will only list products that have either no minimum age or a value greater then or equal to 18 |
delivery_type | string | String (may be comma separated) delivery_types are typically Physical, Email, Downloadable and Prepaid. Products will only have this or these delivery type if this parameter is used |
country | string | This should be a proper case, URL-encoded string of a Country name (as reported in the Regions endpoint). Only products available in this country will be listed |
V3
Behaves the same as V2, but includes translations (where available).
Request
GET /api/v3/catalogues/{id}/products HTTP/1.1
Authorization: Token token=xxx
Response
HTTP/1.1 200 OK
Content-Type: application/json
[
{
"id": 357,
"name": "Product Name",
"base_price": 158.27,
"description": "Product Description",
"model_no": "A-123",
"sku": "A-123",
"available": true,
"availability_note": "",
"international_requirements": false,
"minimum_age": null,
"primary_image_id": 337,
"variant": "",
"voucher": null,
"lowest_denomination": null,
"face_value": null,
"supplier_currency_id": 31,
"available_countries": [
{
"id": 140,
"name": "UK",
"vat_rate": "20%",
"delivery_charge": 7.2
},
{
"id": 165,
"name": "Albania",
"vat_rate": "20%",
"delivery_charge": 34.75
},
...
],
"rrp": "159.99",
"supplier": {
"id": 14
},
"vat_rate": {
"name": "20%",
"numeric": 20
},
"status": {
"name": "Approved"
},
"catalogue": {
"id": 8,
"name": "Demo Catalogue",
"exclusive": false
},
"categories": [
{
"id": 62,
"name": "Necklaces",
"parent_id": 59
}
],
"variants": [
{
"id": 529,
"variant": "small",
"translations": [
{
"locale": "fr",
"name": "petit"
},
{
"locale": "de",
"name": "klein"
}
],
"sku": "B-123",
"available": true,
"product_sku": "A-123",
"face_value": null,
"product_id": null,
"voucher_status": false,
"variant_base_price": null,
"face_value_gbp": null
},
{
"id": 530,
"variant": "large",
"sku": "B-234",
"available": true,
"product_sku": "A-123",
"face_value": null,
"product_id": null,
"voucher_status": false,
"variant_base_price": null,
"face_value_gbp": null
}
],
"media": [
{
"id": 337,
"url": "https://images.com/123533.jpg"
}
],
"delivery_type": {
"id": 1,
"name": "Physical",
"requires_address": true
},
"currency": {
"title": "Pounds Sterling",
"abbreviation": "GBP",
"sign": "£"
},
"translations": [
{
"locale": "fr",
"name": "product_name_french",
"description": "product description_french"
},
{
"locale": "de",
"name": "product_name_german",
"description": "product description_german"
}
]
},
...
]
HTTP Request
GET /api/v3/catalogues/{id}/products
Attributes
Attribute | Type | Info |
---|---|---|
status | string | ordering systems will only see products with a status of approved - this is largely functionless for ordering systems |
minimum_age | integer | when present only products suitable for a minimum age of this value will be shown - for instance a value of 18 will only list products that have either no minimum age or a value greater then or equal to 18 |
delivery_type | string | String (may be comma separated) delivery_types are typically Physical, Email, Downloadable and Prepaid. Products will only have this or these delivery type if this parameter is used |
country | string | This should be a proper case, URL-encoded string of a Country name (as reported in the Regions endpoint). Only products available in this country will be listed |
V4
This endpoint is available for ordering systems that wish to access the list of products available to them. It behaves in a similar way to the V3 endpoint, but includes pagination, query parameters and additional fields such as brand_id
and max_value
(please note that all price values are shown in GBP).
Request
GET /api/v4/catalogues/{id}/products HTTP/1.1
Authorization: Token token=xxx
Response
HTTP/1.1 200 OK
Content-Type: application/json
[
{
"id": 357,
"name": "Product Name",
"base_price": 158.27,
"description": "Product Description",
"model_no": "A-123",
"sku": "A-123",
"available": true,
"availability_note": "",
"international_requirements": false,
"minimum_age": null,
"primary_image_id": 337,
"variant": "",
"voucher": false,
"lowest_denomination": null,
"face_value": null,
"supplier_currency_id": 31,
"available_countries": [
{
"id": 140,
"name": "UK",
"vat_rate": "20%",
"delivery_charge": 7.2
},
{
"id": 165,
"name": "Albania",
"vat_rate": "20%",
"delivery_charge": 34.75
},
...
],
"brand_id": 1,
"max_value": 200,
"rrp": "159.99",
"supplier": {
"id": 14
},
"vat_rate": {
"name": "20%",
"numeric": 20
},
"status": {
"name": "Approved"
},
"catalogue": {
"id": 8,
"name": "Demo Catalogue",
"exclusive": false
},
"categories": [
{
"id": 62,
"name": "Necklaces",
"parent_id": 59
}
],
"variants": [
{
"id": 63489,
"variant": "Small",
"sku": "B-123",
"translations": [
{
"locale": "fr",
"variant": "Petit"
}
],
"available": true,
"product_sku": "A-123",
"face_value": null,
"product_id": null,
"voucher_status": false,
"variant_base_price": 354.6728,
"face_value_gbp": null
},
{
"id": 63490,
"variant": "Large",
"sku": "B-234",
"translations": [
{
"locale": "fr",
"variant": "Grande"
}
],
"available": true,
"product_sku": "A-123",
"face_value": null,
"product_id": null,
"voucher_status": false,
"variant_base_price": null,
"face_value_gbp": null
}
],
"media": [
{
"id": 337,
"url": "https://images.com/123533.jpg"
}
],
"delivery_type": {
"id": 1,
"name": "Physical",
"requires_address": true
},
"currency": {
"title": "Pounds Sterling",
"abbreviation": "GBP",
"sign": "£"
},
"translations": [
{
"locale": "fr",
"name": "product_name_french",
"description": "product description_french"
},
{
"locale": "de",
"name": "product_name_german",
"description": "product description_german"
}
]
},
...
]
HTTP Request
GET /api/v4/catalogues/{id}/products
Parameters
Parameter | Type | Info |
---|---|---|
id | Array | Optional - A list of product ids. This will return products which have ids that match an integer supplied in this list. |
status | String | Optional - Only products with this status will be returned. For example 'Pending' or 'Approved'. |
sku | String | Optional - Specific product SKU. |
country_id | Array | Optional - A list of country ids. This will return products which have associated countries with an id that matches an integer supplied in this list. |
availability | String | Optional - Indicates whether a product is available, the value must be either 'True' or 'False'. |
brand_id | Integer | Optional - Only products linked to this brand_id will be returned. |
page | Integer | Optional - The requested page number. Defaults to page 1 if not supplied. Optional. |
Orders
List all orders
This endpoint fetches a JSON array of orders you are allowed to see. Typically, ordering systems will want to periodically synchronise orders so as to show up-to-date information to users about their Orders. By default this endpoint will fetch all orders from the first order ever placed by the client. This can grow to a long list over time and so becomes slow and taxing to fetch and process. We have provided some parameters for filtering this list of orders so clients can more easily stay up to date. We recommend using the since
parameter - this will return a list of orders that have been updated on or after the date and time provided as this value. Typically orders are updated daily but no more frequently than hourly.
Request
GET /api/v2/orders HTTP/1.1
Authorization: Token token=xxx
Response
HTTP/1.1 200 OK
Content-Type: application/json
[
{
"id": 1142,
"supplier_id": 50,
"number": "9001056",
"product_id": 5202,
"ordered_at": "2016-12-09T16:53:26.000Z",
"programme_id": 1,
"customer_name": "Ted Test",
"customer_phone": "7189404020",
"customer_email": "ted.moyses@corporaterewards.co.uk",
"recipient_address": "8 The Courtyard \nTimothy's Bridge Road \nStratford Upon Avon \nUK \nCV37 9NP",
"delivery_instructions": null,
"voucher_card_number": null,
"tracking_id": null,
"tracking_url": null,
"dispatch_date": null,
"created_at": "2016-12-09T16:53:26.000Z",
"updated_at": "2016-12-09T16:53:26.000Z",
"recipient_name": "Ted Test",
"recipient_phone": "7189404020",
"recipient_email": "ted.moyses@corporaterewards.co.uk",
"state": "pending",
"variant_id": 1000,
"country_id": 140,
"pingback_url": null,
"po_number": null,
"product_name": "Amazon.co.uk eVoucher",
"product_sku": "A-123",
"product_variation": "Variant: 10",
"delivery_type": "Email",
"international_requirements": false,
"price": "9.7",
"delivery_cost": 0,
"points": 1217,
"product_base_price": null,
"product_vat_rate": "8.0",
"api_key_id": null,
"remote_user_id": null,
"voucher": true,
"delivery_charge": 0,
"delivery_vat_numeric": 0,
"delivery_vat_name": "0.0%",
"old_order_type": false,
"customer_address_1": "8 The Courtyard",
"customer_address_2": "Timothy's Bridge Road",
"town": "Stratford Upon Avon",
"postcode": "CV37 9NP",
"country_name": "UK",
"remote_order": "",
"currency_id": 3,
"transactions": [
{
"id": 1234,
"order_id": 1142,
"user_id": null,
"variety": "Redemption",
"points": 1217,
"reason": "Initial points value of customer order",
"transaction_type": "Debit"
}
],
"line_items": [
{
"id": 1121,
"order_id": 1142,
"name": "Amazon.co.uk eVoucher",
"info": "Variant: 10",
"sku": "A-123",
"product_id": 5202,
"product_variant_id": 1000,
"delivery_type": "Email",
"price": 9.7,
"quantity": 1,
"points": null,
"individual_price": 9.7
}
],
"comments": [
{
"id": 375,
"user_id": 5,
"order_id": 1142,
"content": "Order Created",
"created_at": "2016-12-09T16:53:26.000Z",
"updated_at": "2016-12-09T16:53:26.000Z"
}
],
"programme": {
"id": 123,
"created_by_client": null,
"name": "Client Programme",
"reference": "1234",
"created_at": "2017-09-27T08:29:27.000Z",
"updated_at": "2017-09-27T08:29:27.000Z"
}
}
]
HTTP Request
GET /api/v2/orders
Parameters
Parameter | Type | Info |
---|---|---|
status | String | Optional - only orders with this status will be returned. Must be one of: pending, processing, dispatched, cancelled, unable to fulfill, cancel requested, pending return |
programme_ref | String | Optional - used to fetch orders for a given programme. Most ordering system API keys are only allocated/linked to one programme, ordering systems can only access orders for their own programme. This parameter has no effect unless your API key is linked to more than one programme. You should be issued your programme reference along with your API key |
since | Datetime | Sending this parameter with a parsable datetime as the value will only return orders that have been updated since this datetime value. This is useful to poll for orders with new information. Without this parameter present, all orders since the start of your programme (that also match any other provided parameters) will be returned. Example 2017-11-21T23:56:34Z |
Creating orders
This endpoint allows ordering systems to place orders on GPS. In order to place an order you will need:
The id of a product and the SKU shall be provided in the line_item. If the product has variants, line_item will require the SKU of the variant. For vouchers, more than one line_item can be provided.
A country name - as listed in the /regions endpoint
Recipient email address - required for a product where the product
delivery_type
=email
and is the email address where the order will be sent.Recipient delivery address - required for a product where the product
delivery_type
=physical
and is the delivery address where the order will be sent.
If the product is at status Approved and is available (product data can change since an ordering system last refreshed it's product data) at the time of order and the above information is provided correctly - GPS will respond with an HTTP status code of 200. Otherwise a status code of >= 400 will be returned as per REST expectations along with an explanatory plain text message as body content. Ordering systems are expected to track and respond to the response status codes.
The line_items object is a hash of array items and as such will require unique keys for each item. The value of these keys is not used.
Request
POST /api/v2/orders HTTP/1.1
Authorization: Token token=xxx
Content-Type: application/json
{
"order": {
"programme_ref": "1309",
"product_id": "3257",
"points": "100",
"customer_name": "Test Order User",
"customer_email": "email@address.com",
"customer_phone": "447502375063",
"customer_address_1": "22 A street",
"customer_address_2": "",
"country": "UK",
"town": "renfrew",
"postcode": "pa4 8qy",
"recipient_address": "22 A street \n\nrenfrew \npa4 8qy",
"recipient_name": "Mohammed Ashraf",
"recipient_email": "",
"recipient_phone": "447502375063",
"delivery_instructions": ""
},
"line_items": {
"0": {
"line_item": {
"name": "Sony Playstation 4 Console",
"sku": "L-123",
"quantity": "1",
"points": "27720"
}
}
}
}
Response
HTTP/1.1 200 OK
Content-Type: application/json
{
"id": 1246,
"supplier_id": 3,
"number": 9001154,
"product_id": 3257,
"ordered_at": "2017-01-30T17:23:25.945Z",
"programme_id": 34,
"customer_name": "Test Order User",
"customer_phone": "447502375063",
"customer_email": "email@address.com",
"recipient_address": "22 A street \n \nrenfrew \nUK \npa4 8qy",
"delivery_instructions": "",
"voucher_card_number": null,
"tracking_id": null,
"tracking_url": null,
"dispatch_date": null,
"created_at": "2017-01-30T17:23:26.103Z",
"updated_at": "2017-01-30T17:23:26.103Z",
"recipient_name": "Mohammed Ashraf",
"recipient_phone": "447502375063",
"recipient_email": "",
"state": "pending",
"variant_id": null,
"country_id": 140,
"pingback_url": null,
"po_number": null,
"product_name": "Sony Playstation 4 Console",
"product_sku": "L-123",
"product_variation": null,
"delivery_type": "Physical",
"international_requirements": false,
"price": "290.04",
"delivery_cost": 7,
"points": null,
"product_base_price": "290.04",
"product_vat_rate": "20.0",
"api_key_id": 12,
"remote_user_id": null,
"voucher": false,
"delivery_charge": 6.5,
"delivery_vat_numeric": 20,
"delivery_vat_name": "20.0%",
"old_order_type": false,
"customer_address_1": "22 A street",
"customer_address_2": "",
"town": "renfrew",
"postcode": "pa4 8qy",
"country_name": "UK",
"remote_order": null,
"currency_id": 3,
"transactions": [
{
"id": null,
"order_id": 1246,
"user_id": null,
"variety": "Redemption",
"points": null,
"reason": "Initial points value of customer order",
"transaction_type": "Debit"
}
],
"line_items": [
{
"id": 1232,
"order_id": 1246,
"name": "Sony Playstation 4 Console",
"info": null,
"sku": "L-123",
"product_id": null,
"product_variant_id": null,
"delivery_type": "Physical",
"price": 290.04,
"quantity": 1,
"points": 27720,
"individual_price": 290.04
}
],
"comments": [],
"api_key_catalogue_markup": null
}
HTTP Request
POST /api/v2/orders
Attributes
Attribute | Type | Info |
---|---|---|
order[programme_ref] | String | Optional - Please provide the programme reference issued to you by Corporate Rewards - if you do not know this value, it will be inserted automatically |
order[product_id] | Integer | Required - this is the product.id you get from the product in the catalogues endpoint |
order[points] | Integer | Optional - the total amount of points the user was charged by the ordering system for this product including delivery. GPS does not care about points per se but this can be useful when Rewards services are talking about an order as part of a customer service query. This should reflect the total points for all line items in an order. Using this value will reflect a transaction in the transactions key in the returned order data. |
order[customer_name] | String | Required - This is the name of the customer who placed the order |
order[customer_email] | String | Optional - This is the email address of the customer who placed the order |
order[customer_phone] | String | Required - this is the phone number of the customer who placed the order |
order[customer_address_1] | String | Required - this is the first line of the address, required if this order is for a product with a delivery_type with requires_address = true (1) i.e. physically delivered products |
order[customer_address_2] | String | Optional - second line of address |
order[country] | String | Required - this is the name of the country this product will be delivered to. Countries are available from the /regions endpoint or from the list of available_countries for this product. Always use the name of the country (not the id). Required if this order is for a product with a delivery_type with requires_address = true (1) i.e. physically delivered products |
order[town] | String | Required - this is the postal town this product will be delivered to. Required if this order is for a product with a delivery_type with requires_address = true (1) i.e. physically delivered products |
order[postcode] | String | Postal (or zip) code this product is to be delivered to. Required if this order is for a product with a delivery_type with requires_address = true (1) i.e. physically delivered products |
order[recipient_address] | String | Required - this is the concatenated version of the full postal address this product will be delivered to. Required if this order is for a product with a delivery_type with requires_address = true (1) i.e. physically delivered products. If the delivery address has a Company Name, please include this at the start of the recipient address |
order[recipient_name] | String | Optional - This allows a user to place an order and have it delivered to another person i.e. as a gift. |
order[recipient_email] | String | Required for a product where the product delivery_type = email - This allows a user to specify an alternate email address to be the recipient of this order and is used to receive products with a delivery_type = email |
order[recipient_phone] | String | Optional - string representation of an alternate phone number to be provided as the recipient of this product |
order[delivery_instructions] | String | Optional - allows for the provision of extra instructions for the delivery of this order such as "Please knock, the door bell is not working" |
order[remote_order] | String | Optional - this can be used to record the ordering systems own unique id for this order. Some systems will create an order locally before attempting to push the order over the API to GPS. This field can be used to store this id value for later cross referencing. |
order[pingback_url] | String | Optional - if provided, must be a valid URL (with scheme i.e. http:// or https://) that identifies this order locally on the ordering system. If an order is updated by GPS, we will make a simple get request to this url. This is a signal that an update has occured and the ordering system should fetch the order by id (GPS order.id). The URL provided should not require any kind of authentication and as such should also not 'leak' any information. |
line_items[0][line_item][name] | String | Required - this is the name of the product being ordered |
line_items[0][line_item][sku] | String | Required - this is the SKU of the product being order. If ordering a variant of a product, ALWAYS provide the variant SKU |
line_items[0][line_item][quantity] | Integer | Required - the number of this product to deliver |
line_items[0][line_item][points] | Integer | Optional - the value of points charged for this line item. This is used to indicate to GPS how many points each line item is work but is not related to the total points for the order. This has no effect in GPS other than to indicate points for a line item at time of order. |
Error messages and response codes
StatusCode | Likely cause |
---|---|
404 | This product either does not exist or is no longer available |
403 | API key supplied does not have permission to use this endpoint |
422 | The order information supplied is invalid - there will be an accompanying message in the body of the response to explain more about why the request is un acceptable |
500 | Something unexpected has gone wrong on the server side - there may be a detailed error message from the staging environment, please copy and paste any such error to either the Product & Proposition or Technical Team at CR to assist with diagnosing this error |
Possible reasons for a 422:
{{ProductName}}
can't be delivered to this country{{ProductName}}
isn't available to order{{order[pingback_url]}}
isn't a valid URL{{order[product_id]}}
is not supplied by Supplier:{{SupplierName}}
- can't be blank or is an unknown supplier.
- can't be blank or is an unrecognised country.
- can't be blank or is an unrecognised product.
- can't be blank or is an unrecognised programme.
- One or more line items are invalid. It is likely that the corresponding voucher, variant or product may have been deleted in GPS - {{additional line items errors may appear here, if known}}
- One or more line items are invalid - {{more line item related messages may be displayed here, if known}}
- No Line Items found
{{line_items[0][line_item][name]}}
SKU does not match order product SKU
Order actions
Once you have a list of relevant orders to work on, you can perform a limited number of actions on these orders to progress these orders along the order management lifecycle. The order status transitions are governed by a state machine – this state machine will only allow orders to transition between states that valid starting and ending states for a given action. For instance a 'pending' order may transition to 'processing' but not to 'dispatched'.
Any attempt to update an order using an invalid state transition will be met with a 422 (unprocessable entity) and a textual description of the error.
In principle the vast majority of actions a supplier will be performing are:
accept
This action requires the ID of an order with a current status of 'pending', and results in the order having a new status of 'processing'
Request
POST /api/v2/orders/{id}/accept HTTP/1.1
Authorization: Token token=xxx
Response
HTTP/1.1 200 OK
Content-Type: application/json
reject
This action requires the ID of an order with a current status of 'pending', and results in the order having the status 'unable to fulfill'. A reason is required for any order being rejected.
Request
POST /api/v2/orders/{id}/reject HTTP/1.1
Authorization: Token token=xxx
Content-Type: application/json
{
"order": {
"reason": "Reason for supplier rejecting this order"
}
}
Response
HTTP/1.1 200 OK
Content-Type: application/json
Attribute | Type | Info |
---|---|---|
order[reason] | String | Required - text description of why the order cannot be fulfilled and is being rejected. Care should be taken when providing a reason as this will be seen by the end user/customer as well as our reward services team. |
dispatch
This action requires the ID of an order with a current status of 'processing', and results in this order having the status 'dispatched'. In order to dispatch an order you will have to provide a date at which the order was dispatched and optionally either a tracking URL or tracking ID or (preferably) both if required to trace the delivery using a courier.
Request
POST /api/v2/orders/{id}/dispatch HTTP/1.1
Authorization: Token token=xxx
Content-Type: application/json
{
"order": {
"dispatch_date": "2018-01-09 12:34:56",
"tracking_id": "",
"tracking_url": "https://tracking.com/123456"
}
}
Response
HTTP/1.1 200 OK
Content-Type: application/json
Attribute | Type | Info |
---|---|---|
order[dispatch_date] | DateTime (string) | Required - string parsable as datetime (i.e. 2017-01-01 13:45:56) this should be the date and time the order was despatched at - there are currently no restrictions on whether this date is in the past or present, however logically it should not be before the order was accepted for processing |
order[tracking_id] | String | Optional - this value should represent an identifier or token for tracking the delivery with the relevant courier or handler |
order[tracking_url] | String | Optional - if provided, must be a valid URL (i.e. https://courier.com/track?parcelID=232456 ) and should allow the user to click and be shown the progress of their delivery. |
Currencies
List all currencies
An endpoint to retrieve all currencies and their current exchange rate. Your API key must have permission to read currencies.
Request
GET /api/v2/currencies HTTP/1.1
Authorization: Token token=xxx
Response
HTTP/1.1 200 OK
Content-Type: application/json
{
"id": 1,
"title": "Great British Pound",
"abbreviation": "GBP",
"sign": "£",
"name": "Great British Pound (£)",
"created_at": "01/01/2000 00:00:00",
"updated_at": "01/02/2000 00:00:00",
"exchange_rate": 1.1111
}
HTTP Request
GET /api/v2/currencies
Update exchange rates
An endpoint to update the exchange rate of a specified currency. Your API key must have permission to write currencies.
Request
PATCH /api/v2/currencies/{id} HTTP/1.1
Authorization: Token token=xxx
Content-Type: application/json
{
"exchange_rate": 1.1111
}
Response
HTTP/1.1 200 OK
Content-Type: application/json
{
"id": 1,
"name": "Great British Pound (£)",
"exchange_rate": 1.1111
}
HTTP Request
PATCH /api/v2/currencies/{id}
URL Parameters
Attribute | Type | Info |
---|---|---|
id | integer | The id of the currency |
Body Parameters
Attribute | Type | Info |
---|---|---|
exchange_rate | decimal | The currencies current exchange rate (to 4 decimal places) |
Products
Access to products endpoint will be scoped to your supplier in GPS.
This section is should be considered pre-production and subject to significant change
List all products
This endpoint shows all products associated with this API key as a list
Request
GET /api/v2/products HTTP/1.1
Authorization: Token token=xxx
Response
HTTP/1.1 200 OK
Content-Type: application/json
[
{
"id": 22413,
"base_price": 100.0,
"model_no": "bub001",
"sku": "000123454",
"available": true,
"availability_note": null,
"international_requirements": false,
"minimum_age": 0,
"primary_image_id": 6419,
"variant": null,
"voucher": false,
"lowest_denomination": null,
"face_value":null,
"supplier_currency_id": 1,
"brand_id": null,
"name": "Bat Utility Belt",
"description": "<p>Quite simply the quintessential superhero utility belt. Iconnic and functional - no bat-based superhero should be without it </p>",
"available_countries": [
{
"id": 1,
"name": "USA",
"vat_rate": "0%",
"delivery_charge": 0.0
}
],
"rrp": "100",
"supplier": {
"id": 66
},
"vat_rate": {
"name": "0%",
"numeric": 0.0
},
"status": {
"name": "Approved"
},
"catalogue": {
"id": 1,
"name": "Superhero Equipment",
"exclusive": false
},
"categories": [
{
"id": 407,
"parent_id": 75,
"name": "Outerwear"
}
],
"variants": [
{
"id": 30111,
"sku": "000123457",
"available": true,
"product_sku": "000123454",
"face_value": null,
"product_id": null,
"voucher_status": false,
"variant": "small",
"variant_base_price": 100,
"face_value_gbp": null
},
{
"id": 30112,
"sku": "000123459",
"available": true,
"product_sku": "000123454",
"face_value": null,
"product_id": null,
"voucher_status": false,
"variant": "medium",
"variant_base_price": 100,
"face_value_gbp": null
},
{
"id": 30113,
"sku": "000123461",
"available": true,
"product_sku": "000123454",
"face_value": null,
"product_id": null,
"voucher_status": false,
"variant": "large",
"variant_base_price": 100,
"face_value_gbp": null
},
{
"id": 30114,
"sku": "000123463",
"available": true,
"product_sku": "000123454",
"face_value": null,
"product_id": null,
"voucher_status": false,
"variant": "Afleck",
"variant_base_price": 100,
"face_value_gbp": null
}
],
"media": [
{
"id": 6419,
"url": "https://images.com/123533.jpg"
}
],
"delivery_type": {
"id": 1,
"name": "Physical",
"requires_address": true,
"requires_email": true
},
"currency": {
"title": "Dollars",
"abbreviation": "USD",
"sign": "$"
}
},
{
...
}
]
Create product
You can create products over the API as shown - all new products require approval. Products can only be approved using the GPS web interface by a supplier manager or CR staff. Products can only be approved once they have a Category, a Catalogue and at least one image applied. Once a product is approved, it can be shown in a catalogue and ordered, subject to availability.
The created product has a status of pending, and unless provided in the POST request, will have no catalogue or categories - this product needs to be approved in GPS before it will show in a catalogue
V2
Request
POST /api/v2/products HTTP/1.1
Authorization: Token token=xxx
Content-Type: application/json
{
"product": {
"name": "Bat Utility Belt",
"model_no": "bub001",
"brand_id": 1,
"description": "<p>Quite simply the quintessential superhero utility belt. Iconic and functional - no bat-based superhero should be without it </p>",
"sku": "000123454",
"base_price": 100.0,
"rrp": 100.0,
"face_value": null,
"media": "https://images.com/12353.jpg",
"currency": "USD",
"availability_note": "",
"available": "yes",
"countries": [{
"country": "USA",
"vat_rate": 0,
"delivery_charge": 0
}],
"international_requirements": 0,
"minimum_age": 0,
"vat_rate_id": 1,
"delivery_type_id": 1,
"voucher": false,
"lowest_denomination": null,
"catalogue_id": 8,
"categories": [3,4,12]
"variants": [
"{\"available\": 1, \"product_sku\": \"000123454\", \"sku\": \"000123457\", \"face_value\": null, \"base_price\": 100.0, \"voucher_status\": 0, \"variant\":\"small\" }",
"{\"available\": 1, \"product_sku\": \"000123454\", \"sku\": \"000123459\", \"face_value\": null, \"base_price\": 100.0, \"voucher_status\": 0, \"variant\":\"medium\" }",
"{\"available\": 1, \"product_sku\": \"000123454\", \"sku\": \"000123461\", \"face_value\": null, \"base_price\": 100.0, \"voucher_status\": 0, \"variant\":\"large\" }",
"{\"available\": 1, \"product_sku\": \"000123454\", \"sku\": \"000123463\", \"face_value\": null, \"base_price\": 100.0, \"voucher_status\": 0, \"variant\":\"Afleck\" }"
]
}
}
Response
HTTP/1.1 200 OK
Content-Type: application/json
{
"id": 22413,
"base_price": 100.0,
"model_no": "bub001",
"sku": "000123454",
"available": true,
"availability_note": null,
"international_requirements": false,
"minimum_age": 0,
"primary_image_id": 6419,
"variant": null,
"voucher": false,
"lowest_denomination": null,
"face_value":null,
"supplier_currency_id": 1,
"brand_id": 1,
"name": "Bat Utility Belt",
"description": "<p>Quite simply the quintessential superhero utility belt. Iconic and functional - no bat-based superhero should be without it </p>",
"available_countries": [
{
"id": 1,
"name": "USA",
"vat_rate": "0%",
"delivery_charge": 0.0
}
],
"rrp": "100",
"supplier": {
"id": 66
},
"vat_rate": {
"name": "0%",
"numeric": 0.0
},
"status": {
"name": "Pending"
},
"catalogue": {
"id": 8,
"name": "Demo Catalogue",
"exclusive": false
},
"categories": [
{
"id": 3,
"parent_id": 1,
"name": "Experiences & Days Out"
},
{
"id": 4,
"parent_id": 1,
"name": "Food and Drink"
},
{
"id": 12,
"parent_id": 11,
"name": "Home Entertainment"
}
],
"variants": [
{
"id": 30111,
"sku": "000123457",
"available": true,
"product_sku": "000123454",
"face_value": null,
"product_id": null,
"voucher_status": false,
"variant": "small",
"variant_base_price": 100,
"face_value_gbp": null
},
{
"id": 30112,
"sku": "000123459",
"available": true,
"product_sku": "000123454",
"face_value": null,
"product_id": null,
"voucher_status": false,
"variant": "medium",
"variant_base_price": 100,
"face_value_gbp": null
},
{
"id": 30113,
"sku": "000123461",
"available": true,
"product_sku": "000123454",
"face_value": null,
"product_id": null,
"voucher_status": false,
"variant": "large",
"variant_base_price": 100,
"face_value_gbp": null
},
{
"id": 30114,
"sku": "000123463",
"available": true,
"product_sku": "000123454",
"face_value": null,
"product_id": null,
"voucher_status": false,
"variant": "Afleck",
"variant_base_price": 100,
"face_value_gbp": null
}
],
"media": [
{
"id": 6419,
"url": "https://images.com/123533.jpg"
}
],
"delivery_type": {
"id": 1,
"name": "Physical",
"requires_address": true,
"requires_email": true
},
"currency": {
"title": "Dollars",
"abbreviation": "USD",
"sign": "$"
}
}
HTTP Request
POST /api/v2/products
Attributes
Attribute | Type | Info |
---|---|---|
name | String | Required - name of the product as it displayed in the catalogue |
model_no | String | Optional - short descriptive code or model name |
description | HTML (String) | Required - a textual, detailed description of the product can be plain text or marked up in HTML |
sku | String | Required - canonical unique reference or identity of a product used for ordering |
base_price | Float | Required - this is the base_price excluding tax and delivery - the cost of the product |
rrp | Float | Optional - recommended retail price of product |
face_value | Integer | Optional conditional - if this product is to be classed as a voucher, this is face value of the lowest denomination |
media | Url (String) | Optional - a publicly accessible URL for an image (JPG or PNG). This will be fetched by our system, transcoded and associated with this product as the primary image. This image will also be placed in the media library for your supplier in GPS |
currency | String | Required - ISO 3 letter currency code for the currency this product will be billed in - this currency must be associated with your supplier record |
availability_note | String | Optional - this text will be displayed in GPS only to inform our team why the product is not available such as "Coming soon" or "Temporarily out of stock" |
available | Boolean | Required - this indicates the product is or isn't available and triggers the availability_note |
countries | Array | Required - a list of at least one country this product is available to order in |
countries.country | String | Required - 2 letter ISO country code - this country must be associated with your supplier |
countries.vat_rate | Float | the rate of sales tax that will be used to bill for the delivery of this product |
countries.delivery_charge | Float | The charge to be billed for shipping this product excluding taxes |
international_requirements | Boolean | Required - indicates if this product has international requirements or variations such as alternative plugs or instructions. Not shown to end users, more intended for order fulfilment |
minimum_age | Integer | Required - indicates if a minimum age is legally required for this product such as alcohol |
vat_rate_id | Integer | Required - this indicates a sales tax rate. Note this is not a value but a reference to a sales tax rate stored in GPS |
delivery_type_id | Integer | Required - delivery types in GPS are (but not limited to) Physical = 1, Downloadable = 2, Email = 3, Prepaid = 4. These types are used to enforce validation strategies on orders for these products i.e. for physical orders, you must provide a postal address |
voucher | Boolean | Required - indicates if this product is to be treated as a voucher |
lowest_denomination | Integer | Optional conditional - if this product is considered a voucher this field should indicate the lowest denomination of voucher available |
catalogue_id | Integer | Optional - The id of the catalogue the product should belong to |
categories | Array | Optional - An array of category ids that the product should belong to |
variants | Array | Required - this is (somewhat convolutedly) a list of at 0 or more JSON encoded strings representing objects for a variant |
variants.available | Boolean | Required - indicates the availability of this particular variant |
variants.product_sku | String | Required - this is a 'key' that links this variant to its parent product, the value should be the SKU of the main product we are posting |
variants.sku | String | Required - this is the SKU of this particular variant and should be unique |
variants.face_value | Integer | Required conditional - if this product is a voucher, this shows the face value of this denomination |
variants.base_price | Float | Required conditional - for non-voucher products all variants will have the same cost/base price but voucher denominations will have differing base prices |
variants.voucher_status | Boolean | Required - indicated this variant is a voucher - you cannot mix vouchers and physical product variants this should be all or nothing and match the parent product |
variants.variant | String | Required - for non voucher products this represents the reason for the variation such as size (medium large etc) or colour. For vouchers this represents the face value of this denomination |
brand_id | Integer | Optional - this indicates a brand. Note this is not the name of the brand, but the id of the brand as stored in GPS |
V3
Request (non-voucher example)
POST /api/v3/products HTTP/1.1
Authorization: Token token=xxx
Content-Type: application/json
{
"name": "Product Name",
"base_price": 158.27,
"description": "Product Description",
"model_no": "A-123",
"sku": "A-123",
"available": true,
"voucher": false,
"countries": [
{
"country": "GB",
"vat_rate": 20.0,
"delivery_charge": 7.2
},
{
"country": "AL",
"vat_rate": 17.5,
"delivery_charge": 34.75
}
],
"rrp": "159.99",
"vat_rate": 20,
"brand_id": 1,
"catalogue_id": 8,
"categories": [62],
"variant_type_id": 2,
"variants": [
{
"variant": "small",
"sku": "B-123",
"available": true
},
{
"variant": "large",
"sku": "B-234",
"available": true
}
],
"media": ["https://example.test/image.jpg"],
"delivery_type_id": 1,
"currency": "GBP"
}
Response (non-voucher example)
HTTP/1.1 201 Created
Content-Type: application/json
{
"id": 357,
"name": "Product Name",
"base_price": 158.27,
"description": "Product Description",
"model_no": "A-123",
"sku": "A-123",
"available": true,
"availability_note": "",
"international_requirements": false,
"minimum_age": null,
"primary_image_id": 337,
"variant": "",
"voucher": false,
"lowest_denomination": null,
"face_value": null,
"supplier_currency_id": 31,
"max_value_per_order": null,
"available_countries": [
{
"id": 140,
"name": "UK",
"vat_rate": "20%",
"delivery_charge": 7.2
},
{
"id": 165,
"name": "Albania",
"vat_rate": "17.5%",
"delivery_charge": 34.75
}
],
"rrp": "159.99",
"supplier": {
"id": 14
},
"brand": {
"id": 1,
"name": "Acme"
},
"variant_type": {
"id": 2,
"name": "Size"
},
"vat_rate": {
"name": "20%",
"numeric": 20
},
"status": {
"name": "Pending"
},
"catalogue": {
"id": 8,
"name": "Demo Catalogue",
"exclusive": false
},
"categories": [
{
"id": 62,
"name": "Necklaces",
"parent_id": 59
}
],
"variants": [
{
"id": 529,
"variant": "small",
"sku": "B-123",
"available": true,
"product_sku": "A-123",
"face_value": null,
"product_id": null,
"voucher_status": false,
"variant_base_price": null,
"face_value_gbp": null
},
{
"id": 530,
"variant": "large",
"sku": "B-234",
"available": true,
"product_sku": "A-123",
"face_value": null,
"product_id": null,
"voucher_status": false,
"variant_base_price": null,
"face_value_gbp": null
}
],
"media": [
{
"id": 337,
"url": "https://example.test/image.jpg"
}
],
"delivery_type": {
"id": 1,
"name": "Physical",
"requires_address": true
},
"currency": {
"title": "Pounds Sterling",
"abbreviation": "GBP",
"sign": "£"
},
"translations": []
}
Request (voucher example)
POST /api/v3/products HTTP/1.1
Authorization: Token token=xxx
Content-Type: application/json
{
"name": "Product Name",
"base_price": 9.95,
"description": "Product Description",
"sku": "A-123|10",
"available": true,
"voucher": true,
"face_value": 10,
"lowest_denomination": "$10",
"countries": [
{
"country": "GB",
"vat_rate": 0,
"delivery_charge": 0
},
{
"country": "AL",
"vat_rate": 0,
"delivery_charge": 0
}
],
"rrp": "$10",
"vat_rate": 0,
"catalogue_id": 2,
"categories": [542],
"variants": [
{
"variant": "$10",
"face_value": 10,
"base_price": 9.95,
"sku": "A-123|10",
"available": true
},
{
"variant": "$20",
"face_value": 20,
"base_price": 19.95,
"sku": "A-123|20",
"available": true
}
],
"media": ["https://example.test/image.jpg"],
"delivery_type_id": 3,
"currency": "USD"
}
Response (voucher example)
HTTP/1.1 201 Created
Content-Type: application/json
{
"id": 357,
"name": "Product Name",
"base_price": 158.27,
"description": "Product Description",
"model_no": null,
"sku": "A-123",
"available": true,
"availability_note": "",
"international_requirements": false,
"minimum_age": null,
"primary_image_id": 337,
"variant": "",
"voucher": true,
"lowest_denomination": "$10",
"face_value": 10,
"supplier_currency_id": 41,
"max_value_per_order": null,
"available_countries": [
{
"id": 140,
"name": "UK",
"vat_rate": "0%",
"delivery_charge": 0
},
{
"id": 165,
"name": "Albania",
"vat_rate": "0%",
"delivery_charge": 0
}
],
"rrp": "159.99",
"supplier": {
"id": 14
},
"vat_rate": {
"name": "0%",
"numeric": 0
},
"status": {
"name": "Pending"
},
"catalogue": {
"id": 2,
"name": "Vouchers",
"exclusive": false
},
"categories": [
{
"id": 542,
"name": "Food & Dining",
"parent_id": 75
}
],
"variants": [
{
"id": 529,
"variant": "$10",
"sku": "A-123|10",
"available": true,
"product_sku": "A-123|10",
"face_value": 10,
"product_id": null,
"voucher_status": true,
"variant_base_price": 9.95,
"face_value_gbp": null
},
{
"id": 530,
"variant": "$20",
"sku": "A-123|20",
"available": true,
"product_sku": "A-123|10",
"face_value": 20,
"product_id": null,
"voucher_status": true,
"variant_base_price": 19.95,
"face_value_gbp": null
}
],
"media": [
{
"id": 337,
"url": "https://example.test/image.jpg"
}
],
"delivery_type": {
"id": 3,
"name": "Email",
"requires_address": false
},
"currency": {
"title": "US Dollars",
"abbreviation": "USD",
"sign": "$"
},
"translations": []
}
HTTP Request
POST /api/v3/products
Attributes
Attribute | Type | Info |
---|---|---|
name | String | Required - name of the product as it is displayed in the catalogue |
description | String | Required - a textual, detailed description of the product - can be plain text or HTML |
sku | String | Required - canonical unique reference or identity of a product used for ordering |
base_price | Float | Required - this is the base_price excluding tax and delivery - the cost of the product |
rrp | String | Required - recommended retail price of product |
currency | String | Required - ISO 3-letter currency code for the currency this product will be billed in - this currency must be associated with your supplier |
available | Boolean | Required - this indicates if the product is or isn't available and triggers the availability_note if false |
vat_rate | Float | Required - this indicates a sales tax rate |
delivery_type_id | Integer | Required - delivery types in GPS are (but not limited to) Physical = 1, Downloadable = 2, Email = 3, Prepaid = 4. These types are used to enforce validation strategies on orders for these products - i.e. for physical orders, you must provide a postal address |
voucher | Boolean | Optional (default false) - indicates if this product is to be treated as a voucher |
model_no | String | Optional - short descriptive code or model name |
face_value | Integer | Required (conditional) - if this product is to be classed as a voucher, this is the face value of the lowest denomination |
media | Array of URLs (String) | Optional - publicly accessible URL(s) for image(s) (JPG or PNG). This will be fetched by our system, transcoded and associated with this product, with the first URL as the primary image. Images will also be placed in the media library for your supplier in GPS |
availability_note | String | Optional - this text will be displayed in GPS only to inform our team why the product is not available such as "Coming soon" or "Temporarily out of stock" |
countries | Array | Optional - a list of at least one country this product is available to order in |
countries.country | String | Required - 2-letter ISO country code - this country must be associated with your supplier |
countries.vat_rate | Float | Required - the rate of sales tax that will be used to bill for the delivery of this product |
countries.delivery_charge | Float | Required - the charge to be billed for shipping this product, excluding taxes |
international_requirements | Boolean | Optional (default false) - indicates if this product has international requirements or variations such as alternative plugs or instructions. Not shown to end users, more intended for order fulfilment |
minimum_age | Integer | Optional - indicates if a minimum age is legally required for this product (as with alcohol etc.) |
max_value_per_order | Float | Optional - the maximum total value (quantity * face_value for vouchers, quantity * base_price otherwise) of this product that can be purchased in a single order |
lowest_denomination | String | Required (conditional) - if this product is considered a voucher, this field should indicate the lowest denomination of voucher available |
brand_id | Integer | Optional - this indicates a brand. Note this is not the name of the brand, but the ID of the brand as stored in GPS |
catalogue_id | Integer | Optional - the ID of the catalogue the product should belong to |
categories | Array of Integers | Optional - an array of category IDs that the product should belong to |
variant_type_id | Integer | Optional - the ID of a variant type in GPS (Colour = 1, Size = 2, Other = 8). Ignored for vouchers (since their variants are always denominations) |
variants | Array | Optional - an array of variants or denominations for this product |
variants.variant | String | Required - for non-voucher products this represents the reason for the variation such as size (medium large etc) or colour. For vouchers this represents the face value of this denomination |
variants.sku | String | Required - this is the SKU of this particular variant and should be unique |
variants.face_value | Integer | Required (conditional) - if this product is a voucher, this shows the face value of this denomination |
variants.base_price | Float | Required (conditional) - for non-voucher products all variants will have the same cost/base price but voucher denominations will have differing base prices |
variants.available | Boolean | Optional (default true) - indicates the availability of this particular variant |
Update product
The update product API is available to update product information.
Request
PATCH /api/v2/products/{product_id} HTTP/1.1
Authorization: Token token=xxx
Content-Type: application/json
{
"product": {
"name": "Updated product",
"model_no": "735updated",
"description": "<p>A high quality updated product</p>",
"sku": "DEMO - updated",
"base_price": 30,
"rrp": 45,
"face_value": null,
"media": "https://images.com/12353.jpg",
"currency": "USD",
"availability_note": "available",
"available": "yes",
"countries": [{
"country": "US",
"vat_rate": 0,
"delivery_charge": 0
}
],
"international_requirements": 0,
"minimum_age": 21,
"vat_rate_id": 1,
"delivery_type_id": 1,
"voucher": false,
"lowest_denomination": null,
"catalogue_id": 1,
"brand_id": 1,
"variants": ["{\"available\": 1, \"product_sku\": \"000123454\", \"sku\": \"000123457\", \"face_value\": null, \"base_price\": 100.0, \"voucher_status\": 0, \"variant\":\"test\" }"]
}
}
Response
HTTP/1.1 200 OK
Content-Type: application/json
{
"id": 123,
"base_price": 30,
"model_no": "735updated",
"sku": "DEMO - updated",
"available": true,
"availability_note": "available",
"international_requirements": false,
"minimum_age": 21,
"primary_image_id": 6419,
"variant": null,
"voucher": false,
"lowest_denomination": null,
"face_value": null,
"supplier_currency_id": 123,
"max_value": null,
"brand_id": 1,
"name": "Updated product",
"description": "<p>A high quality updated product</p>",
"available_countries": [
{
"id": 120,
"name": "USA",
"vat_rate": "0%",
"delivery_charge": 0.0
}
],
"rrp": "45",
"supplier": {
"id": 1
},
"vat_rate": {
"name": "0%",
"numeric": 0.0
},
"status": {
"name": "Approved"
},
"catalogue": {
"id": 1,
"name": "Core merch",
"exclusive": false
},
"categories": [
{
"id": 47,
"parent_id": 4,
"name": "Test"
}
],
"variants": [
{
"id": 1655,
"sku": "000123457",
"available": true,
"product_sku": "DEMO - 73568updated",
"face_value": null,
"product_id": null,
"voucher_status": false,
"variant": "test",
"variant_base_price": 78.2962,
"face_value_gbp": null
}
],
"media": [
{
"id": 123,
"url": "https://images.com/123533.jpg"
}
],
"delivery_type": {
"id": 1,
"name": "Physical",
"requires_address": true,
"requires_email": false
},
"variant_type": {
"id": 10,
"name": "other"
},
"currency": {
"title": "US Dollar",
"abbreviation": "USD",
"sign": "$"
}
}
HTTP Request
PUT /api/v2/products/{product_id}
PATCH /api/v2/products/{product_id}
Request Parameters
Attribute | Type | Info |
---|---|---|
name | String | Optional - name of the product as it displayed in the catalogue |
model_no | String | Optional - short descriptive code or model name |
description | HTML (String) | Optional - a textual, detailed description of the product can be plain text or marked up in HTML |
sku | String | Optional - canonical unique reference or identity of a product used for ordering |
base_price | Float | Optional - this is the base_price excluding tax and delivery - the cost of the product |
rrp | Float | Optional - recommended retail price of product |
face_value | Integer | Optional conditional - if this product is to be classed as a voucher, this is face value of the lowest denomination |
media | URL (String) | Optional - a publicly accessible URL for an image (jpg or png). This will be fetched by our system, transcoded and associated with this product as the primary image. This image will also be placed in the media library for your supplier in GPS |
currency | String | Optional - ISO currency code for the currency this product will be billed in - this currency must be associated with your supplier record |
availability_note | String | Optional - this text will be displayed in GPS only to inform our team why the product is not available such as "Coming soon" or "Temporarily out of stock" |
available | Boolean | Optional - this indicates the product is or isn't available and triggers the availability_note |
countries | Array | Optional - a list of countries this product is available to order in. You can add countries but not remove them via the API. |
countries.country | String | Required for each country added - ISO country code - this country must be associated with your supplier |
countries.vat_rate | Float | Required for each country added - the rate of sales tax that will be used to bill for the delivery of this product |
countries.delivery_charge | Float | Required for each country added - The charge to be billed for shipping this product excluding taxes |
international_requirements | Boolean | Optional - indicates if this product has international requirements or variations such as alternative plugs or instructions. Not shown to end users, more intended for order fulfilment |
minimum_age | Integer | Optional - indicates if a minimum age is legally required for this product such as alcohol |
vat_rate_id | Integer | Optional - this indicates a sales tax rate. Note this is not a value but a reference to a sales tax rate stored in GPS |
delivery_type_id | Integer | Optional - delivery types in GPS are (but not limited to) Physical = 1, Downloadable = 2, Email = 3, Prepaid = 4. These types are used to enforce validation strategies on orders for these products i.e. for physical orders, you must provide a postal address |
voucher | Boolean | Optional - indicates if this product is to be treated as a voucher |
lowest_denomination | Integer | Optional conditional - if this product is considered a voucher this field should indicate the lowest denomination of voucher available |
catalogue_id | Integer | Optional - The id of the catalogue the product should belong to |
variants | Array | Optional - this is (somewhat convolutedly) a list of at 0 or more JSON encoded strings representing objects for a variant |
variants.available | Boolean | Required for each variant added - indicates the availability of this particular variant |
variants.product_sku | String | Required for each variant added - this is a 'key' that links this variant to its parent product, the value should be the SKU of the main product we are posting |
variants.sku | String | Required for each variant added - this is the SKU of this particular variant and should be unique |
variants.face_value | Integer | Required for each variant added - conditional - if this product is a voucher, this shows the face value of this denomination |
variants.base_price | Float | Required for each variant added - conditional - for non-voucher products all variants will have the same cost/base price but voucher denominations will have differing base prices |
variants.voucher_status | Boolean | Required for each variant added - indicated this variant is a voucher - you cannot mix vouchers and physical product variants this should be all or nothing and match the parent product |
variants.variant | String | Required for each variant added - for non voucher products this represents the reason for the variation such as size (medium large etc) or colour. For vouchers this represents the face value of this denomination |
brand_id | Integer | Optional - this indicates a brand. Note this is not the name of the brand, but the id of the brand as stored in GPS |
Delete Product
You can also delete products over the API as shown. Products can only be deleted by the supplier of the product.
Deleting a product will:
- Remove the product as well as any variations and translations
- Remove any associated media, providing it is not used by other products
- Preserve the order history
Request
DELETE /api/v2/products/{product_id} HTTP/1.1
Authorization: Token token=xxx
Response
HTTP/1.1 200 OK
Content-Type: application/json
HTTP Request
DELETE /api/v2/products/{product_id}
Product actions
Available on v3 of the API only
Approve product
Changes the status of a product to approved. A product must have at least one country, one catalogue, one category, and one image before it can be approved.
Request
POST /api/v3/products/{id}/approve HTTP/1.1
Authorization: Token token=xxx
Response
HTTP/1.1 200 OK
Content-Type: application/json
HTTP Request
POST /api/v3/products/{id}/approve
URL Parameters
Attribute | Type | Info |
---|---|---|
id | integer | The id of the product |
Put product on hold
Changes the status of a product to on hold
Request
POST /api/v3/products/{id}/onhold HTTP/1.1
Authorization: Token token=xxx
Response
HTTP/1.1 200 OK
Content-Type: application/json
HTTP Request
POST /api/v3/products/{id}/onhold
URL Parameters
Attribute | Type | Info |
---|---|---|
id | integer | The id of the product |
Archive product
Changes the status of a product to archived
Request
POST /api/v3/products/{id}/archive HTTP/1.1
Authorization: Token token=xxx
Response
HTTP/1.1 200 OK
Content-Type: application/json
HTTP Request
POST /api/v3/products/{id}/archive
URL Parameters
Attribute | Type | Info |
---|---|---|
id | integer | The id of the product |