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

CourierCourier ServiceDescription
DPD1^12Next Day
DPD1^11Two Day
DPD1^16Saturday
DPD1^19DPD Classic (EU)
DHL Parcel1Next Day YYY
DHL Parcel2Next Day 12:00 YYY
DHL Parcel4Saturday YYY
DHL Parcel9Next Day 10:30 YYY
DHL Parcel4848 Hour
DHL Parcel7272 Hour
DHL Parcel210Next Day YYY/Safe
DHL Parcel211Next Day 12:00 YYY/Safe
DHL Parcel212Next Day 10:30 YYY/Safe
DHL Parcel215Saturday YYY/Safe
DHL Parcel220Next Day NYN
DHL Parcel221Next Day 12:00 NYN
DHL Parcel222Next Day 10:30 NYN
DHL Parcel225Saturday NYN
DHL Parcel International204International Road
HermesUK2424 Hour
HermesUK24SIG24 Hour Signature
HermesUK4848 Hour
HermesUK48SIG48 Hour Signature
Royal Mail1_CRL_FRoyal Mail 24 Large Letter
Royal Mail1_CRL_PRoyal Mail 24 Parcel
Royal Mail2_CRL_FRoyal Mail 48 Large Letter
Royal Mail2_CRL_PRoyal Mail 48 Parcel
Royal MailI_IE1_EZone Sort Priority Parcel
Royal MailI_IE1_GZone Sort Priority Large Letter
Royal MailI_PS9_EMax Sort Priority Parcel
Royal MailI_PG9_GMax Sort Priority Large Letter
Royal MailT_TPN_FRoyal Mail Tracked 24 Large Letter
Royal MailT_TPN_PRoyal Mail Tracked 24 Parcel
Royal MailT_TPS_FRoyal Mail Tracked 48 Large Letter
Royal MailT_TPS_PRoyal Mail Tracked 48 Parcel

Errors

HTTP Status CodeErrorMessage
40310Invalid or missing secret.
40020Order <<origin>> has already been imported.
40030No order lines.
40031Invalid SKU: <<sku>>
40040Invalid courier.
40041[Standard|Chilled] courier account does not exist.
40042Courier service <<code>> does not exist.
40050Invalid priority.
40060Invalid customer type.
40070Invalid or missing: <<address line>>
40080Order is <<status>> and cannot be updated.
40490Order not found.
40099Invalid JSON.
500An unhandled error has occurred and no error message will be returned.
503Service unavailable due to maintenance. Try again later.

Supported Countries

GBUnited Kingdom
AUAustralia
ATAustria
BEBelgium
CACanada
DKDenmark
FIFinland
FRFrance
DEGermany
GGGuernsey
HKHong Kong
HUHungary
ISIceland
IEIreland
IMIsle of Man
ITItaly
JEJersey
LVLatvia
LULuxembourg
MCMonaco
NLNetherlands
NZNew Zealand
NONorway
PLPoland
PTPortugal
SGSingapore
ZASouth Africa
ESSpain
SESweden
AEUnited Arab Emirates
USUnited 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})$
BE4-digit
CA^[ABCEGHJ-NPRSTVXY]\d[ABCEGHJ-NPRSTV-Z] \d[ABCEGHJ-NPRSTV-Z]\d$
FI4-digit
FR5-digit
DE5-digit
HU4-digit
IT5-digit
LV4-digit
LU4-digit
MC98000
NZ4-digit
NO4-digit
PT4-digit
SG6-digit
ZA4-digit
ES5-digit
SE5-digit
US^\d{5}(?:[-\s]\d{4})?$
Countries missing from this list do not have their postal codes validated.