If you are using Shopify or WooCommerce we can provide integrations for you. This API is for customers on other platforms who want to connect to our systems directly.
The API is REST and the following examples are in Python but should be very easy to translate to any other language.
When a call is successful the API returns status code 200 OK (if you are viewing something or changing something) or 201 CREATED (if you have just created something new).
If a call fails you may get 403 FORBIDDEN (which means your secret is wrong), 404 NOT FOUND (if you are trying to view something that doesn’t exist) or 400 BAD REQUEST (for all other expected errors).
A 500 status code means there has been an unexpected error and Move Fresh will have been notified to investigate.
Whenever there is an error you will be sent a JSON response with the error code and a message like this:
{
"error": 10,
"message": "Invalid or missing secret"
}
A full list of error codes appears at the end of this document.
Ping
Just to make sure everything is working you should start with a ping:
import requests
response = requests.get('https://app.movefresh.com/api/ping/',
headers={'Authorization': 'Bearer <<YOUR SECRET>>'}
)
if response.status_code == 200:
print(response.json())
elif response.status_code == 403:
print('Your secret is wrong.')
You should get the message “PONG” coming back.
Create Order
We recommend that orders are pushed to us quite frequently, either by a queue or perhaps every 10 minutes through a scheduled job.
Here’s some example code:
import requests
response = requests.post('https://app.movefresh.com/api/order/create/',
headers={'Authorization': 'Bearer <<YOUR SECRET>>'},
json={
'brand': 'Test Brand',
'order_number': '1001',
'courier': 'dhl_parcel',
'courier_service': '210',
'customer_type': 'consumer', # Optional
'delivery_name': 'Bob Test',
'delivery_oranisation': 'Move Fresh Ltd', # Optional
'delivery_address_1': '2 Rennie Square',
'delivery_address_2': 'Brucefield Ind Estate', # Optional
'delivery_town': 'Livingston',
'delivery_county': 'West Lothian', # Optional
'delivery_postcode': 'EH2 3BU',
'delivery_country': 'GB',
'delivery_email': 'bob@example.com', # Optional
'delivery_phone': '447123456789', # Optional
'delivery_instructions': 'Leave in porch if out', # Optional
'message': 'You now have 100 loyalty points!', # Optional
'priority': 'high', # Optional
'lines': [
{'sku': 'SK1010', 'quantity': 10},
{'sku': 'SK1082', 'quantity': 10}
]
}
)
if response.status_code == 201:
print('Order created successfully.')
elif response.status_code == 400:
print('Error:', response.json()['message'])
elif response.status_code == 500:
print('Unhandled error please contact Move Fresh.')
The fields are as follows:
- brand – the brand name registered with us
- order_number – is the Order Number on your store and must be unique
- courier – is ‘dpd’, ‘dhl_parcel’, ‘dhl_parcel_international’, ‘hermes’ or ‘royalmail’
- courier_service – see courier services
- customer_type – is ‘business’ for B2B, or ‘consumer’ for B2C which is the default [optional]
- delivery_name – person’s name (max 60 characters)
- delivery_organisation – company or organisation (max 60 characters) [optional]
- delivery_address_1 – first line of address (max 60 characters)
- delivery_address_2 – second line of address (max 60 characters) [optional]
- delivery_town – town or city (max 60 characters)
- delivery_county – county, province or state (max 60 characters) [optional]
- postcode – postal code or Zip code (max 10 characters)
- delivery_country – ISO-3166 country code (max 2 characters) but note that only countries we ship to are supported as shown below
- delivery_email – an email address for the courier (max 254 characters)[optional]
- delivery_phone – a phone number for the courier (include country code)
- delivery_instructions – a safe place parcels can be left (max 60 characters)[optional]
- message – a message for the customer to be printed on the delivery note (max 128 characters) [optional]
- priority – is ‘low’, ‘normal’ (default if not supplied), ‘high’ or ‘urgent’; it’s recommended that urgent is reserved for manual use to expedite specific orders [optional]
Note that multiple order lines for the same product will be consolidated. So 10 x SKU1 and 20 x SKU1 will be consolidated to 30 x SKU1.
If the courier service is not available it will be adjusted if possible. For example attempting to send to the Scottish Highlands on a next day service will usually be downgraded to a 48 hour service.
If successful, the status code 201 CREATED will be returned along with the origin. The origin is your order number with a brand prefix. The brand prefix for “Test Brand” would be “TB” so in this example the order number was 1001 so the origin would be “TB-1001”. We make sure that all of our clients have a different brand prefix to avoid confusion.
Linking to Order Page
You may want to link directly to orders from your CRM or other web application. This could be done for an order with the origin TB-1001 by linking to:
https://app.movefresh.com/customer/origin/TB-1001/
Cancel Order
If a customer changes their mind or fails a fraud check you may want to cancel the order before it is shipped. The following code would cancel an order with origin TB-1001.
import requests
response = requests.post('https://app.movefresh.com/api/order/TB-1001/cancel/',
headers={'Authorization': 'Bearer <<YOUR SECRET>>'}
)
if response.status_code == 200:
print('Order successfully cancelled.')
elif response.status_code == 404:
print('Order not found.')
elif response.status_code == 400:
print('Order cannot be cancelled')
print(response.json()['message'])
Orders can be cancelled even while being picked but can no longer be cancelled once the pick is complete.
Set Order Priority
After sending an order to Move Fresh it is possible to adjust the priority. This might happen in response to a customer service contact where it is necessary to ship the order as fast as possible.
The possible priorities are ‘low’, ‘normal’, ‘high’ or ‘urgent’. An attempt to set a priority outside of these will generate an error 50.
If an order status is In Process, Done or Cancelled, then it is not possible to update the priority and an error 80 will be returned.
import requests
response = requests.post('https://app.movefresh.com/api/order/TB-1001/priority/',
headers={'Authorization': 'Bearer <<YOUR SECRET>>'},
json={'priority': 'high'}
)
if response.status_code == 200:
print('Order priority updated.')
elif response.status_code == 400:
print(response.json()['message'])
elif response.status_code == 404:
print('Order not found.')
Get Order Status
You may want to check the order status at the end of each day to get the courier tracking details to email to your customers.
In this example we are checking on the order TB-1001 that we created in the first example:
import requests
response = requests.get('https://app.movefresh.com/api/order/TB-1001/',
headers={'Authorization': 'Bearer <<YOUR SECRET>>'}
)
if response.status_code == 200:
result = response.json()
print('Status:', result['status'])
print('Message:', result['message'])
if 'courier_reference' in result:
print('Tracking Ref:', result['courier_reference'])
if 'courier_link' in result:
print('Tracking Link:', result['courier_link'])
elif response.status_code == 404:
print('Order not found.')
The following statuses may be returned:
- pending – order has just been received but not processed
- waiting – order is waiting for stock to be available
- ready – stock has been allocated and the order is ready to pick
- in_process – is being picked and dispatched
- done – the order is complete
- on_hold – the order has been put on hold by a member of the team
- deferred – certain orders are deferred to be dispatched at a particular time
- cancelled – order has been cancelled and will not dispatched
Note that tracking details are not always available, depending on how the order was shipped.
Products and Stock
It is good practice to regularly check stock available and update your store.
import requests
response = requests.get('https://app.movefresh.com/api/product/',
headers={'Authorization': 'Bearer <<YOUR SECRET>>'},
params={'brand': 'Test Brand'},
)
if response.status_code == 200:
result = response.json()
for product in result['products']:
print('Is active?:', product['is_active'])
print('Name:', product['name'])
print('SKU:', product['sku'])
print('Available Stock:', product['available'])
else:
print('Error:', response.status_code)
Note that available stock can be negative if we hold more orders than stock.
Roadmap
We currently have brands sharing secrets. As soon as possible, each brand will be using their own unique secret. Once this is implemented it will no longer be necessary to pass the brand to create an order or list products and stock.
Our original URL for the API was https://dietchef.warehousebuddy.com but this will no longer be supported in the future so please make sure you migrate your applications to https://app.movefresh.com
Courier Services
Courier | Courier Service | Description |
DPD | 1^12 | Next Day |
DPD | 1^11 | Two Day |
DPD | 1^16 | Saturday |
DPD | 1^19 | DPD Classic (EU) |
DHL Parcel | 1 | Next Day YYY |
DHL Parcel | 2 | Next Day 12:00 YYY |
DHL Parcel | 4 | Saturday YYY |
DHL Parcel | 9 | Next Day 10:30 YYY |
DHL Parcel | 48 | 48 Hour |
DHL Parcel | 72 | 72 Hour |
DHL Parcel | 210 | Next Day YYY/Safe |
DHL Parcel | 211 | Next Day 12:00 YYY/Safe |
DHL Parcel | 212 | Next Day 10:30 YYY/Safe |
DHL Parcel | 215 | Saturday YYY/Safe |
DHL Parcel | 220 | Next Day NYN |
DHL Parcel | 221 | Next Day 12:00 NYN |
DHL Parcel | 222 | Next Day 10:30 NYN |
DHL Parcel | 225 | Saturday NYN |
DHL Parcel International | 204 | International Road |
Hermes | UK24 | 24 Hour |
Hermes | UK24SIG | 24 Hour Signature |
Hermes | UK48 | 48 Hour |
Hermes | UK48SIG | 48 Hour Signature |
Royal Mail | 1_CRL_F | Royal Mail 24 Large Letter |
Royal Mail | 1_CRL_P | Royal Mail 24 Parcel |
Royal Mail | 2_CRL_F | Royal Mail 48 Large Letter |
Royal Mail | 2_CRL_P | Royal Mail 48 Parcel |
Royal Mail | I_IE1_E | Zone Sort Priority Parcel |
Royal Mail | I_IE1_G | Zone Sort Priority Large Letter |
Royal Mail | I_PS9_E | Max Sort Priority Parcel |
Royal Mail | I_PG9_G | Max Sort Priority Large Letter |
Royal Mail | T_TPN_F | Royal Mail Tracked 24 Large Letter |
Royal Mail | T_TPN_P | Royal Mail Tracked 24 Parcel |
Royal Mail | T_TPS_F | Royal Mail Tracked 48 Large Letter |
Royal Mail | T_TPS_P | Royal Mail Tracked 48 Parcel |
Errors
HTTP Status Code | Error | Message |
403 | 10 | Invalid or missing secret. |
400 | 20 | Order <<origin>> has already been imported. |
400 | 30 | No order lines. |
400 | 31 | Invalid SKU: <<sku>> |
400 | 40 | Invalid courier. |
400 | 41 | [Standard|Chilled] courier account does not exist. |
400 | 42 | Courier service <<code>> does not exist. |
400 | 50 | Invalid priority. |
400 | 60 | Invalid customer type. |
400 | 70 | Invalid or missing: <<address line>> |
400 | 80 | Order is <<status>> and cannot be updated. |
404 | 90 | Order not found. |
400 | 99 | Invalid JSON. |
500 | – | An unhandled error has occurred and no error message will be returned. |
503 | – | Service unavailable due to maintenance. Try again later. |
Supported Countries
GB | United Kingdom |
AU | Australia |
AT | Austria |
BE | Belgium |
CA | Canada |
DK | Denmark |
FI | Finland |
FR | France |
DE | Germany |
GG | Guernsey |
HK | Hong Kong |
HU | Hungary |
IS | Iceland |
IE | Ireland |
IM | Isle of Man |
IT | Italy |
JE | Jersey |
LV | Latvia |
LU | Luxembourg |
MC | Monaco |
NL | Netherlands |
NZ | New Zealand |
NO | Norway |
PL | Poland |
PT | Portugal |
SG | Singapore |
ZA | South Africa |
ES | Spain |
SE | Sweden |
AE | United Arab Emirates |
US | United States |
Postal Code Validation
British and Canadian postal codes are converted to uppercase and have an appropriate space added (if missing) before they are validated.
GB | ^([A-Z][A-HJ-Y]?\d[A-Z\d]? ?\d[A-Z]{2}|GIR ?0A{2})$ |
BE | 4-digit |
CA | ^[ABCEGHJ-NPRSTVXY]\d[ABCEGHJ-NPRSTV-Z] \d[ABCEGHJ-NPRSTV-Z]\d$ |
FI | 4-digit |
FR | 5-digit |
DE | 5-digit |
HU | 4-digit |
IT | 5-digit |
LV | 4-digit |
LU | 4-digit |
MC | 98000 |
NZ | 4-digit |
NO | 4-digit |
PT | 4-digit |
SG | 6-digit |
ZA | 4-digit |
ES | 5-digit |
SE | 5-digit |
US | ^\d{5}(?:[-\s]\d{4})?$ |