Welcome to Royal Mail Rest API’s documentation!¶
Royal Mail Rest API¶
A small helper for integrating python with Royal Mails Rest API
This is to help with getting started integrating Royal Mails shipping and Tracking API’s into your project.
They do have an Open API to build this with Swagger-Codegen, but I found there were a few issues with this. 1. Horrible final code - overly verbose and complicated. 1. Half the time it would not build (needed beta versions of swagger-codegen) and then it would still not work.
This is cleaner, easier to modify and extend, and a lot lighter weight, only using the standard library.
It is VERY MUCH a work in progress, so help is hugely appreciated, and be careful, it may change as I implement more features / improve and enhance what we already have.
- Free software: MIT license
- Documentation: https://royal-mail-rest-api.readthedocs.io.
Features¶
Create Labels Update Labels Create Manifests Post Manifests
Credits¶
This package was created with Cookiecutter and the audreyr/cookiecutter-pypackage project template.
Installation¶
Stable release¶
To install Royal Mail Rest API, run this command in your terminal:
$ pip install royal_mail_rest_api
This is the preferred method to install Royal Mail Rest API, as it will always install the most recent stable release.
If you don’t have pip installed, this Python installation guide can guide you through the process.
From sources¶
The sources for Royal Mail Rest API can be downloaded from the Github repo.
You can either clone the public repository:
$ git clone git://github.com/bobspadger/royal_mail_rest_api
Or download the tarball:
$ curl -OL https://github.com/bobspadger/royal_mail_rest_api/tarball/master
Once you have a copy of the source, you can install it with:
$ python setup.py install
Usage¶
To use Royal Mail Rest API in a project:
Note
(this is from the example.py file which will be updated, its worth looking there)
import json
from royal_mail_rest_api.tools import RoyalMailBody
from royal_mail_rest_api.shipping import ShippingApi
from royal_mail_rest_api.tracking import TrackingApi
from royal_mail_rest_api.get_credentials import return_credentials
if __name__ == '__main__':
# Get our API credentials (from credentials.ini)
creds = return_credentials()
# make some nice easy to read variables for authenticating with
CLIENT_ID = creds['royal_mail']['CLIENT_ID']
CLIENT_SECRET = creds['royal_mail']['CLIENT_SECRET']
USERNAME = creds['royal_mail']['USERNAME']
PASSWORD_HASHED = creds['royal_mail']['PASSWORD_HASHED']
# Create a new delivery object to make our address etc with
body = RoyalMailBody('Delivery')
# Add our items to it
body.add_ship_date(None)
body.add_service('P', 1, 'TPN', 'T', True, ['14'])
body.customer_reference = 'D123456'
body.department_reference = 'Q123456'
body.sender_reference = 'A123456'
body.add_items(1, 100, 'g')
body.add_receipient_contact('Joe Bloggs', 'joe.bloggs@royalmail.com', None, '07970810000')
body.add_receipient_address('Broadgate Circle', 'London', None, 'EC1A 1BB', country='GB', building_number='1',
address_line2='Add line 2', address_line3='Add line 3', building_name='My building')
# Request our body to use to request a label from royal mail
my_rm_body = body.return_domestic_body()
# Create a shipping object, populate it with our credentials
my_shipping = ShippingApi(CLIENT_ID, CLIENT_SECRET, USERNAME, PASSWORD_HASHED)
# Request an authentication token
my_shipping.get_token()
# Post a shipping request
post_shipping = my_shipping.post_domestic(my_rm_body)
# Store our tracking id for use.
tracking_ref = post_shipping['completedShipments'][0]['shipmentItems'][0]['shipmentNumber']
# Get a label ! this is base64 encoded
label = my_shipping.put_shipment_label(tracking_ref)
# Now lets change some info about the receipient
body.add_receipient_contact('Alex Hellier', 'alex@me.com', 'Alex S Hellier', '123455')
# And get our update body - this is slightly different from the original request
new_data = body.return_domestic_update_boy()
# Request a change
change_name = my_shipping.put_shipment(tracking_ref, new_data)
# Request a new label
new_label = my_shipping.put_shipment_label(tracking_ref)
# Lets delete the post request
delete_shipping = my_shipping.delete_shipment(tracking_ref)
# If we have some labels to manifest - request it
manifest_info = {'yourReference': '123'}
manifest_data = my_shipping.post_manifest(manifest_info)
# Get the manifest doumentation - note, you will need the maniefest number to get this
manifest_label = my_shipping.put_manifest(manifest_batch_number=5)
# Now, a period of time has passed, we can track those packages
tracking_api = TrackingApi(CLIENT_ID, CLIENT_SECRET)
try:
test_tracking = tracking_api.summary(tracking_ref)
print(test_tracking)
except Exception as e:
print(e)
try:
test_pod = tracking_api.proof_of_delivery(tracking_ref)
print(test_pod)
except Exception as e:
print(e)
try:
history_tracking = tracking_api.history(tracking_ref)
print(history_tracking)
except Exception as e:
print(e)
Example Shipping object from Royal Mail¶
{
"shipmentType":"Delivery",
"service":{
"format":"P",
"occurrence":"1",
"offering":"TPN",
"type":"T",
"signature":"true",
"enhancements":["14"
]
},
"shippingDate":"2017-09-25",
"items":[
{
"count":1,
"weight":{
"unitOfMeasure":"g",
"value":100
}
}
],
"recipientContact":{
"name":"Joe Bloggs",
"complementaryName":"null",
"email":"joe.bloggs@royalmail.com"
},
"recipientAddress":{
"buildingName":"Cable and Engineering Limited",
"buildingNumber":"1",
"addressLine1":"Broadgate Circle",
"addressLine2":"Address line 2",
"addressLine3":"Address Line 3",
"postTown":"London",
"country":"GB",
"postCode":"EC1A 1BB"
},
"senderReference":"Senders Ref",
"departmentReference":"Dept Ref",
"customerReference":"Do not use",
"safePlace":"null"
}
royal_mail_rest_api¶
royal_mail_rest_api package¶
Submodules¶
royal_mail_rest_api.api module¶
Main module.
royal_mail_rest_api.errors module¶
royal_mail_rest_api.example module¶
royal_mail_rest_api.get_credentials module¶
royal_mail_rest_api.shipping module¶
-
class
royal_mail_rest_api.shipping.
ShippingApi
(client_id, client_secret, username, password)[source]¶ Bases:
royal_mail_rest_api.api.RoyalMailBaseClass
Royal Mail Shipping Class, used to communicate with the Royal Mail Rest API to create labels
-
delete_shipment
(shipment_number)[source]¶ Description
Delete a shipment. Send a shipment identifier in Url. Successful response will be 200 with no content.
Returns:
-
delete_shipment_url
= '/shipping/v2/'¶
-
get_token
()[source]¶ Method to get a JWT token
This method will accept a DMO/NEOPOST user name and password. On successful validation of the user credential it will issue a JWT token to the user which will be valid for 4 hours. On subsequent requests, user will pass the JWT token in the request header.
Returns:
-
post_domestic
(data)[source]¶ Operation to create a shipment
This method will take a domestic shipment request in the body and on successful response, it will return the shipment numbers and item details. :return:
-
post_domestic_url
= '/shipping/v2/domestic'¶
-
post_manifest_url
= '/shipping/v2/manifest'¶
-
put_manifest
(sales_order_number=None, manifest_batch_number=None)[source]¶ This method return a manifest label for a previously manifested shipment.
Returns:
-
put_shipment
(shipment_number, data)[source]¶ updateShipment
Update a shipment. Send a shipment request in body. On successful response, it will return shipment number and warnings. Service related information can not be updated, and if passed as part of request, it will be ignored.
Returns:
-
put_shipment_label
(shipment_number)[source]¶ This method returns a label for the shipment identifier passed in the url.
Returns:
-
put_shipment_label_url
= '/shipping/v2/'¶
-
put_shipment_update_url
= '/shipping/v2/'¶
-
token_url
= '/shipping/v2/token'¶
-
royal_mail_rest_api.tools module¶
-
class
royal_mail_rest_api.tools.
RoyalMailBody
(shipment_type)[source]¶ Bases:
object
-
add_items
(number, weight, unit_of_measure)[source]¶ Add items- currently only a single item :param number: :param weight: :param unit_of_measure: :return:
-
add_receipient_address
(address_line1, post_town, county, postcode, country, building_name=None, building_number=None, address_line2=None, address_line3=None)[source]¶ Add address of receipient :param address_line1: :param post_town: :param county: :param postcode: :param country: :param building_name: :param building_number: :param address_line2: :param address_line3: :return:
-
add_receipient_contact
(name, email, complementary_name=None, telephone=None)[source]¶ Add the name and contact of who this is being sent to :param name: :param email: :param complementary_name: :param telephone: :return:
-
add_service_enhancements
(enhancement)[source]¶ add a single service enhancement, can be called multiple times to append required items :param enhancement: :return:
-
add_service_format
(format=None)[source]¶ add a valid service format using our friendly names :param format: :return:
-
add_service_offering
(service_offering=None)[source]¶ add a valid service offering using our friendly names :param service_offering: :return:
-
add_service_type
(service_type=None)[source]¶ add a valid service type using our friendly names :param service_type: :return:
-
add_ship_date
(date_obj=None)[source]¶ take a datetime object and format it to royal mails Y-m-d format :param date_obj: :return:
-
add_signature
(signature=False)[source]¶ Do we want a signature on delivery :param signature: :return:
-
static
remove_none_values
(iterable)[source]¶ take out values of None by removing the key :param iterable: :return: dictionary
-
service_enhancements
= {'e-mail_notification': '14', 'local_collect': '22', 'loss_1000': '1', 'loss_10000': '5', 'loss_2500': '2', 'loss_5000': '3', 'loss_750': '11', 'loss_7500': '4', 'recorded': '6', 'safeplace': '15', 'saturday_guaranteed': '24', 'signature': '12', 'sms_and_e-mail_notification': '16', 'sms_notification': '13'}¶
-
service_formats
= {'inland_format_not_applicable': 'N', 'inland_large_letter': 'F', 'inland_letter': 'L', 'inland_parcel': 'P', 'international_format_not_applicable': 'N', 'international_large_letter': 'G', 'international_letter': 'P', 'international_parcel': 'E'}¶
-
service_offerings
= {'1st_and_2nd_class_account_mail': 'STL', 'international_signed_on_account': 'OSA', 'international_tracked_and_signed_on_acct': 'OTC', 'international_tracked_on_account': 'OTA', 'intl_bus_mail_l_ltr_ctry_srt_hi_vol_economy_': 'DG3', 'intl_bus_mail_l_ltr_ctry_srt_hi_vol_priority_': 'DG1', 'intl_bus_mail_l_ltr_ctry_srt_lo_vol_economy_': 'DG6', 'intl_bus_mail_l_ltr_ctry_srt_lo_vol_priority_': 'DG4', 'intl_bus_mail_l_ltr_zero_srt_economy_mch': 'WG6', 'intl_bus_mail_l_ltr_zone_srt_economy_mch_': 'IG6', 'intl_bus_mail_lrg_ltr_max_sort_economy': 'PS8', 'intl_bus_mail_lrg_ltr_max_sort_priority': 'PS7', 'intl_bus_mail_lrg_ltr_max_sort_standard': 'PSB', 'intl_bus_mail_lrg_ltr_zero_sort_economy': 'WG3', 'intl_bus_mail_lrg_ltr_zero_srt_pri_mch': 'WG4', 'intl_bus_mail_lrg_ltr_zero_srt_priority': 'WG1', 'intl_bus_mail_lrg_ltr_zone_sort_economy': 'IG3', 'intl_bus_mail_lrg_ltr_zone_sort_pri': 'IG1', 'intl_bus_mail_lrg_ltr_zone_srt_pri_mch': 'IG4', 'intl_bus_mail_mixd_zero_srt_economy_mch': 'WW6', 'intl_bus_mail_mixed_zero_sort_economy': 'WW3', 'intl_bus_mail_mixed_zero_sort_premium': 'ZC1', 'intl_bus_mail_mixed_zero_sort_pri_mch': 'WW4', 'intl_bus_mail_mixed_zero_sort_priority': 'WW1', 'intl_bus_mail_mixed_zone_sort_economy': 'OZ3', 'intl_bus_mail_mixed_zone_sort_pri_mch': 'OZ4', 'intl_bus_mail_mixed_zone_sort_priority': 'OZ1', 'intl_bus_mail_mixed_zone_srt_economy_mch': 'OZ6', 'intl_bus_mail_signed': 'MTM', 'intl_bus_mail_signed_country_priced': 'MTO', 'intl_bus_mail_signed_extra_comp': 'MTN', 'intl_bus_mail_signed_extra_comp_country': 'MTP', 'intl_bus_mail_track_and_sign_xtr_comp_ctry': 'MTH', 'intl_bus_mail_tracked': 'MTI', 'intl_bus_mail_tracked_and_signed': 'MTC', 'intl_bus_mail_tracked_and_signed_country': 'MTG', 'intl_bus_mail_tracked_and_signed_xtr_comp': 'MTD', 'intl_bus_mail_tracked_country_priced': 'MTK', 'intl_bus_mail_tracked_extra_comp': 'MTJ', 'intl_bus_mail_tracked_extra_comp_ctry': 'MTL', 'intl_bus_parcel_track&sign_xtr_cmp_ctry': 'MTF', 'intl_bus_parcels_max_sort_economy': 'PS0', 'intl_bus_parcels_max_sort_priority': 'PS9', 'intl_bus_parcels_max_sort_standard': 'PSC', 'intl_bus_parcels_print_direct_economy': 'MB3', 'intl_bus_parcels_print_direct_priority': 'MB1', 'intl_bus_parcels_print_direct_standard': 'MB2', 'intl_bus_parcels_signed': 'MP5', 'intl_bus_parcels_signed_country_priced': 'MP9', 'intl_bus_parcels_signed_extra_comp': 'MP6', 'intl_bus_parcels_signed_extra_comp_ctry': 'MP0', 'intl_bus_parcels_tracked': 'MP1', 'intl_bus_parcels_tracked_and_signed': 'MTA', 'intl_bus_parcels_tracked_and_signed__ctry': 'MTE', 'intl_bus_parcels_tracked_country_priced': 'MP7', 'intl_bus_parcels_tracked_extra_comp': 'MP4', 'intl_bus_parcels_tracked_extra_comp_ctry': 'MP8', 'intl_bus_parcels_tracked_signed_xtr_comp': 'MTB', 'intl_bus_parcels_zero_sort_economy': 'WE3', 'intl_bus_parcels_zero_sort_hi_vol_economy_': 'DE3', 'intl_bus_parcels_zero_sort_hi_vol_priority_i': 'DE1', 'intl_bus_parcels_zero_sort_priority': 'WE1', 'intl_bus_parcels_zero_srt_lo_vol_economy_': 'DE6', 'intl_bus_parcels_zero_srt_lo_vol_priority_': 'DE4', 'intl_bus_parcels_zone_sort_economy': 'IE3', 'intl_bus_parcels_zone_sort_plus_priority': 'MTQ', 'intl_bus_parcels_zone_sort_priority_': 'IE1', 'intl_bus_parcels_zone_srt_plus_economy': 'MTS', 'intl_economy_on_account': 'OLS', 'intl_signed_on_account_extra_comp': 'OSB', 'intl_standard_on_account': 'OLA', 'intl_tracked_and_signed_on_acct_extra_comp': 'OTD', 'intl_tracked_on_account_extra_comp': 'OTB', 'royal_mail_24_48': 'CRL', 'royal_mail_24_48_p_flat_rate': 'PPF', 'royal_mail_24_ll_daily_rate': 'RM1', 'royal_mail_24_ll_flat_rate': 'PK9', 'royal_mail_24_p_daily_rate': 'RM2', 'royal_mail_24_p_flat_rate': 'RM5', 'royal_mail_24_sort8_ll_daily_rate': 'RM7', 'royal_mail_24_sort8_ll_flat_rate': 'FS1', 'royal_mail_24_sort8_llp_daily_rate': 'PK3', 'royal_mail_24_sort8_p_daily_rate': 'RM8', 'royal_mail_24_sort8_p_flat_rate': 'PK1', 'royal_mail_48_ll_daily_rate': 'RM3', 'royal_mail_48_ll_flat_rate': 'PK0', 'royal_mail_48_p_daily_rate': 'RM4', 'royal_mail_48_p_flat_rate': 'RM6', 'royal_mail_48_sort8_ll_daily_rate': 'RM9', 'royal_mail_48_sort8_ll_flat_rate': 'FS2', 'royal_mail_48_sort8_llp_daily_rate': 'PK4', 'royal_mail_48_sort8_p_daily_rate': 'RM0', 'royal_mail_48_sort8_p_flat_rate': 'PK2', 'royal_mail_tracked_24': 'TPN', 'royal_mail_tracked_24_hv': 'TPM', 'royal_mail_tracked_24_lbt': 'TRN', 'royal_mail_tracked_24_lbt_hv': 'TRM', 'royal_mail_tracked_48': 'TPS', 'royal_mail_tracked_48_hv': 'TPL', 'royal_mail_tracked_48_lbt': 'TRS', 'royal_mail_tracked_48_lbt_hv': 'TRL', 'royal_mail_tracked_returns_24': 'TSN', 'royal_mail_tracked_returns_48': 'TSS', 'sd_guaranteed_by_1pm': 'SD1', 'sd_guaranteed_by_1pm_1000': 'SD2', 'sd_guaranteed_by_1pm_2500': 'SD3', 'sd_guaranteed_by_9am': 'SD4', 'sd_guaranteed_by_9am_1000': 'SD5', 'sd_guaranteed_by_9am_2500': 'SD6'}¶
-
service_types
= {'BFPO': 'H', 'Royal Mail 48': '2', 'international': 'I', 'royal_mail_24': '1', 'royal_mail_tracked': 'T', 'special_delivery': 'D', 'tracked_returns': 'R'}¶
-
-
class
royal_mail_rest_api.tools.
valid_service
(serviceType, serviceOffering, serviceFormat, enhancementType, signatureTracked, safePlace)¶ Bases:
tuple
-
enhancementType
¶ Alias for field number 3
-
safePlace
¶ Alias for field number 5
-
serviceFormat
¶ Alias for field number 2
-
serviceOffering
¶ Alias for field number 1
-
serviceType
¶ Alias for field number 0
-
signatureTracked
¶ Alias for field number 4
-
royal_mail_rest_api.tracking module¶
-
class
royal_mail_rest_api.tracking.
TrackingApi
(client_id, client_secret)[source]¶ Bases:
royal_mail_rest_api.api.RoyalMailBaseClass
Start class for royal mail shipping api
-
history
(tracking_number)[source]¶ Return history for a tracked item :param tracking_number: :return:
-
history_url
= 'mailPieces/{}/history'¶
-
pod_url
= 'mailPieces/{}/proofOfDelivery'¶
-
proof_of_delivery
(tracking_number)[source]¶ recover proof of delivery :param tracking_number: :return:
-
summary
(tracking_number)[source]¶ takes 13 digit tracking number and requests summary data :param tracking_number: :return: tracking_summary
-
summary_url
= 'mailPieces/{}/summary'¶
-
Module contents¶
Top-level package for Royal Mail Rest API.
Contributing¶
Contributions are welcome, and they are greatly appreciated! Every little bit helps, and credit will always be given.
You can contribute in many ways:
Types of Contributions¶
Report Bugs¶
Report bugs at https://github.com/bobspadger/royal_mail_rest_api/issues.
If you are reporting a bug, please include:
- Your operating system name and version.
- Any details about your local setup that might be helpful in troubleshooting.
- Detailed steps to reproduce the bug.
Fix Bugs¶
Look through the GitHub issues for bugs. Anything tagged with “bug” and “help wanted” is open to whoever wants to implement it.
Implement Features¶
Look through the GitHub issues for features. Anything tagged with “enhancement” and “help wanted” is open to whoever wants to implement it.
Write Documentation¶
Royal Mail Rest API could always use more documentation, whether as part of the official Royal Mail Rest API docs, in docstrings, or even on the web in blog posts, articles, and such.
Submit Feedback¶
The best way to send feedback is to file an issue at https://github.com/bobspadger/royal_mail_rest_api/issues.
If you are proposing a feature:
- Explain in detail how it would work.
- Keep the scope as narrow as possible, to make it easier to implement.
- Remember that this is a volunteer-driven project, and that contributions are welcome :)
Get Started!¶
Ready to contribute? Here’s how to set up royal_mail_rest_api for local development.
Fork the royal_mail_rest_api repo on GitHub.
Clone your fork locally:
$ git clone git@github.com:your_name_here/royal_mail_rest_api.git
Install your local copy into a virtualenv. Assuming you have virtualenvwrapper installed, this is how you set up your fork for local development:
$ mkvirtualenv royal_mail_rest_api $ cd royal_mail_rest_api/ $ python setup.py develop
Create a branch for local development:
$ git checkout -b name-of-your-bugfix-or-feature
Now you can make your changes locally.
When you’re done making changes, check that your changes pass flake8 and the tests, including testing other Python versions with tox:
$ flake8 royal_mail_rest_api tests $ python setup.py test or py.test $ tox
To get flake8 and tox, just pip install them into your virtualenv.
Commit your changes and push your branch to GitHub:
$ git add . $ git commit -m "Your detailed description of your changes." $ git push origin name-of-your-bugfix-or-feature
Submit a pull request through the GitHub website.
Pull Request Guidelines¶
Before you submit a pull request, check that it meets these guidelines:
- The pull request should include tests.
- If the pull request adds functionality, the docs should be updated. Put your new functionality into a function with a docstring, and add the feature to the list in README.rst.
- The pull request should work for Python 2.7, 3.4, 3.5 and 3.6, and for PyPy. Check https://travis-ci.org/bobspadger/royal_mail_rest_api/pull_requests and make sure that the tests pass for all supported Python versions.
Deploying¶
A reminder for the maintainers on how to deploy. Make sure all your changes are committed (including an entry in HISTORY.rst). Then run:
$ bumpversion patch # possible: major / minor / patch
$ git push
$ git push --tags
Travis will then deploy to PyPI if tests pass.
Credits¶
Development Lead¶
- Alex Hellier <alex.hellier@gmail.com>
Contributors¶
None yet. Why not be the first?
History¶
0.0.6 (2018-04-06)¶
Raise useful errors from the api calls so they are returned to the calling app
0.0.5¶
Tests Service helpers
0.0.4¶
0.0.3 (2018-04-03)¶
Store token for 4 hours (issue #7) Fix some poor documentation Fix some examples
0.0.2 (2018-04-03)¶
Fixing PyPI install not working
0.0.1 (2018-03-26)¶
- First release on PyPI.